Overview
This error typically appears when the branch’s reflog file is missing or corrupted:
- Message: fatal: your current branch appears to be broken
- Common trigger: running git reflog or commands that consult the reflog
- Root cause: .git/logs/refs/heads/<branch> is missing or unreadable, or reflogs are disabled
Good news: the underlying commits are usually intact. You can recreate the reflog and, if necessary, repoint the branch to a known commit (e.g., the current HEAD or a remote branch).
Quickstart (safe defaults)
- Make a backup of the repository folder (or at least .git) before changes.
- Confirm current branch and commit:
branch=$(git symbolic-ref --short HEAD)
head=$(git rev-parse --verify HEAD)
- Ensure reflogs are enabled for future updates:
git config --bool core.logAllRefUpdates true
- Recreate the branch reflog entry by re-writing the branch ref to the current commit:
# Creates a fresh reflog entry without changing the commit
git update-ref -m "restore reflog" "refs/heads/$branch" "$head"
- Verify:
git reflog
If the branch pointer itself is wrong or missing, reset from a known source (e.g., origin/<branch>):
git fetch origin
git checkout -B "$branch" "origin/$branch"
Minimal working example
This reproduces the error and shows a fix. Run in a temp directory.
set -euo pipefail
# Setup a demo repo
git init demo && cd demo
git config user.name "Dev"
git config user.email "[email protected]"
echo hi > f.txt
git add f.txt
git commit -m "c1"
# Confirm reflog exists
git reflog | head -n1
# Simulate a missing reflog for the current branch
branch=$(git symbolic-ref --short HEAD)
rm -f ".git/logs/refs/heads/$branch"
# Observe the error (non-zero exit expected)
if git reflog; then echo "unexpected"; else echo "reflog missing (expected)"; fi
# Fix: recreate a clean reflog entry at current HEAD
head=$(git rev-parse HEAD)
git update-ref -m "restore reflog" "refs/heads/$branch" "$head"
# Works again
git reflog | head -n3
Step-by-step recovery
- Backup first
- Copy the repo or at least the .git directory.
- Identify your state
- Current branch: git symbolic-ref --short HEAD
- Current commit: git rev-parse --verify HEAD
- Remote tip: git ls-remote --heads origin | grep "$branch" or git rev-parse --verify "origin/$branch" after fetch
- Ensure reflogs are enabled
- git config --bool core.logAllRefUpdates true
- In bare repos, this may be off by default; enabling helps future recovery.
- If only the reflog is missing (branch points to the correct commit)
- Recreate an initial reflog entry without changing the commit:
git update-ref -m "restore reflog" "refs/heads/$(git symbolic-ref --short HEAD)" "$(git rev-parse HEAD)"
- Alternative: re-point the branch to the same commit using branch -f (also writes a reflog entry):
git branch -f "$(git symbolic-ref --short HEAD)" "$(git rev-parse HEAD)"
- If the branch pointer is missing or incorrect
- Prefer resetting from a remote you trust:
git fetch --all --prune
# Overwrite the local branch pointer to remote tip
git checkout -B "$branch" "origin/$branch"
- If there is no remote, but you know the commit SHA:
git checkout -B "$branch" <known-commit-sha>
- If you don’t know the SHA, try locating candidates:
# Find recent commits reachable in the repo
git fsck --full --no-reflogs | grep -E "^(dangling|reachable) commit" | head
# Or list all refs that still exist
git show-ref -d | sort
- Optional: seed branch reflog from HEAD reflog
- If .git/logs/HEAD exists, you can copy it as a starting point:
mkdir -p .git/logs/refs/heads
cp .git/logs/HEAD ".git/logs/refs/heads/$branch"
Note: This approximates history; timestamps and entries may not perfectly match past branch moves.
- Final checks
- Verify: git status, git log --oneline -n5, git reflog -n5
- Set upstream if needed: git branch --set-upstream-to "origin/$branch"
Pitfalls
- Hard resets overwrite your working tree. Stash or commit local changes first.
- Choosing the wrong commit when repointing the branch can hide work. Keep a note of the previous SHA and create a safety tag:
git tag safety-before-repair "$(git rev-parse HEAD)"
- Copying .git/logs/HEAD to the branch log is a best-effort guess, not a precise reconstruction.
- Aggressive cleanup (git gc --prune=now) may permanently remove unreachable objects; recover before pruning.
- Bare repositories often have reflogs disabled. Enable core.logAllRefUpdates before expecting logs.
Performance notes
- git fsck can be slow on large repos. Narrow scope by grepping only commits, and avoid running it repeatedly.
- git fetch --all --prune minimizes unnecessary local objects but may take time on large remotes.
- Reflog growth can impact disk usage. Periodically expire and pack:
git reflog expire --expire=90.days --expire-unreachable=30.days --all
git gc --prune=now --aggressive # use aggressive sparingly on very large repos
- Avoid frequent full clones for recovery; a local backup of .git is faster and safer.
FAQ
Q: Why did the reflog go missing? A: Common causes include manual deletion in .git/logs, repository migration, filesystem issues, or reflogs disabled (core.logAllRefUpdates=false).
Q: Did I lose commits? A: Not necessarily. Missing reflogs remove the convenience history, not the commits themselves. Use remotes, tags, and git fsck to locate commits.
Q: Is copying .git/logs/HEAD safe? A: It’s acceptable as a starting point. Prefer using git update-ref or git checkout -B to generate consistent reflog entries.
Q: Can I prevent this in CI/CD or servers? A: Enable core.logAllRefUpdates, avoid manual edits under .git, and run periodic git gc and reflog expire with conservative settings.
Q: What if HEAD is detached? A: Recreate the branch at the current commit:
git checkout -B <branch> HEAD
Then recreate the reflog using update-ref if needed.