Getting the “current” Git branch, even if you’re in a detached HEAD state
(Note: This post is originally from 2017, and is copied to this new site for historical reasons. Opinions, network infrastructure, and other things may have changed since this was first written.)
Yeah, yeah, I know, remote branches aren’t technically my current branch because blah blah Git internals. Terminology purists can send me hate mail all they want. The point is, shell prompts commonly have a display for your current branch (like mine), but Google results at the time of writing all fail to work if you happen to be in a “detached HEAD state”, which you are when you’ve checked out a remote branch. So here’s a solution that works in that case.
#!/bin/sh
git rev-parse --git-dir &> /dev/null || return 0 # do nothing if not a git repo
commithash=$(git log --pretty=format:"%h" -n 1)
fullbranchname=$(git name-rev --name-only ${commithash})
branchtype=$(echo ${fullbranchname} | cut -d"/" -f1)
if [[ "${branchtype}" == "refs" ]]; then
branchname=$(echo ${fullbranchname} | cut -d"/" -f3)
elif [[ "${branchtype}" == "remotes" ]]; then
branchname=$(echo ${commithash} | cut -d"/" -f2-)
elif [[ "${branchtype}" == "${fullbranchname}" ]]; then
# git did it for us
branchname=${fullbranchname}
else
branchname=${fullbranchname}
# output a warning to stderr, convenience for maintenance
echo "warning: unrecognized branch type ${branchtype}" >&2
fi
echo ${branchname}
So, what’s happening in this file?
- First, the script makes sure the current working directory is within a Git repo in the first place. If not, the script exits immediately.
- Then, the first useful thing it does is save the current commit hash and full name of the ref you’ve checked out as provided by
git name-rev
. - The “full branch name” is then
cut
using/
as a separator, and the first “field” is compared. - If it’s
refs
, the last item is the branch name (refs/heads/master
becomesmaster
). - If the
cut
command returns the same thing it put in (no/
characters), then that is assumed to be the branch name. I don’t know, the first time I usedgit name-rev
, I gotrefs/heads/lavacano
, and then I put it in my prompt, and then when I checked out a local branch latergit name-rev
started returning justlavacano
. Maybe I did it weird the first time. - If the first field is
remotes
, then we’re on a remote branch, and the last two fields are used (remote/origin/master
becomesorigin/master
). - If none of the above are true, the “branch name” variable is filled with the whole
git name-rev
result and a warning is printed to stderr. - Finally, the result is printed to stdout.
This script has only been tested with remote branches and local branches. I don’t know what it will do if you’ve detached your HEAD in some other fashion.