Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checkout branch with libgit2

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

git_libgit2_init();
git_object *treeish = NULL;
git_checkout_options opts;
opts.checkout_strategy = GIT_CHECKOUT_SAFE;

/* branchName in this case is "master" */
handleError(git_revparse_single(&treeish, repo, branchName));
handleError(git_checkout_tree(repo, treeish, &opts));

git_object_free(treeish);
git_libgit2_shutdown();

However, the branch does not change when I check it using git status. I've checked the 101 examples of libgit2 and it says:

git_checkout_options isn’t actually very optional. The defaults won’t be useful outside of a small number of cases. The best example of this is checkout_strategy; the default value does nothing to the work tree. So if you want your checkout to check files out, choose an appropriate strategy.

NONE is the equivalent of a dry run; no files will be checked out.

SAFE is similar to git checkout; unmodified files are updated, and modified files are left alone. If a file was present in the old HEAD but is missing, it’s considered deleted, and won’t be created.

RECREATE_MISSING is similar to git checkout-index, or what happens after a clone. Unmodified files are updated, and missing files are created, but files with modifications are left alone.

FORCE is similar to git checkout --force; all modifications are overwritten, and all missing files are created.

In my case I'm testing it with a very small repo without uncommited changes and without any conflicts between these 2 branches.

git log

What am I doing wrong? I expected this code to do something like git checkout master

like image 471
Abdelilah El Aissaoui Avatar asked Oct 15 '17 17:10

Abdelilah El Aissaoui


1 Answers

The git checkout command is exceptionally overloaded. It deals with both putting files on disk (checking out) and switching branches. In particular, git checkout <branch> will update the working directory to match the contents of the given branch and switch to it.

The libgit2 APIs do not conflate these two operations. git_checkout_* functions will only check files out on disk.

The documentation should clarify this:

In libgit2, checkout is used to update the working directory and index to match a target tree. Unlike git checkout, it does not move the HEAD commit for you - use git_repository_set_head or the like to do that.

So what you have written (above) will update the working directory to match the contents of the branch. After that, you will need to update your branch to the branch you want to switch to.

You can do this with git_repository_set_head to update HEAD to point to the given branch, once the files have been checked out. Be sure to specify the fully-qualified branch name (eg, refs/heads/master).

git_object *treeish = NULL;
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_SAFE;

git_libgit2_init();

handleError(git_revparse_single(&treeish, repo, "master"));
handleError(git_checkout_tree(repo, treeish, &opts));

handleError(git_repository_set_head(g_repo, "refs/heads/master"));

git_object_free(treeish);
git_libgit2_shutdown();
like image 122
Edward Thomson Avatar answered Sep 30 '22 08:09

Edward Thomson