What this error means
Git shows "fatal: A branch named '<name>' already exists" when you try to create a branch with a name that already exists in your local repository. This happens with commands like:
- git branch <name>
- git checkout -b <name>
- git switch -c <name>
It does not indicate a remote problem by itself; it’s a local name collision under refs/heads/<name>.
Quickstart (TL;DR)
- If you meant to switch to the branch:
- git switch <name>
- or: git checkout <name>
- If you want to recreate/reset the branch to a start point:
- git switch -C <name> <start-point>
- or: git checkout -B <name> <start-point>
- If you need a different name:
- git switch -c <new-name>
- If the local branch is stale and you want to delete it:
- git branch -d <name> # safe delete (merged only)
- git branch -D <name> # force delete (data loss risk)
- If a remote branch exists and you want a local tracking branch:
- git switch -c <name> --track origin/<name>
- or: git switch -C <name> origin/<name>
Minimal working example
Reproduce the error and apply common fixes in a scratch repo.
# 1) Create a repo and a branch
mkdir demo && cd demo
git init -q
echo one > file.txt
git add file.txt
git commit -qm "init"
git switch -c feature/login
# 2) Try to create it again (triggers the error)
# Any of these will fail because feature/login already exists
set -e
{
git branch feature/login
} || true
{
git checkout -b feature/login
} || true
{
git switch -c feature/login
} || true
# 3) Fix A: You meant to use it, not create it
git switch feature/login
# 4) Fix B: Reset it to main (danger: rewrites branch tip)
git switch -C feature/login main
# 5) Fix C: Use a different name instead
git switch -c feature/login-v2
Solutions by intent
- I only wanted to use the existing branch
- git switch <name>
- Legacy: git checkout <name>
- I need a branch at a specific commit, regardless of current branch tip
- Reset/create in one step:
- git switch -C <name> <start-point>
- or: git checkout -B <name> <start-point>
- Notes:
- -C and -B overwrite the existing branch ref to point at <start-point>.
- Use with care; you are rewriting the branch tip.
- I need a new branch with a similar name
- Choose another name:
- git switch -c <new-name>
- Consider a naming convention (e.g., feature/login-2 or feature/login-refactor).
- I want a local branch that tracks an existing remote branch
- Create and track:
- git switch -c <name> --track origin/<name>
- or replace both with one idempotent command:
- git switch -C <name> origin/<name>
- Afterward, pushing works without extra args: git push
- I want to delete the existing local branch, then recreate it
- Safe delete (only if fully merged):
- git branch -d <name>
- Force delete (even if unmerged; data loss risk):
- git branch -D <name>
- Recreate:
- git switch -c <name> <start-point>
- I need to rename the existing branch
- If you’re on a different branch:
- git branch -m <old> <new>
- If you’re on the branch:
- git branch -m <new>
- Push rename to remote (if needed):
- git push origin -u <new>
- git push origin --delete <old>
CI/CD and automation tips (DevOps)
- Prefer idempotent commands in pipelines:
- git fetch --prune origin
- git switch -C <name> origin/<name> This works whether the local branch exists or not and aligns it with the remote tip.
- For ephemeral runners, avoid local caching issues by always fetching the exact refs you need:
- git fetch --no-tags --depth=1 origin <refspec>
- If your CI uses a detached HEAD, explicitly create/reset the target branch with -C.
Numbered steps: diagnose and resolve
- List branches and confirm the collision
- git branch --list
- git show-ref --heads | grep "refs/heads/<name>"
- Decide your intent (switch, reset, rename, delete, or track remote).
- Apply the matching fix:
- Switch: git switch <name>
- Reset: git switch -C <name> <start-point>
- Rename: git branch -m <old> <new>
- Delete: git branch -d <name> (or -D)
- Track remote: git switch -C <name> origin/<name>
- If a remote is involved, sync it
- git push -u origin <name>
- If you renamed: git push origin --delete <old>
- Clean up stale refs
- git fetch --prune
Pitfalls and how to avoid them
- Data loss with -D, -C, and -B:
- These can move or delete refs even if commits are unmerged. Consider creating a safety tag first: git tag backup/<name> <name>.
- Branch name vs tag name collisions:
- If a tag shares the name, commands may be ambiguous. Prefer fully qualified refs: refs/heads/<name> or refs/tags/<name>.
- Case sensitivity:
- Git is case-sensitive; some filesystems are not. feature/Login and feature/login can collide on macOS/Windows. Normalize names.
- Protected branches on remotes:
- You may not be able to delete or force-push protected branches. Adjust branch protection or use a different branch.
- Detached HEAD confusion:
- Creating branches from a detached HEAD works, but remember to switch to them before committing.
Performance notes
- Listing branches in very large repos:
- Use filters: git branch --list 'feature/*'
- For scripts, prefer plumbing: git for-each-ref --format='%(refname:short)' refs/heads
- Reduce network overhead in CI:
- Fetch only needed refs and prune: git fetch --prune --depth=1 origin <branch>
- Idempotent reset avoids extra steps:
- git switch -C <name> <start-point> performs create-or-reset in one command.
FAQ (tiny)
- Q: I ran git checkout -b <name> and got the error. How do I just use it?
- A: Run git switch <name> (or git checkout <name>).
- Q: How do I create or reset the branch in one go?
- A: Use git switch -C <name> <start-point> or git checkout -B <name> <start-point>.
- Q: The branch exists remotely but not locally. What now?
- A: git switch -c <name> --track origin/<name> or git switch -C <name> origin/<name>.
- Q: Can I safely delete the local branch?
- A: Use git branch -d <name> to delete only if merged. Use -D only if you’re sure.
- Q: My CI keeps failing with this error. How to make it idempotent?
- A: Fetch with prune, then git switch -C <name> origin/<name>.