gitStatus reports branch as ".invalid" in reftable-backend repos (reads .git/HEAD directly)
Summary
The session-start gitStatus context block reports Current branch: .invalid for any repository that uses git's reftable ref-storage backend (extensions.refStorage = reftable). The real branch is reported correctly by git itself; only Claude Code's snapshot is wrong.
Root cause
When a repo uses the reftable backend, the real refs live in .git/reftable/*.ref, and git deliberately writes a stub .git/HEAD containing:
ref: refs/heads/.invalid
.invalid (RFC 2606) is an intentional sentinel: tools that read .git/HEAD directly — instead of asking git — get a guaranteed-bogus name so the breakage is visible rather than silent.
Claude Code's branch detection appears to read/parse .git/HEAD directly, so it picks up the sentinel verbatim.
Reproduction
mkdir reftable-repo && cd reftable-repo
git init --ref-format=reftable # or: git -c init.defaultRefFormat=reftable init
git commit --allow-empty -m init
git switch -c my-feature
cat .git/HEAD
# -> ref: refs/heads/.invalid (the stub)
git rev-parse --abbrev-ref HEAD
# -> my-feature (git's correct answer)
Start Claude Code in that repo. The gitStatus block shows Current branch: .invalid instead of my-feature.
Expected
Current branch: my-feature — derived via git rather than by reading .git/HEAD.
Suggested fix
Determine the branch by invoking git instead of parsing .git/HEAD:
git branch --show-current(empty when detached, which the snapshot can special-case), orgit symbolic-ref --quiet --short HEAD
Both understand reftable, worktrees, and packed/loose layouts. Direct .git/HEAD parsing is a heuristic that breaks on all of these.
Environment
- Claude Code 2.1.177
- git 2.54.0
- Linux (CachyOS)