c++gitgit-checkoutlibgit2

Checkout local commit with libgit2


I'm trying to implement a simple checkout operation between 2 commit. The code executes without errors.

int checkout2() {
git_repository_free(repo);

git_repository_open(&this->repo, this->dir);

git_commit* commit = NULL;

git_tree* tree;
check_lg2(git_commit_tree(&tree, commit), "Get tree", NULL);

const char* target_ref = "commit hash";

git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;

/*checkout from HEAD*/
int error = git_checkout_head(repo, &opts);

/*Checkout from the index*/
error = git_checkout_index(repo, NULL, &opts);

/*Checkout a different tree*/
git_object* treeish = NULL;

error = git_revparse_single(&treeish, repo, target_ref);
error = git_checkout_tree(repo, treeish, &opts);

return 0;

}

However, the commit does not change. I've checked the example in libgit2 (checkout.cpp) but there is a git_remote_list().

I want to checkout only between local commit.

What am I doing wrong?

I want to do something like git checkout hash_commit


Solution

  • int checkout() {
    git_repository_free(repo);
    
    git_repository_open(&this->repo, this->dir);
    
    git_commit* commit = NULL;
    
    git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
    git_reference* ref = NULL, * branch = NULL;
    git_commit* target_commit = NULL;
    int err;
    
    const char* target_ref;
    
    target_ref = "commit hash";
    
    /** Setup our checkout options from the parsed options */
    checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
    checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
    
    git_annotated_commit* target;
    
    resolve_refish(&target, repo, target_ref);
    
    /** Grab the commit we're interested to move to */
    err = git_commit_lookup(&target_commit, repo, git_annotated_commit_id(target));
    if (err != 0) {
        fprintf(stderr, "failed to lookup commit: %s\n", git_error_last()->message);
        return 0;
    }
    
    /**
     * Perform the checkout so the workdir corresponds to what target_commit
     * contains.
     *
     * Note that it's okay to pass a git_commit here, because it will be
     * peeled to a tree.
     */
    err = git_checkout_tree(repo, (const git_object*)target_commit, &checkout_opts);
    if (err != 0) {
        fprintf(stderr, "failed to checkout tree: %s\n", git_error_last()->message);
        return 0;
    }
    
    /**
     * Now that the checkout has completed, we have to update HEAD.
     *
     * Depending on the "origin" of target (ie. it's an OID or a branch name),
     * we might need to detach HEAD.
     */
    if (git_annotated_commit_ref(target)) {
        const char* target_head;
    
        if ((err = git_reference_lookup(&ref, repo, git_annotated_commit_ref(target))) < 0) {
        
            return 0;
        }
    
        if (git_reference_is_remote(ref)) {
            if ((err = git_branch_create_from_annotated(&branch, repo, target_ref, target, 0)) < 0) {
    
                return 0;
            }
            target_head = git_reference_name(branch);
        }
        else {
            target_head = git_annotated_commit_ref(target);
        }
    
        err = git_repository_set_head(repo, target_head);
    }
    else {
        err = git_repository_set_head_detached_from_annotated(repo, target);
    }
    
    return 0;
    

    }