How to get the name of the current git branch into a variable in a shell script?

73,062

Solution 1

The * is expanded, what you can do is use sed instead of grep and get the name of the branch immediately:

branch=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')

And a version using git symbolic-ref, as suggested by Noufal Ibrahim

branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

To elaborate on the expansion, (as marco already did,) the expansion happens in the echo, when you do echo $test with $test containing * master then the * is expanded according to the normal expansion rules. To suppress this one would have to quote the variable, as shown by marco: echo "$test". Alternatively, if you get rid of the asterisk before you echo it, all will be fine, e.g. echo ${test:2} will just echo master. Alternatively you could assign it anew as you already proposed:

branch=${test:2}
echo $branch

This will echo master, like you wanted.

Solution 2

Expanding on Noufal Ibrahim's answer, use the --short flag with git-symbolic-ref, no need to fuss with sed.

I've been using something like this in hooks and it works well:

#!/bin/bash

branch=$(git symbolic-ref --short HEAD)

echo
echo "**** Running post-commit hook from branch $branch"
echo

That outputs "**** Running post-commit hook from branch master"

Note that git-symbolic-ref only works if you're in a repository. Luckily .git/HEAD, as a leftover from Git's early days, contains the same symbolic ref. If you want to get the active branch of several git repositories, without traversing directories, you could use a bash one-liner like this:

for repo in */.git; do branch=$(cat $repo/HEAD); echo ${repo%/.git} :  ${branch##*/}; done

Which outputs something like:

repo1 : master  
repo2 : dev  
repo3 : issue12

If you want to go further, the full ref contained in .git/HEAD is also a relative path to a file containing the SHA-1 hash of the branch's last commit.

Solution 3

I would use the git-symbolic-ref command in the git core. If you say git-symbolic-ref HEAD, you will get the name of the current branch.

Solution 4

I use this git describe --contains --all HEAD in my git helper scripts

example:

#!/bin/bash
branchname=$(git describe --contains --all HEAD)
git pull --rebase origin $branchname

I have that in a file called gpull in ~/scripts

Edit:

for a lot of CI environments, they'll check your code out in a "detached head" state, so then I'll use:

BRANCH=$(\
  git for-each-ref \
  --format='%(objectname) %(refname:short)' refs/heads \
  | awk "/^$(git rev-parse HEAD)/ {print \$2}"\
)

Solution 5

The problem relies on:

echo $test

In fact the variable test contains a wildcard which is expanded by the shell. To avoid that just protect $test with double quotes:

echo "$test"
Share:
73,062

Related videos on Youtube

Ben
Author by

Ben

Updated on February 02, 2021

Comments

  • Ben
    Ben over 3 years

    I am new to shell scripting and can't figure this out. If you are unfamiliar, the command git branch returns something like

    * develop
      master
    

    , where the asterisk marks the currently checked out branch. When I run the following in the terminal:

    git branch | grep "*"
    

    I get:

    * develop
    

    as expected.

    However, when I run

    test=$(git branch | grep "*")
    

    or

    test=`git branch | grep "*"`
    

    And then

    echo $test
    

    , the result is just a list of files in the directory. How do we make the value of test="* develop"?

    Then the next step (once we get "* develop" into a variable called test), is to get the substring. Would that just be the following?

    currentBranch=${test:2} 
    

    I was playing around with that substring function and I got "bad substitution" errors a lot and don't know why.

    • Dominik Sandjaja
      Dominik Sandjaja over 14 years
    • glenn jackman
      glenn jackman over 14 years
      What if you use single quotes around the asterisk: '*' instead of "*"
    • wich
      wich over 14 years
      @glenn that's not where the expansion happens, it's in the echo, as marco already elaborated upon.
  • Noufal Ibrahim
    Noufal Ibrahim over 14 years
    It would be courteous of you to mention my answer if you used elements from it to update yours.
  • wich
    wich over 14 years
    Of course, my apologies, I updated quickly before leaving, missed the attribution.
  • wich
    wich over 14 years
    that's not where the expansion happens, it's in the echo, as marco already elaborated upon.
  • Jamey Hicks
    Jamey Hicks over 14 years
    In later version of git, you will have to use git symbolic-ref HEAD instead.
  • hakre
    hakre about 10 years
    git describe --contains --all HEAD does not give me the current branch as highlighted by a star with git branch.
  • nemesisdesign
    nemesisdesign over 9 years
    this was useful in a jenkins build script, thanks
  • Pat
    Pat almost 9 years
    alias currentgitbranch='git symbolic-ref --short HEAD'
  • zhirzh
    zhirzh over 8 years
    ok, so I tried both the methods, and I must say that symbolic-ref won't always work. eg: if you checkout some old commit, it throws error, whereas the sed command gives something like (HEAD detached at 1qw23er)
  • Aral Balkan
    Aral Balkan about 8 years
    Note: the first technique works even if there are forward slashes in the branch name (e.g., because it is an issue URL), why the second one only takes the last segment in that case.
  • 0atman
    0atman almost 8 years
    This is the best answer, using --short gets you just the string you are looking for. Thanks!
  • UTF_or_Death
    UTF_or_Death about 5 years
    You'd want to use the --short flag to only get the branch name. For an example: While on the master branch git-symbolic-ref HEAD outputs refs/heads/master but ` git-symbolic-ref --short HEAD` only outputs master
  • João Portela
    João Portela about 3 years
    Attention: With git describe, if you have a tag on HEAD it will give you the tag name instead of branch name.
  • wilbur4321
    wilbur4321 about 2 years
    sed makes this even easier, actually! branch=$(git branch | sed '/^ /d;s/^\* //')