How to programmatically determine the current checked out Git branch [duplicate]
Asked Answered
R

20

331

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?

Roseannaroseanne answered 20/10, 2009 at 7:52 Comment(4)
Duplicate? https://mcmap.net/q/12588/-show-just-the-current-branch-in-git/1143126Rammish
With Git 2.22 (Q2 2019), you will have a simpler approach: git branch --show-current. See my answer here.Severe
Adding --no-color will give a even more script-friendly result git branch --no-color --show-currentGraphics
The question could be better put. However it differs in the "programmatically". I.e., how to capture the branch name in a shell script or other code. Happy to edit appropriately.Fuzzy
P
349

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.


Added 11-06-2013

Junio C. Hamano (git maintainer) blog post, Checking the current branch programatically, from June 10, 2013 explains whys (and hows) in more detail.

Parthenos answered 20/10, 2009 at 9:34 Comment(17)
+ for $(git symbolic-ref -q HEAD), I'm using this for an automation script # head_sha1=$(cat .git/$(git symbolic-ref HEAD)); # echo $head_sha1 9ed68f221e158ce90f8a36832d981befa6e75179 works great, many thanksPiggish
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.Sural
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? :-DDivergence
@conny: Not really, since :- and friends seem to require real variables.Cultism
... unless of course you resort to sed and friends. But for the common case where this is used (bash prompts), you'd probably want to avoid calling binaries for performance reasons.Cultism
@Divergence git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3 should get you branch name in one goPolystyrene
what does the ## do in branch_name=${branch_name##refs/heads/}?Emersen
@Thr4wn it removes (trim) the beginning of the string, removing here 'refs/heads/' from $branch_name string value. See thegeekstuff.com/2010/07/bash-string-manipulation or tldp.org/LDP/abs/html/string-manipulation.htmlSevere
branch=$(basename $(git symbolic-ref -q HEAD || echo HEAD))Unbroken
@dpk: First, basename won't work for hierarchical branch names (eg. subsystem/feature or programmer_initials/feature); you need to strip refs/heads/ exactly. Second, it is one extra call to external command that you don't need, especially in latency-sensitive place as prompt.Sural
@Polystyrene you don't need to pipe the output of git symbolic-ref to get rid of the refs/head/ part. Git has a command line flag for that: git symbolic-ref -q --short HEAD would do the job. I have edited the answer to reflect this suggestion.Load
@HaralanDobrev: IIRC git symbolic-ref didn't have --short option when this answer was written. Thanks for an info.Sural
@Polystyrene Add a - to the end of that command, otherwise branches with "/" in the name will fail. git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3- is what you want. :)Snowwhite
Since Git 1.7.10 you can specify --short option to git-symbolic-ref, which removes refs/heads in the output for you.Shayshaya
branch_name = ${${$(git symbolic-ref -q HEAD)##refs/heads/}:-HEAD} to nest them all in one statement.Riffe
@Divergence LOL at 'bash string artists'Macnair
If anyone uses a branch in format "some/environment" you can use git symbolic-ref -q HEAD | sed "s/refs\/heads*\///"Mastaba
S
247

Does anyone see anything wrong with just asking Git to describe the branch you are on?

git rev-parse --symbolic-full-name --abbrev-ref HEAD

That can be used within $() and passed easily in Bash, Powershell, Perl, etc. It isn't fooled if you have several branches on the commit you are on, and if you currently aren't on a branch, it simply replies with "HEAD".

Alternatively, you can use

git symbolic-ref --short -q HEAD

Which will give you the same output, but it won't return anything at all if you are detached. This one is useful if you want an error when detached though, just remove the -q.

Superabound answered 14/8, 2012 at 18:27 Comment(4)
Sorry, I guess the --short option for synbolic-ref only available in in Git 1.7.10 (MSYS). The second option doesn't work as well for 1.7.9 (CygWin).Superabound
How would you then take the command git rev-parse --symbolic-full-name --abbrev-ref HEAD and put it into a PS1 variable for bash or a prompt for csh?Railroader
For PowerShell, I just use: function Git-GetCurrentBranch() { return (&$git rev-parse --symbolic-full-name --abbrev-ref HEAD) } Where $git is the path to my Git.exeSuperabound
Why do you need --symbolic-full-name?Trubow
K
55

you can use git name-rev --name-only HEAD

Koontz answered 27/2, 2013 at 12:8 Comment(2)
If HEAD is tagged, this will output the tag, not the branch nameInsurgence
Also, if several branches point to the same commit, this might return the wrong branch.Suppositious
C
41

From this answer: https://mcmap.net/q/12588/-show-just-the-current-branch-in-git :

$ git rev-parse --abbrev-ref HEAD
master

Apparently works with Git 1.6.3 or newer.

Contrabass answered 22/10, 2012 at 1:15 Comment(3)
it doesn't work if you are in detached head state.Vizier
@Vizier - it simply prints 'HEAD' in detached head state on my system: gist.github.com/johnnyutahh/2f4db5c755bc032b106b. Are you running Git >= 1.6.3 ?Contrabass
I like this answer because it works with older versions of git than the accepted answer. Thank you.Bannockburn
M
28

Try with:

 git symbolic-ref --short -q HEAD

Or you try with git branch with --no-color force simple plain string the output:

 git branch  --no-color

With grep in regex mode(-E) you can check if exists the character '*':

 git branch  --no-color  | grep -E '^\*' 

The results its similar to:

* currentBranch

You can use the next options:

sed 's/\*[^a-z]*//g'
cut -d ' ' -f 2
awk '{print $2}'

for example:

 git branch  --no-color  | grep -E '^\*' | sed 's/\*[^a-z]*//g'
 git branch  --no-color  | grep -E '^\*' | sed cut -d ' ' -f 2
 git branch  --no-color  | grep -E '^\*' | awk '{print $2}'

if exists a error you cant use an default value:

  cmd || echo 'defualt value';

All into in a bash function:

function get_branch() {
      git branch --no-color | grep -E '^\*' | awk '{print $2}' \
        || echo "default_value"
      # or
      # git symbolic-ref --short -q HEAD || echo "default_value";
}

Use:

branch_name=`get_branch`;
echo $branch_name;
Mcqueen answered 13/6, 2014 at 17:31 Comment(0)
F
10

adapting the accepted answer to windows powershell:

Split-Path -Leaf (git symbolic-ref HEAD)
Felicio answered 12/5, 2012 at 8:47 Comment(0)
T
10

This one worked for me in the bash file.

git branch | grep '^*' | sed 's/* //'  


################bash file###################
#!/bin/bash
BRANCH=$(git branch | grep '^*' | sed 's/* //' )
echo $BRANCH
Teachin answered 9/2, 2016 at 17:34 Comment(2)
^* should be quoted to avoid being expanded, i.e. git branch | grep '^*' | sed 's/* //'Viand
@MingjiangShi thanks for the suggestion. I have updated the answerTeachin
R
7

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
$
Roseannaroseanne answered 20/10, 2009 at 7:53 Comment(3)
git-branch is porcelain (user interface) command, and its output should not be used in scriptsSural
Does not work on my MacOS 10.6.8 system.Contrabass
Very bad idea to use git-branch. But if you like sed you can do it simpler :) git branch | sed -n "/\*/ s/.* // p"Phallic
L
6

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/'
Loquitur answered 20/10, 2009 at 8:48 Comment(3)
git-branch is porcelain (user interface) command, and its output should not be used in scripts. Although you get bonus points for '--no-color'.Sural
No color is produced when output is connected to a pipe, try: git branch | cat.Allegorize
@Allegorize depending on your value for git config color.branch...Hinman
G
5

I found two really simple ways to do that:

$ git status | head -1 | cut -d ' ' -f 4

and

$ git branch | grep "*" | cut -d ' ' -f 2
Gurkha answered 16/10, 2012 at 7:59 Comment(1)
I'm not sure about first one (e.g. doesn't seem to work on Git 2.11.1 / MacOS) but the second command works.Firenze
R
5

Using --porcelain gives a backwards-compatible output easy to parse:

git status --branch --porcelain | grep '##' | cut -c 4-

From the documentation:

The porcelain format is similar to the short format, but is guaranteed not to change in a backwards-incompatible way between Git versions or based on user configuration. This makes it ideal for parsing by scripts.

https://git-scm.com/docs/git-status

Repentant answered 20/11, 2015 at 11:46 Comment(1)
If current branch has an upstream branch set, it includes the upstream and remote branch name as well, example: master...origin/masterMince
H
4

I'm trying for the simplest and most self-explanatory method here:

git status | grep "On branch" | cut -c 11-
Hayrick answered 10/8, 2016 at 10:16 Comment(1)
git status : it refresh the index so this solution can lead to bad performanceFlowering
T
4

Same results as accepted answer in a one-line variable assignment:

branch_name=$((git symbolic-ref HEAD 2>/dev/null || echo "(unnamed branch)")|cut -d/ -f3-)
Tillett answered 31/5, 2018 at 16:9 Comment(3)
Keep it simple: branch_name=`git rev-parse --abbrev-ref HEAD`Upswell
Doesn't work if repo has no commitsUnshakable
add an space between ((: $( (git symbolic-ref HEAD 2>/dev/null || echo "(unnamed branch)")|cut -d/ -f3-)Amygdala
S
2

Someone mentioned doing it in bash with less than three assignments... how about some messy control flow like this:

branch_name="$(b=$(git symbolic-ref -q HEAD); { [ -n "$b" ] && echo ${b##refs/heads/}; } || echo HEAD)"
Sweeping answered 25/10, 2011 at 2:22 Comment(0)
R
2

If you're using the old NT command line, you can use the following:

@for /f "usebackq" %i in (`git symbolic-ref -q HEAD`) do @echo %~ni

To use in a batch file, you'll have to double the %'s:

@for /f "usebackq" %%i in (`git symbolic-ref -q HEAD`) do @echo %%~ni
Ridenour answered 24/5, 2012 at 20:38 Comment(0)
P
2

Here's my solution, suitable for use in a PS1, or for automatically labeling a release

If you are checked out at a branch, you get the branch name.

If you are in a just init'd git project, you just get '@'

If you are headless, you get a nice human name relative to some branch or tag, with an '@' preceding the name.

If you are headless and not an ancestor of some branch or tag you just get the short SHA1.

function we_are_in_git_work_tree {
    git rev-parse --is-inside-work-tree &> /dev/null
}

function parse_git_branch {
    if we_are_in_git_work_tree
    then
    local BR=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD 2> /dev/null)
    if [ "$BR" == HEAD ]
    then
        local NM=$(git name-rev --name-only HEAD 2> /dev/null)
        if [ "$NM" != undefined ]
        then echo -n "@$NM"
        else git rev-parse --short HEAD 2> /dev/null
        fi
    else
        echo -n $BR
    fi
    fi
}

You can remove the if we_are_in_git_work_tree bit if you like; I just use it in another function in my PS1 which you can view in full here: PS1 line with git current branch and colors

Philtre answered 15/8, 2012 at 19:39 Comment(0)
D
0

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).

Doll answered 20/10, 2009 at 8:2 Comment(4)
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?Roseannaroseanne
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.Roseannaroseanne
This code is from GitHub : github.com/guides/put-your-git-branch-name-in-your-shell-prompt I've used only with Darwin and Ubuntu. It works well on both of them.Doll
git-branch is porcelain (user interface) command, and its output should not be used in scriptsSural
N
0

I found that calling git is rather slow (any of the subcommands), especially for updating the prompt. Time varies between .1 and .2 seconds within the root dir of a repo, and over .2 seconds outside a repo, on a top notch machine (raid 1, 8 gb ram, 8 hardware threads). It does run Cygwin, though.

Therefore I wrote this script for speed:

#!/usr/bin/perl

$cwd=$ENV{PWD}; #`pwd`;
chomp $cwd;

while (length $cwd)
{
        -d "$cwd/.git" and do {
                -f "$cwd/.git/HEAD" and do {
                        open IN, "<", "$cwd/.git/HEAD";
                        $_=<IN>;
                        close IN;
                        s@ref: refs/heads/@@;
                        print $_;
                };
                exit;
        };

        $cwd=~s@/[^/]*$@@;
}

May need some tweaking.

Nuts answered 22/10, 2013 at 3:16 Comment(1)
It has been 5 years since the post, git has got a lot faster. I just ran a loop in bash doing this 1000 times vs git rev-parse --abbrev-ref HEAD and the git command was ~2.5x faster (!) [git 2.17 vs perl 5.18, macOS]Linnette
S
0

If you are using gradle,

```

def gitHash = new ByteArrayOutputStream()    
project.exec {
                commandLine 'git', 'rev-parse', '--short', 'HEAD'
                standardOutput = gitHash
            }

def gitBranch = new ByteArrayOutputStream()   
project.exec {
                def gitCmd = "git symbolic-ref --short -q HEAD || git branch -rq --contains "+getGitHash()+" | sed -e '2,\$d'  -e 's/\\(.*\\)\\/\\(.*\\)\$/\\2/' || echo 'master'"
                commandLine "bash", "-c", "${gitCmd}"
                standardOutput = gitBranch
            }

```

Shonda answered 12/9, 2016 at 18:9 Comment(1)
This solves all situation, including detached mode. Great~~~~!Valene
H
-1

If you are on a detached head (i.e. you've checked out a release) and have an output from git status such as

HEAD detached at v1.7.3.1

And you want the release version, we use the following command...

git status --branch | head -n1 | tr -d 'A-Za-z: '

This returns 1.7.3.1, which we replace in our parameters.yml (Symfony) with

# RevNum=`svn status -u | grep revision | tr -d 'A-Za-z: '`  # the old SVN version
RevNum=`git status --branch | head -n1 | tr -d 'A-Za-z: '` # Git (obvs)

sed -i "/^    app_version:/c\    app_version:$RevNum" app/config/parameters.yml

Hope this helps :) Obviously if you have non-numerics in your branch name, you'll need to alter the arguments to the tr command.

Heyward answered 7/6, 2017 at 21:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.