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
git rev-parse --abbrev-ref HEADReturns `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=""`.
git rev-parse --abbrev-ref HEADgit rev-parse --abbrev-ref HEADCapture 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.
git rev-parse --abbrev-ref HEADSame 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".
for /f "delims=" %i in ('git rev-parse --abbrev-ref HEAD') do @set br=%icmd 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
- List modified files in a git repo— Print the paths of files with uncommitted changes (staged or unstaged) — for pre-commit hooks, CI lint-only-changed gates, and "what am I about to commit".
- List staged changes— Print files (or the full diff) of what's currently in the git index — what `git commit` will commit if you run it now.
- Count files changed since a commit— Get the number of distinct files that differ between a reference commit (a tag, SHA, or `origin/main`) and the working tree — for CI gates and PR-size summaries.