10

I am trying to use libgit2 to read the name of the current branch. Do I have to do some sort of resolve?

I tried using

git_branch_lookup

to look up the git_reference for HEAD, but it results in

Unable to find local branch 'HEAD'

Thanks!

Jake
  • 15,007
  • 22
  • 70
  • 86

3 Answers3

11

Running git branch -a doesn't list HEAD. In libgit2, HEAD isn't considered a valid branch either. It's only a reference.

If you want to discover which reference is the current branch, then you should

  • Load the current HEAD reference (try the git_repository_head() convenience method)
  • Determine its type (using git_reference_type())
  • Depending on its type (GIT_REFERENCE_SYMBOLIC or GIT_REFERENCE_DIRECT) retrieve one of the following
    • The name of the branch (using git_reference_symbolic_target())
    • The commit being pointed at (using git_reference_target())
MakotoE
  • 1,814
  • 1
  • 20
  • 39
nulltoken
  • 64,429
  • 20
  • 138
  • 130
  • @Jake Was this answer helpful? – nulltoken Aug 28 '12 at 22:19
  • note that sometime after 0.0.17 libgit2 renamed a lot of methods, including the `git_reference_*` methods: http://librelist.com/browser//libgit2/2012/11/28/re-the-great-api-renaming-of-2012/ – Nelson Apr 07 '13 at 23:29
  • @Nelson Thanks. This has been fixed. Cheers ;-) – nulltoken Apr 08 '13 at 07:40
  • You don't have to check the reference type anymore, as `git_reference_resolve()` will "resolve" direct references and actually resolve symbolic references – T0xicCode Apr 08 '13 at 22:08
  • 2
    @xav0989 Beware that those function serves different purposes: `git_reference_resolve` will peel the reference until a direct reference is found then return its oid. `git_reference_resolve` will accept either a direct or a symbolic reference. `git_reference_target` will only accept a direct reference. `git_reference_symbolic_target` will only accept a symbolic reference as input and return the name of the reference being pointed at (which could be a direct or another chained symbolic reference). – nulltoken Apr 09 '13 at 05:48
  • @nulltoken Yes. I assumed that the oid of the commit eventually associated with this reference was the end goal, but if the next target is the end goal, the `git_reference-*target` functions are better suited. – T0xicCode Apr 09 '13 at 15:16
  • The old constant names have been updated since [v0.28.2](https://libgit2.org/libgit2/#HEAD/group/reference/git_reference_type). I went ahead and changed the constant names in this answer to the new ones. – MakotoE Apr 24 '23 at 23:46
0

I did not find the existing answer/comments helpful, when having this exact problem. Instead I combined git_reference_lookup() and git_reference_symbolic_target().

git_reference* head_ref;
git_reference_lookup(&head_ref, repo, "HEAD");
const char *symbolic_ref;
symbolic_ref = git_reference_symbolic_target(head_ref);
std::string result;
// Skip leading "refs/heads/" -- 11 chars.
if (symbolic_ref) result = &symbolic_ref[11];
git_reference_free(head_ref);

This feels like something of a dirty hack, but it's the best I've managed. The result string either ends up empty (e.g. detached head, there is no checked out branch) or contains the name of the checked out branch. The symbolic target is owned by the ref, so copy that value into the string before freeing it!

arantius
  • 1,715
  • 1
  • 17
  • 28
  • In retrospect, this is almost exactly what the existing answer said, just that it also contains some (out of date?) red herrings which confused me at first. – arantius Jan 21 '21 at 20:01
0

There is an example for this at https://libgit2.org/libgit2/ex/HEAD/status.html . It is based around the method get_reference_shorthand. This should give the branch name instead of the reference, so no string manipulation needed, and it should also work in the edge case where branch and remote have different names.

static void show_branch(git_repository *repo, int format)
{
  int error = 0;
  const char *branch = NULL;
  git_reference *head = NULL;

  error = git_repository_head(&head, repo);

  if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND)
    branch = NULL;
  else if (!error) {
    branch = git_reference_shorthand(head);
  } else
    check_lg2(error, "failed to get current branch", NULL);

  if (format == FORMAT_LONG)
    printf("# On branch %s\n",
      branch ? branch : "Not currently on any branch.");
  else
    printf("## %s\n", branch ? branch : "HEAD (no branch)");

  git_reference_free(head);
}
Kjell
  • 492
  • 1
  • 7
  • 15