The 'fatal: invalid reference' error occurs when Git cannot find the branch, tag, or commit you specified. This typically happens due to typos, case sensitivity issues, or when the remote branch hasn't been fetched yet.
This error occurs when Git cannot locate the reference (branch, tag, or commit) you're trying to check out. In Git terminology, a "reference" is any pointer to a commit - most commonly a branch name. When you see "fatal: invalid reference: branch-name", Git is telling you that it searched its list of local branches, remote tracking branches, tags, and other refs, but couldn't find anything matching that name. About 90% of the time, this error simply means "this branch doesn't exist." The reference could be misspelled, using incorrect casing (Git is case-sensitive), or the remote branch may not have been fetched to your local repository yet. This is one of the most common Git errors, especially when working with multiple remotes, switching between repositories, or trying to check out branches from remote repositories without fetching first.
First, check which branches actually exist in your repository:
# List all local branches
git branch
# List all branches including remote-tracking branches
git branch -a
# List branches with more details
git branch -vvLook for the branch you're trying to check out. Pay close attention to:
- Exact spelling
- Capitalization (feature-branch vs Feature-Branch)
- Prefix (origin/main vs main)
If the branch isn't listed, it may need to be fetched from the remote.
If the branch exists on the remote but not locally, fetch it:
# Fetch all branches from all remotes
git fetch --all
# Fetch from a specific remote
git fetch origin
# Fetch and prune deleted remote branches
git fetch --pruneAfter fetching, list branches again to confirm the branch is now available:
git branch -a | grep branch-nameNow try checking out the branch:
# Checkout and track the remote branch
git checkout branch-name
# Or explicitly create a local branch tracking the remote
git checkout -b branch-name origin/branch-nameGit branch names are case-sensitive on most systems. A common issue is trying to checkout a branch with incorrect casing:
# These are different branches in Git:
git checkout feature-branch # lowercase
git checkout Feature-Branch # mixed case
git checkout FEATURE-BRANCH # uppercaseTo find the correct case, search for the branch:
# Case-insensitive search for branches
git branch -a | grep -i "branch-name"
# Show all references containing the name
git show-ref | grep -i "branch-name"Note: On case-insensitive file systems (Windows, macOS default), Git may have issues with branches that differ only by case. Avoid creating branches with case-only differences.
If your branch name contains special characters, the shell might interpret them before Git sees them:
# Branch names with brackets need quoting (especially in zsh)
git checkout "feature/[JIRA-123]"
# Branch names with spaces (not recommended but possible)
git checkout "feature with spaces"
# Use single quotes to prevent variable expansion
git checkout 'feature/$variable'Common shell interpretation issues:
- [...] in zsh triggers glob pattern matching
- * and ? are wildcard characters
- $ triggers variable expansion
- Spaces split the argument into multiple parts
Best practice: Use simple branch names with only letters, numbers, hyphens, and forward slashes.
You can explicitly verify a reference exists before attempting checkout:
# Check if the reference exists
git show-ref --verify --quiet refs/heads/branch-name && echo "Branch exists" || echo "Branch not found"
# Check for remote branches
git show-ref --verify --quiet refs/remotes/origin/branch-name && echo "Remote branch exists" || echo "Not found"
# List all references to find the correct name
git show-refIf the branch doesn't exist, you can create it:
# Create a new branch at current HEAD
git checkout -b branch-name
# Create a new branch from a specific commit
git checkout -b branch-name commit-hash
# Create a branch tracking a remote branch
git checkout -b branch-name origin/branch-nameIf a branch was deleted on the remote, your local repository might still have stale references:
# Prune stale remote-tracking branches
git fetch --prune
# Or prune a specific remote
git remote prune origin
# Enable auto-pruning for future fetches
git config --global fetch.prune trueIf you have a local branch tracking a deleted remote branch:
# Delete the local branch
git branch -d branch-name
# Force delete if it has unmerged changes
git branch -D branch-nameIf none of the above works and you suspect repository corruption:
# Check repository for issues
git fsck
# Remove and re-add the remote
git remote remove origin
git remote add origin [email protected]:user/repo.git
git fetch origin
# Refresh all remote-tracking branches
git remote update origin --pruneAs a last resort, you can re-clone the repository:
# Move current repo and clone fresh
mv myrepo myrepo.backup
git clone [email protected]:user/repo.git
cd myrepo
# Copy any local uncommitted changes from backup if needed### Understanding Git References
A Git reference (ref) is a pointer to a commit. References include:
- Branches (refs/heads/main)
- Remote-tracking branches (refs/remotes/origin/main)
- Tags (refs/tags/v1.0.0)
- HEAD (current branch pointer)
- Stash (refs/stash)
When you run git checkout branch-name, Git searches for a matching reference in this order:
1. Local branch (refs/heads/branch-name)
2. Remote-tracking branch (refs/remotes/*/branch-name)
3. Tag (refs/tags/branch-name)
4. Abbreviated commit SHA
### Invalid Branch Name Characters
Git has strict rules for branch names. Invalid names include:
- Starting with a hyphen: -feature
- Containing ..: feature..test
- Containing @{: feature@{test}
- Ending with .lock: feature.lock
- Containing whitespace or control characters
- Using reserved names like HEAD
Check if a name is valid:
git check-ref-format --branch "proposed-name"### Using git switch (Modern Alternative)
Git 2.23+ introduced git switch as a cleaner alternative to git checkout for branch operations:
# Switch to existing branch
git switch branch-name
# Create and switch to new branch
git switch -c new-branch
# Create branch tracking remote
git switch -c branch-name --track origin/branch-name### Checkout vs Switch vs Restore
| Command | Purpose |
|---------|---------|
| git switch | Switch branches |
| git restore | Restore file contents |
| git checkout | Both (legacy, still works) |
### Dealing with Detached HEAD
If you accidentally check out a commit instead of a branch:
# Create a branch at current detached HEAD
git checkout -b new-branch-name
# Or return to a branch
git checkout main### Case Sensitivity on Different Systems
| OS | File System | Git Branch Case |
|----|-------------|-----------------|
| Linux | ext4 | Case-sensitive |
| macOS | APFS (default) | Case-insensitive |
| Windows | NTFS | Case-insensitive |
On case-insensitive systems, Git might get confused if you have branches like Feature and feature. Run git pack-refs --all to normalize references.
### CI/CD Considerations
In CI/CD pipelines, checkout errors often occur because:
- The branch hasn't propagated yet (add a small delay)
- Shallow clones don't include the branch
- Protected branches require authentication
# Fetch with full depth if shallow clone is causing issues
git fetch --unshallow
# Fetch specific branch explicitly
git fetch origin branch-name:refs/remotes/origin/branch-namewarning: 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