This error occurs when Git cannot find the specified commit reference during a revert operation. Common causes include shallow clones with limited history, syntax errors in the revision specifier, or referencing commits that don't exist in your local repository.
When you run `git revert HEAD~5` or any revert command with a revision specifier, Git needs to look up the specific commit you're referencing. The "fatal: bad revision" error means Git cannot resolve the revision you provided to an actual commit in your repository. This typically happens in one of three scenarios: your repository doesn't have enough commit history (common in CI/CD pipelines that use shallow clones), you've made a syntax error in the revision specifier (like using `HEAD-5` instead of `HEAD~5`), or the commit simply doesn't exist in your local repository yet (it may exist on the remote but hasn't been fetched). Understanding the difference between `~` (tilde) and `^` (caret) is crucial: `HEAD~5` means "5 commits before HEAD following first parents" while `HEAD^5` means "the 5th parent of HEAD" (only relevant for merge commits). Using the wrong syntax or referencing commits beyond your history will trigger this error.
Make sure you're using the correct syntax for revision specifiers:
# Correct: using tilde (~) for ancestor commits
git revert HEAD~5
# Wrong: using hyphen (-) instead of tilde
git revert HEAD-5 # This causes "bad revision" errorThe tilde (~) followed by a number means "N commits back following first parents." Using a hyphen is a common mistake.
Count the commits in your repository to ensure you're not referencing beyond the available history:
# Count total commits on current branch
git rev-list --count HEAD
# View recent commit history
git log --oneline | head -10If you only have 3 commits and try git revert HEAD~5, you'll get a bad revision error because that commit doesn't exist.
If you're working with a shallow clone (common in CI/CD pipelines), fetch the full history:
# Convert shallow clone to full clone
git fetch --unshallow
# Alternative: fetch specific depth
git fetch --depth=100For GitHub Actions, modify your checkout step:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetches all history for all branchesFor GitLab CI, set in your .gitlab-ci.yml:
variables:
GIT_DEPTH: 0 # Full cloneIf the commit exists on the remote but not locally, fetch it:
# Fetch all branches and tags
git fetch --all
# Fetch a specific branch
git fetch origin main
# Verify the commit now exists
git cat-file -t <commit-hash> # Should output "commit"If you're trying to revert a commit from a different branch, make sure that branch is fetched first.
Short commit hashes can be ambiguous or mistyped. Use the full 40-character hash:
# Get the full hash of a commit
git rev-parse HEAD~5
# Then use the full hash for the revert
git revert <full-40-char-hash>You can also use git log to copy the exact hash you need:
git log --oneline -10
# Pick the commit hash from the outputBefore running the revert, confirm the revision is valid:
# Check if revision exists and show commit info
git show HEAD~5 --no-patch
# Or check if a specific hash exists
git cat-file -e <commit-hash> && echo "Commit exists"If these commands fail, the commit doesn't exist in your local repository and you need to fetch it first.
If you're trying to revert to a previous state but can't find the commit, use reflog:
# Show all recent HEAD movements
git reflog
# Find the commit you want and use its reference
git revert HEAD@{3} # Reverts the state from 3 operations agoThe reflog shows every position HEAD has been in, even for commits that might not be reachable through normal history.
### Understanding Git Revision Syntax
Git supports multiple ways to reference commits:
| Syntax | Meaning |
|--------|---------|
| HEAD~N | N commits before HEAD (following first parent) |
| HEAD^N | Nth parent of HEAD (for merge commits) |
| @{N} | Nth reflog entry |
| branch@{upstream} | The upstream branch |
For most use cases, HEAD~N is what you want.
### Shallow Clones in CI/CD
Many CI/CD systems use shallow clones by default for performance:
- GitHub Actions: fetch-depth: 1 by default
- GitLab CI: GIT_DEPTH: 20 by default
- Bitbucket Pipelines: 50 commits by default
- Jenkins: Configurable per job
When you need to access older commits, you must either increase the fetch depth or unshallow the clone.
### git revert vs git reset
Remember that git revert creates a new commit that undoes changes, while git reset moves the branch pointer. If you just want to see the state of a file at a specific commit, use:
git show HEAD~5:path/to/file
# or checkout that version
git checkout HEAD~5 -- path/to/file### Handling Merge Commits
When reverting merge commits, you need to specify which parent to follow:
# Revert a merge commit, keeping changes from parent 1 (usually main branch)
git revert -m 1 <merge-commit-hash>Without -m, Git won't know which parent's changes to undo.
warning: BOM detected in file, this may cause issues
UTF-8 Byte Order Mark (BOM) detected in file
fatal: Server does not support --shallow-exclude
Server does not support --shallow-exclude
warning: filtering out blobs larger than limit
Git partial clone filtering large blobs warning
fatal: Server does not support --shallow-since
Server does not support --shallow-since in Git
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server