[git] How to programmatically determine the current checked out Git branch

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?

This question is related to git bash shell

The answer is


From this answer: https://stackoverflow.com/a/1418022/605356 :

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

Apparently works with Git 1.6.3 or newer.


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

git status | grep "On branch" | cut -c 11-

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


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

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

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/'

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


adapting the accepted answer to windows powershell:

Split-Path -Leaf (git symbolic-ref HEAD)

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

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

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;

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.


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
            }

```


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
$

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.


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


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

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.


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


Examples related to git

Does the target directory for a git clone have to match the repo name? Git fatal: protocol 'https' is not supported Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) git clone: Authentication failed for <URL> destination path already exists and is not an empty directory SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 GitLab remote: HTTP Basic: Access denied and fatal Authentication How can I switch to another branch in git? VS 2017 Git Local Commit DB.lock error on every commit How to remove an unpushed outgoing commit in Visual Studio?

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"