This error occurs when you try to create or checkout a Git branch with a name that violates Git's reference naming rules. Common causes include starting the name with a hyphen, using reserved names like HEAD, or including forbidden characters. The fix is to rename the branch using valid characters and following Git's naming conventions.
The "fatal: 'branch name' is not a valid branch name" error indicates that Git cannot accept the branch name you've specified because it violates one or more of Git's reference naming rules (defined in `git-check-ref-format`). Git uses branch names as file system references internally, so there are restrictions to ensure compatibility across operating systems, shell environments, and Git's own syntax. When you try to create a branch with an invalid name, Git immediately rejects it to prevent corruption or ambiguity in your repository. This error can appear in several situations: - Creating a new branch with `git checkout -b` or `git branch` - Switching to a branch with an invalid name - Renaming a branch to an invalid name - Receiving a branch from a remote repository with naming issues The error message itself tells you exactly which name is problematic, making it straightforward to identify and fix the issue.
First, understand which part of your branch name is causing the issue. Git's error message shows the exact name that failed.
# If you tried this:
git checkout -b -my-feature
# Git responds: fatal: '-my-feature' is not a valid branch name
# The leading hyphen is the problemYou can also use Git's built-in validation tool to check if a name is valid:
# Check if a branch name is valid
git check-ref-format --branch "my-branch-name"
# Returns 0 if valid, non-zero if invalid
# Or with verbose output
git check-ref-format --branch "my-branch-name" && echo "Valid" || echo "Invalid"This helps when you're unsure which character or pattern is problematic.
Branch names cannot start with a hyphen because Git interprets them as command-line flags.
The Problem:
git checkout -b -bugfix
# fatal: '-bugfix' is not a valid branch nameThe Solution:
# Option 1: Use a prefix before the hyphen
git checkout -b fix-bugfix
# Option 2: Use a different separator
git checkout -b bugfix_123
# Option 3: Use a category prefix (recommended)
git checkout -b bugfix/issue-123If you're receiving branch names from automation or user input, validate them first:
# Strip leading hyphens in a script
BRANCH_NAME="-my-branch"
SAFE_NAME="${BRANCH_NAME#-}" # Removes leading hyphen
git checkout -b "$SAFE_NAME"Git reserves certain names for internal references. You cannot use these as branch names:
Reserved names:
- HEAD - Points to current branch/commit
- FETCH_HEAD - Last fetched branch
- ORIG_HEAD - Previous HEAD before dangerous operations
- MERGE_HEAD - Commit being merged
- CHERRY_PICK_HEAD - Commit being cherry-picked
# These will all fail:
git checkout -b HEAD # fatal: 'HEAD' is not a valid branch name
git checkout -b FETCH_HEAD # Same errorThe Solution:
# Use descriptive names instead
git checkout -b feature/head-refactor
git checkout -b update-fetch-logicNote that lowercase versions may work (head), but it's best to avoid these names entirely to prevent confusion.
Several characters are forbidden in Git branch names because they have special meaning in Git syntax or shell commands:
Forbidden characters:
| Character | Reason |
|-----------|--------|
| Space | Shell interpretation issues |
| ~ | Ancestor reference (HEAD~1) |
| ^ | Parent reference (HEAD^2) |
| : | Pathspec separator (branch:file) |
| ? | Wildcard pattern |
| * | Wildcard pattern |
| [ | Wildcard pattern |
| \ | Escape character |
| .. | Range syntax (main..feature) |
| @{ | Reflog syntax (@{1}) |
# These all fail:
git checkout -b "feature branch" # Space
git checkout -b "feature~1" # Tilde
git checkout -b "fix:bug" # Colon
git checkout -b "test..suite" # Double dotsThe Solution:
# Replace with hyphens or underscores
git checkout -b feature-branch
git checkout -b feature_1
git checkout -b fix-bug
git checkout -b test-suite
# Or use slashes for hierarchy
git checkout -b feature/branch-nameGit has specific rules about dots in branch names:
1. Cannot start with a dot - Components can't begin with .
2. Cannot end with `.lock` - Reserved for Git's lock files
3. Cannot contain `..` - Used for range syntax
# These fail:
git checkout -b .hidden # Starts with dot
git checkout -b feature.lock # Ends with .lock
git checkout -b v1..v2 # Contains ..
git checkout -b refs/heads/.test # Component starts with dotThe Solution:
# For hidden-like names, use a prefix
git checkout -b dot-hidden
git checkout -b _hidden
# For lock-like names, use different suffix
git checkout -b feature-locked
git checkout -b feature.locked
# For version ranges, use single dots or hyphens
git checkout -b v1.2
git checkout -b v1-to-v2Slashes are allowed for hierarchical branch names (like feature/login), but with restrictions:
1. Cannot end with a slash
2. Cannot have consecutive slashes
3. Components between slashes must be valid
# These fail:
git checkout -b feature/ # Ends with slash
git checkout -b feature//login # Consecutive slashes
git checkout -b feature/.hidden # Component starts with dotThe Solution:
# Remove trailing slashes
git checkout -b feature/login
# Remove duplicate slashes
git checkout -b feature/user/login
# Ensure each component is valid
git checkout -b feature/hidden-fileAlso note: you cannot create a branch feature/login if a branch feature already exists (or vice versa), as Git stores branches as filesystem paths.
When building automation or scripts that create branches, use Git's built-in validation:
# Basic validation
git check-ref-format --branch "proposed-name"
# Normalize a name (fix some issues automatically)
git check-ref-format --normalize "refs/heads/FEATURE"
# Output: refs/heads/feature (lowercased)
# In a script:
validate_branch_name() {
local name="$1"
if git check-ref-format --branch "$name" >/dev/null 2>&1; then
echo "Valid branch name: $name"
return 0
else
echo "Invalid branch name: $name"
return 1
fi
}
# Usage
validate_branch_name "feature/new-login" && git checkout -b "feature/new-login"This is especially useful in CI/CD pipelines or tools that generate branch names from user input or ticket systems.
Sometimes you encounter invalid branch names from remote repositories, especially when migrating from other version control systems:
# If you get an error fetching:
# fatal: 'origin/feature branch' is not a valid branch name
# You'll need to rename it on the remote
# First, on a system where the branch exists:
git branch -m "feature branch" "feature-branch"
git push origin "feature-branch"
git push origin --delete "feature branch"For bulk renaming during migration:
# List all branches
git branch -a
# Rename problematic local branches
git branch -m "old name" "new-name"
# Push with the new name and delete the old
git push origin "new-name"
git push origin --delete "old name"If the invalid branch is on a remote you don't control, you may need to contact the repository administrator.
Complete Git Branch Naming Rules (git-check-ref-format):
Git's reference naming rules are documented in the git-check-ref-format man page. Here's the complete list:
1. No components starting with `.` - Each slash-separated component can't start with a dot
2. No `..` anywhere - Double dots are reserved for range syntax
3. No ASCII control characters - Bytes 0x00-0x1F and 0x7F (DEL)
4. **No space, ~, ^, :, ?, *, [ - Reserved for Git syntax
5. No backslash \ - Escape character
6. No components ending with .lock - Reserved for Git's locking mechanism
7. Cannot end with / - Invalid path
8. No consecutive slashes // - Invalid path
9. Cannot be the single character @ - Reserved for stash reference
10. Cannot be the empty string
11. No @{ sequence** - Reflog syntax
GitHub Additional Restrictions:
GitHub adds its own restrictions beyond Git's rules:
- No names that look like Git object IDs (40 hex characters)
- No names starting with refs/ (prevents confusion with full refs)
Why Hyphens Can't Start Branch Names:
The hyphen restriction isn't in Git's ref-format rules, but exists because Git parses command-line arguments. When you type:
git checkout -b -mybranchGit's argument parser sees -mybranch and tries to interpret it as an option flag. The workaround in Git 2.30+ is:
git checkout -b -- -mybranchThe -- tells Git that everything after is a positional argument, not an option. However, even if creation succeeds, working with hyphen-prefixed branches is awkward, so it's best to avoid them.
Branch Name Best Practices:
For maximum compatibility across tools, CI systems, and team members:
feature/TICKET-123-short-description
bugfix/TICKET-456-fix-login
hotfix/2024-01-security-patch
release/v1.2.0Rules:
- Use lowercase letters
- Use hyphens to separate words
- Use slashes for categorization
- Include ticket/issue numbers
- Keep names under 100 characters
- Avoid special characters entirely
Testing Invalid Names:
You can use git check-ref-format in scripts:
#!/bin/bash
# Sanitize a string for use as a branch name
sanitize_branch_name() {
local input="$1"
local output
# Convert to lowercase
output="${input,,}"
# Replace spaces and special chars with hyphens
output="${output//[^a-z0-9\/]/-}"
# Remove leading hyphens
output="${output#-}"
# Remove trailing slashes
output="${output%/}"
# Collapse multiple hyphens/slashes
output=$(echo "$output" | sed 's/-\+/-/g; s/\/\+/\//g')
echo "$output"
}
# Usage
sanitize_branch_name "Feature: Add Login!" # feature-add-loginGit 2.45+ Improvements:
Git 2.45 (Q2 2024) added helpful advice messages when branch creation fails. Instead of just the fatal error, you now get suggestions pointing to the git-check-ref-format documentation with specific rule violations.
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