gitStatus reports branch as ".invalid" in reftable-backend repos (reads .git/HEAD directly)

Open 💬 0 comments Opened Jun 13, 2026 by philwo

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), or
  • git 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)

View original on GitHub ↗