KhueApps
Home/DevOps/Fixing Git 'fatal: bad revision' and 'unknown revision' errors

Fixing Git 'fatal: bad revision' and 'unknown revision' errors

Last updated: October 07, 2025

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)

  1. Verify the ref exists:
    • git rev-parse --verify <rev>
    • git show-ref --heads --tags | grep <name>
  2. 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
  3. Disambiguate refs vs paths:
    • Use -- to separate, e.g., git log main -- src/
  4. Check branch and tag spelling/case:
    • git branch -a; git tag --list
  5. 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)

  1. Identify what you passed to Git

    • Command: echo "$CMD"
    • Look for range operators (.., ...), carets (^), and path-like segments.
  2. Verify refs explicitly

    • Single ref: git rev-parse --verify <ref>
    • All refs: git show-ref --heads --tags | grep -E "<pattern>"
  3. 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.
  4. 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
  5. 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”).
  6. 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
  7. 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>
  8. 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

SymptomCauseFix
bad revision 'origin/feature'Remote branch not fetchedgit fetch origin origin/feature:refs/remotes/origin/feature
unknown revision or pathPath/ref ambiguityInsert -- before paths: git diff main -- src/
bad revision 'v1.2.3'Tag not fetchedgit fetch --tags; verify with git tag -l
bad revision 'A..B'One side doesn’t existgit rev-parse --verify A; git rev-parse --verify B
unknown revision in CIShallow clone missing historygit fetch --unshallow or increase --depth
wrong case 'Main'Case-sensitive refsUse exact case; list via git branch -a
stash@{n} invalidStash entry missinggit 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 -a

  • How 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

Series: Git

DevOps