What these errors mean
- fatal: bad revision: Git can’t resolve the revision/range you asked for (branch, tag, commit, or range like A..B).
- unknown revision or path not in the working tree: Git can’t find the ref, or it thinks your argument is a path. Often accompanied by “Use '--' to separate paths from revisions.”
Typical triggers:
- Typos or case differences in branch/tag names
- Using a range with a non-existent ref (e.g., origin/branch without fetching)
- Confusing paths with refs (missing -- separator)
- Shallow clones or partial history in CI
Quickstart (fast diagnosis)
- Verify the ref exists:
- git rev-parse --verify <rev>
- git show-ref --heads --tags | grep <name>
- If it’s a remote branch, fetch it:
- git fetch --all --prune --tags
- For CI shallow clones: git fetch --unshallow || git fetch --depth=1000 --tags
- Disambiguate refs vs paths:
- Use -- to separate, e.g., git log main -- src/
- Check branch and tag spelling/case:
- git branch -a; git tag --list
- For ranges, verify both sides:
- git rev-parse --verify A && git rev-parse --verify B
Minimal working example
Reproduce the error and fix it locally.
#!/usr/bin/env bash
set -euo pipefail
rm -rf /tmp/bad-rev-demo
mkdir -p /tmp/bad-rev-demo && cd /tmp/bad-rev-demo
git init -q
printf "a" > a.txt
git add a.txt
git commit -qm "init"
git switch -c feature -q
printf "b" >> a.txt
git commit -am "feature work" -q
git switch -c main -q
# Intentional typo: 'features' does not exist
set +e
git log features..main 2>err.log
status=$?
set -e
echo "Exit: $status"; echo "--- error ---"; cat err.log
# Fix: use the correct ref and verify first
if git rev-parse --verify feature >/dev/null 2>&1; then
echo "\nFix: using feature..main"; git log --oneline feature..main | cat
fi
What you’ll see:
- The first git log fails with fatal: bad revision because features is not a ref.
- The fix uses the correct ref feature and succeeds.
Diagnose and fix (step-by-step)
Identify what you passed to Git
- Command: echo "$CMD"
- Look for range operators (.., ...), carets (^), and path-like segments.
Verify refs explicitly
- Single ref: git rev-parse --verify <ref>
- All refs: git show-ref --heads --tags | grep -E "<pattern>"
Disambiguate paths from refs
- If your command mixes both, insert -- before the first path:
- git log main -- app/ src/
- If you’re unsure, test both components with rev-parse.
- If your command mixes both, insert -- before the first path:
Handle remote refs
- Fetch updates: git fetch --all --prune --tags
- For a branch tracked on origin: git branch -r | grep origin/
- Create a local tracking branch if needed:
- git switch -c feature origin/feature
Fix ranges
- Ensure both sides exist: git rev-parse --verify A && git rev-parse --verify B
- Correct order may matter for your intent (A..B is “commits in B not in A”).
Address shallow or partial clones (common in CI/CD)
- If a commit SHA from the pipeline is missing: git fetch --depth=1000 origin +refs/heads/:refs/remotes/origin/
- To make it full: git fetch --unshallow || true
- Ensure tags are present if you reference them: git fetch --tags
Recover deleted/moved refs
- Check reflog: git reflog --date=iso | head
- If you find the commit, use its SHA directly or recreate the ref:
- git branch recovered <sha>
Detect corruption or broken refs (rare)
- Validate: git fsck --no-reflogs --full
- If broken, re-clone or fetch from a healthy remote.
Common causes and remedies
| Symptom | Cause | Fix |
|---|---|---|
| bad revision 'origin/feature' | Remote branch not fetched | git fetch origin origin/feature:refs/remotes/origin/feature |
| unknown revision or path | Path/ref ambiguity | Insert -- before paths: git diff main -- src/ |
| bad revision 'v1.2.3' | Tag not fetched | git fetch --tags; verify with git tag -l |
| bad revision 'A..B' | One side doesn’t exist | git rev-parse --verify A; git rev-parse --verify B |
| unknown revision in CI | Shallow clone missing history | git fetch --unshallow or increase --depth |
| wrong case 'Main' | Case-sensitive refs | Use exact case; list via git branch -a |
| stash@{n} invalid | Stash entry missing | git stash list; use an existing index |
Examples of correct usage
- Compare a branch to main:
- git log --oneline feature..main
- Diff a path against a branch:
- git diff main -- src/module/
- Show a remote branch after fetching:
- git fetch origin; git log origin/release --oneline
- Use an exact commit SHA:
- git show 1a2b3c4d
Pitfalls to avoid
- Forgetting -- when mixing refs and paths; Git may treat a filename as a ref.
- Assuming origin/branch exists locally without fetching.
- Using A..B when you meant B..A; the direction flips the set of commits.
- Relying on shallow clones in CI while referencing older SHAs or tags.
- Case mismatches on case-sensitive filesystems (Linux/macOS by default).
- Invisible whitespace in ref names when scripting; trim inputs.
CI/CD-specific notes
- Shallow clones: Many providers default to --depth=1. If your job needs ranges or tags, fetch more history.
- Merge commits in PR builds: The synthetic merge ref may not exist locally; fetch the specific refspec printed by the provider.
- Tags: Release pipelines often reference tags; ensure git fetch --tags or include +refs/tags/:refs/tags/ in your fetch step.
Performance notes
- Prefer targeted fetches over full-history unshallowing when possible:
- git fetch --depth=200 origin <branch>
- Avoid running git fsck on very large repos unless you suspect corruption; it is expensive.
- Use rev-parse to validate refs cheaply before expensive log/diff walks.
- For huge diffs, restrict paths or use --max-count / --since to limit history traversal.
Tiny FAQ
Why do I get “Use '--' to separate paths from revisions”?
Git detected ambiguity. Put -- before the first path: git log main -- src/What’s the difference between bad revision and unknown revision?
Practically the same: Git couldn’t resolve what you typed into a valid ref/range.How do I check if a branch exists?
git show-ref --heads | grep <branch> or git branch -aHow do I check if a tag exists?
git show-ref --tags | grep <tag> or git tag -l <pattern>Can I reference deleted commits?
Often yes via reflog: git reflog; then use the SHA or recreate the ref.
Summary checklist
- Verify refs: git rev-parse --verify <ref>
- Fetch what you need: branches and tags, possibly unshallow
- Disambiguate paths with --
- Validate both sides of ranges
- Mind case and typos