Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

While trying to set up my new fish shell prompt, I ended up testing ways to get the branch name and also testing if I was on a git repository. I have found (1) git rev-parse --abbrev-ref HEAD, (2) git symbolic-ref HEAD | sed 's/refs\/heads\///' and (3) git describe --contains --all HEAD do the trick just fine.

I’m curious because I love the simplicity of (1), but on a new and untouched (just git inited) repository, it gives me a “fatal:” error, while (2) works as intended, that is, giving me a default master as output. The thing is, even with a “fatal:” error, the return code is 0. Is that the intended behavior?

To test if I was in a git repository, I ended up simply testing if the current directory had a “.git” folder: test -d ".git". Rudimentary solution, but it works, and it seems to be faster that using any git command.

So, my questions are:

  1. Shouldn’t that “fatal:” with (1) return an exit code different from 0? If indeed it is a bug, since I don’t know how git people standardised their return codes, where should I report it?
  2. I know if I redirect (1) with ^ /dev/null (for those who don’t know, ^ is the same as 2>), I won’t get the error, but it will say HEAD instead of master, but if I cat .git/HEAD, I get: ref: refs/heads/master. What should it really say? With master am I just being ignorant and picky, because it should instead say HEAD? I mean in the case of a just git inited repository.
  3. Have you actually benchmarked any possible solutions during your quest to get a nice prompt?

This is the code I use to benchmark (for fish):

set -l before (date +%s%N)
git rev-parse --abbrev-ref HEAD
set -l after (date +%s%N)
set -l elapsed_time (expr $after - $before)
echo $elapsed_time

Thanks in advance!

PS: The tools are the latest GNU versions, I mean, sed, date and expr. I’m sorry if there is too much information or if something doesn’t make any sense. Bear with me. Thanks!

EDIT: As someone correctly guessed in an answer, the whole error is:

fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions
share|improve this question
    
Please post the fatal: error. Tough to know how it should be treated without being able to read it. :-) – Christopher Sep 12 '12 at 12:56
    
I just did it. :) – Andrés Botero Sep 12 '12 at 19:46
up vote 2 down vote accepted

Doesn't fully answer your questions but probably a bit more than just a comment:

  1. Based on other comments in your answer, I think the error you saw is fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. That occurs because you're conducting these tests on a brand new git repository, one that has no committed work. Not only is this not really a fair test (your performance will by definition be worse on a larger repository), it is in nearly every way an edge case. For example, .git/HEAD shows ref: refs/heads/master by convention. The error is thrown because HEAD is ambiguous. You have no history, thus any value passed to rev-parse would be treated the same. Additionally, this doesn't exit 0 for me:

    $ git init /tmp/test && cd /tmp/test
    $ git rev-parse --abbrev-ref HEAD
    $ echo $?
    128
    

    In sum, don't sweat this error. Grab yourself one of the huge android repos, or perhaps the linux kernel, and test your prompt there.

  2. HEAD is not a branch. It's a pointer to the checked-out state. When you've got a branch checked out, it's a symbolic reference to that branch. When you're in 'detached HEAD' state, the HEAD pointer is pointing at a commit. You get HEAD as the return using method (1) because rev-parse is just echoing the passed refspec value in the error. Try it with blah; you'll see the same thing.

  3. I haven't actually benchmarked solutions, but a few things you might try (both are used in my zsh prompt, which I didn't write, and both have performed quite well):

    git rev-parse --is-inside-work-tree ;# avoids your 'test -d .git' call
    ref=$(git symbolic-ref HEAD 2> /dev/null) ;# grab the full refspec
    branch=$(echo ${ref#refs/heads/}) ;# extract the branch name
    
share|improve this answer
    
I’m not at home right now, but I’m going to try in my Android ROM source when I get back. Indeed what best place to try it out... Thanks! – Andrés Botero Sep 12 '12 at 19:47
    
--is-inside-work-tree is a much better option (but not as fast, though) than testing .git directory, since .git is only in the root. For the branch, “git help symbolic-ref” gave me the answer: git symbolic-ref --short HEAD 2>/dev/null. Much cooler, a single command, perfect. No idea how I didn’t see it before. Thanks! – Andrés Botero Sep 24 '12 at 6:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .