Skip to content
shellmap

Show the current git branch

Print the name of the branch HEAD points at — used in shell prompts, CI build labels, and "deploy what's on the branch" scripts.

How to show the current git branch in each shell

Bashunix
git rev-parse --abbrev-ref HEAD

Returns `HEAD` (the literal string) when in detached-HEAD state — NOT an error, NOT the empty string. Prompts that test for branch names need to filter this case: `[ "$br" != "HEAD" ] || br=""`.

Zshunix
git rev-parse --abbrev-ref HEAD
Fishunix
git rev-parse --abbrev-ref HEAD

Capture with `(...)` not bash `$(...)`: `set br (git rev-parse --abbrev-ref HEAD 2>/dev/null)`. Fish strings come back without a trailing newline — no `$(... | tr -d \n)` cleanup needed.

PowerShellwindows
git rev-parse --abbrev-ref HEAD

Same git binary. To capture in pwsh: `$br = git rev-parse --abbrev-ref HEAD`. Check `$LASTEXITCODE` (NOT `$?` — pwsh `$?` is a generic boolean, not the integer rc) — non-zero means "not in a git repo".

cmd.exewindows
for /f "delims=" %i in ('git rev-parse --abbrev-ref HEAD') do @set br=%i

cmd has no command-substitution `$(...)`. The `for /f "delims="` trick captures a single line into `%i` (or `%%i` in a `.bat` file) — note the doubled `%%` only inside batch files.

Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.

Gotchas & notes

  • **`git rev-parse --abbrev-ref HEAD` vs `git symbolic-ref --short HEAD`** — the two canonical idioms differ on detached HEAD: `rev-parse --abbrev-ref` returns the literal string `HEAD` (rc 0); `symbolic-ref --short` exits with rc 128 and prints `fatal: ref HEAD is not a symbolic ref` to stderr. Use `rev-parse` for "give me a label, even if it's vacuous"; use `symbolic-ref` for "fail if we're not on a branch". `git branch --show-current` (git 2.22+, June 2019) is the modern equivalent of `symbolic-ref --short` and is the cleanest choice for new scripts — it returns the branch name or empty (NOT the word "HEAD") on detached HEAD with rc 0.
  • Exit-code conventions across shells: bash/zsh `$?` (last rc); fish `$status` (no `$?` — porting bash to fish trips on this); pwsh `$LASTEXITCODE` for native-command exit codes specifically, vs `$?` which is a `[bool]` "did the last *cmdlet* succeed" (different mechanism — `$?` after `git foo` is misleading: it can be `$true` even if git failed, because the pwsh wrapper around the native call "succeeded at invoking" it). The correct portable check after a git invocation: `if [ $? -ne 0 ]` (bash), `if test $status -ne 0` (fish), `if ($LASTEXITCODE -ne 0)` (pwsh).
  • Prompt-integration trap: shells re-evaluate the prompt every keystroke (or every command) — naive `git rev-parse` adds 5-50ms × every keystroke on slow disks. Use a prompt-cache: bash starship/posh-git/oh-my-bash handle this; raw `PS1` should `git status --porcelain --branch -uno 2>/dev/null` (one stat-heavy call returns BOTH branch + dirty + ahead/behind in a single fork) rather than three separate calls. fish: `fish_git_prompt` is built-in and async (no per-keystroke fork). pwsh: `posh-git` async-job pattern.
  • Worktree-aware lookup: in a git worktree (`git worktree add ../v2 main`), `git rev-parse --abbrev-ref HEAD` returns the worktree's checked-out branch (not the main repo's). To find the branch of a DIFFERENT worktree: `git -C ../v2 rev-parse --abbrev-ref HEAD`. To list all worktrees + their branches: `git worktree list` — output `path commit [branch]`. Submodules: `git submodule status` shows submodule SHAs but NOT branches (submodules pin to commits, not branches, by design).

Related commands

Related tasks