views:

458

answers:

5

In a Unix or GNU scripting environment (e.g. a Linux distro, Cygwin, OSX), what is the best way to determine which Git branch is currently checked out in a working directory?

One use of this technique would be automatically labeling a release (like svnversion would do with Subversion).

Please also see my related question: How to programmatically determine whether a Git checkout is a tag, and if so what is the tag name?

A: 

Here is what I do:

git branch | sed --quiet 's/* \(.*\)/\1/p'

The output would look like this:

$ git branch | sed --quiet 's/* \(.*\)/\1/p'
master
$
jhs
git-branch is *porcelain* (user interface) command, and its output should not be used in scripts
Jakub Narębski
A: 

That's one solution. If you add it to your .bashrc, it'll display the current branch in the console.

# git branch
parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /'
}
$PS1="\$(parse_git_branch)$PS1"

However it's pretty limited. But there is a great project called git sh, which is doing exactly that (and much more).

Damien MATHIEU
Woah, that's crazy. That is exactly the code I had in my .bashrc. I shortened it to use GNU sed options and I kept thinking, this doesn't look like my code. I'm curious, was the code you posted from some sort of public example?
jhs
Also +1 because, while I haven't tested, I'm pretty sure your answer is non-GNU compatible so it might be preferred on Darwin, Solaris, etc.
jhs
This code is from GitHub : http://github.com/guides/put-your-git-branch-name-in-your-shell-promptI've used only with Darwin and Ubuntu. It works well on both of them.
Damien MATHIEU
git-branch is *porcelain* (user interface) command, and its output should not be used in scripts
Jakub Narębski
+5  A: 

A robust way to do this is to use git name-rev:

$ git name-rev --name-only HEAD
master

This is generally considered more reliable because it is a "plumbing" command and is designed to be parsed by a program (in fact, the only output is exactly what you want). The output of git branch is more variable and could change in the future.

A good way to describe a release is to use the git describe command. This refers the current commit to the nearest tag, providing a stable indicator of which branch was built. If you label your build as coming from the "integ_2" branch, you still won't know what was actually included in the build.

Greg Hewgill
+1 I originally posted just to share my own code snippet, but yours is superior. I can't edit answers. Would you mind adding that you can also run `git name-rev --name-only HEAD` to get the branch name only? Thanks!
jhs
Good addition, thanks for that.
Greg Hewgill
This can give more than one result when there is more than one branch pointing to current commit, or if current commit is tagged. Use git-symbolic-ref.
Jakub Narębski
Jakub, thank you for pointing that out. However, with my related question, I do not appreciate you down-voting **and** commenting critically on every answer except your own. I prefer Greg's solution due to its brevity. Not every situation warrants copying source from the Git project :)
jhs
Also this solution wouldn't work if we are on detached HEAD (i.e. HEAD points directly to a commit); we would get 'undefined' as a result. We are not on branch named 'undefined' but on unnamed, anonymous branch.
Jakub Narębski
***Correction:*** `git name-rev --name-only HEAD` would chose one of references, if there are more than one reference (branch) pointing to current commit. So for example if you are on branch 'tmp', and branch 'master' points to the same commit (perhaps because we just created 'tmp' branch), the above solution would **incorrectly** return 'master' even though 'tmp' is currently checked out branch, and new commits would go on 'tmp'.
Jakub Narębski
A: 

This one works for me. The --no-color part is, or can be, important if you want a plain string back.

git branch --no-color | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
August Lilleaas
git-branch is *porcelain* (user interface) command, and its output should not be used in scripts. Although you get bonus points for '--no-color'.
Jakub Narębski
+8  A: 

The correct solution is to take a peek at contrib/completions/git-completion.bash does that for bash prompt in __git_ps1. Removing all extras like selecting how to describe detached HEAD situation, i.e. when we are on unnamed branch, it is:

branch_name="$(git symbolic-ref HEAD 2>/dev/null)" ||
branch_name="(unnamed branch)"     # detached HEAD

branch_name=${branch_name##refs/heads/}

git symbolic-ref is used to extract fully qualified branch name from symbolic reference; we use it for HEAD, which is currently checked out branch.

Alternate solution could be:

branch_name=$(git symbolic-ref -q HEAD)
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD}

where in last line we deal with the detached HEAD situation, using simply "HEAD" to denote such situation.

Jakub Narębski
+ for $(git symbolic-ref -q HEAD), I'm using this for an automation script# head_sha1=$(cat .git/$(git symbolic-ref HEAD)); # echo $head_sha19ed68f221e158ce90f8a36832d981befa6e75179works great, many thanks
Fire Crow
Do not use `cat .git/refs/heads/branch`; use `git rev-parse --verify refs/heads/branch`. Refs can be **packed**, and the solution with `cat` would fail.
Jakub Narębski
A challenge for all bash string artists out there: *surely* there must be a nice way of doing this in less than three variable assignments? :-D
conny