Git's "is not a valid branch name" error is precise — the name you supplied violates one or more of Git's refname rules. The fix is almost always a one-line change once you know which character or pattern triggered it. This guide covers the full set of Git naming restrictions, the most common causes with exact fixes, how to rename a branch that already exists, and how to enforce valid naming across your whole team before anyone hits the error in the first place.
What the error means
When Git reports `fatal: 'some-name' is not a valid branch name`, it means the string you passed as a branch name violates Git's refname specification — the set of rules governing what constitutes a valid reference name in a Git repository. Git uses the same rules for branch names, tag names, and remote tracking names, because all of them are stored as references in the `.git/refs/` directory.
The validation happens before any object is written. Git runs your proposed name through `check_refname_format()` internally and aborts with the error if the name fails. This means you see the error immediately when running `git checkout -b`, `git branch`, or `git switch -c` — there is no partial state to clean up.
Where the error appears
- `git checkout -b branch-name` — creating a new branch and switching to it
- `git branch branch-name` — creating a new branch without switching
- `git switch -c branch-name` — the modern equivalent of checkout -b
- `git push origin branch-name` — pushing to a remote with an invalid local name
- CI/CD scripts — when a branch name is constructed programmatically from a ticket ID or commit message
Note
Git branch naming rules
Git's refname specification (defined in `git-check-ref-format` man page) describes a precise set of characters and patterns that are forbidden. Learning the rules once prevents all future naming errors — there are no ambiguous cases once you know the full list.
Explicitly forbidden characters and sequences
- Space (ASCII 0x20) — the most common mistake; use `-` or `_` instead.
- Tilde `~` — used in reflog notation (`branch~2` means two commits before the tip).
- Caret `^` — used in revision notation (`branch^` means the parent commit).
- Colon `:` — used in fetch refspec notation (`refs/heads/main:refs/heads/main`).
- Question mark `?` — glob wildcard character in ref patterns.
- Asterisk `*` — glob wildcard character in ref patterns.
- Open bracket `[` — glob character set opener.
- Backslash `\` — path separator on Windows; forbidden to avoid cross-platform issues.
- Double dot `..` — used in range notation (`main..feature`).
- @{ sequence — reflog shorthand notation (`branch@{1}` is a reflog entry).
Positional and structural rules
- Cannot start with a dot (`.`) — hidden files convention; `.hidden` is not a valid start.
- Cannot end with a dot (`.`) — ambiguous with `.lock` extension and file extension notation.
- Cannot end with `.lock` — Git uses `.lock` suffix for lock files; any path component ending in `.lock` is forbidden.
- Cannot start with a hyphen (`-`) — conflicts with command-line option parsing.
- Cannot contain consecutive dots (`..`) — range notation conflict (see above).
- Cannot be the single character `@` — shorthand for `HEAD`.
- Cannot contain control characters — ASCII characters below 0x20 and DEL (0x7F) are forbidden.
- Cannot be empty — an empty string is not a valid name.
# ✓ Valid branch names
git checkout -b feature/add-login
git checkout -b fix/null-pointer-123
git checkout -b release/v2.1.0
git checkout -b chore_update-deps
git checkout -b users/alice/experiment
# ✗ Invalid — contains a space
git checkout -b "my feature"
# fatal: 'my feature' is not a valid branch name
# ✗ Invalid — double dot
git checkout -b feature..login
# fatal: 'feature..login' is not a valid branch name
# ✗ Invalid — ends with .lock
git checkout -b release.lock
# fatal: 'release.lock' is not a valid branch name
# ✗ Invalid — starts with hyphen
git checkout -b -hotfix
# fatal: '-hotfix' is not a valid branch nameTip
Common causes and fixes
Most occurrences of this error come from a small number of repeating patterns. Each has a specific cause and a specific one-line fix.
Spaces from copy-pasted ticket titles
The most common trigger is copying a ticket or story title directly into the branch name. "Add user login form" becomes `git checkout -b Add user login form`, which Git sees as three separate arguments and rejects the branch name `Add`. Fix: replace every space with a hyphen. Many teams automate this with a `branch-from-ticket` alias or script that transforms the title before passing it to Git. The Slug Generator converts any text into a clean hyphen-separated slug suitable for branch names.
Special characters in CI/CD variable interpolation
CI pipelines often construct branch names from environment variables — PR titles, commit messages, or Jira ticket IDs. If any of those values contains a special character (a colon in a Jira ID like `PROJECT:123`, or a slash in a semver tag like `v1.0.0/rc.1`), the interpolated branch name will fail. Fix: sanitise the input before using it as a branch name. Replace non-alphanumeric characters with hyphens and strip any leading or trailing hyphens and dots.
Trailing dot or .lock suffix
A branch name that ends with a dot (`feature.`) or ends with `.lock` (`release.lock`) fails because Git reserves these patterns for lock files. This error typically appears when a developer types a name ending with a period by accident, or when a script appends `.lock` as part of a generated name. Fix: remove the trailing dot, or replace `.lock` with a valid suffix like `-locked` or `-pending`.
| Invalid pattern | Example | Fix |
|---|---|---|
| Space | feature/add login | feature/add-login |
| Double dot | feat..login | feat/login |
| Tilde | hotfix~v2 | hotfix-v2 |
| Colon | PROJECT:123 | PROJECT-123 |
| Trailing dot | release. | release |
| Ends with .lock | fix.lock | fix-pending |
| Starts with hyphen | -bugfix | bugfix |
| @ followed by { | user@{branch} | user-branch |
| Backslash | feature\login | feature/login |
Branch Name Convention Validator
Validate Git branch names against the full refname spec and your team's convention — browser-local, instant feedback, no setup required.
How to rename an invalid branch
In rare cases — particularly with older Git versions or branches created via third-party tools — you might end up with an invalid branch name already committed to your repository. Modern Git prevents this at creation time, but if you inherit a repository with a problematic branch name, here is how to fix it.
Rename the local branch
Run `git branch -m old-name new-name` to rename the branch in your local repository. The `-m` flag moves (renames) the branch reference without touching the commit history. If the old name contains characters that make quoting tricky in your shell, use single quotes around it: `git branch -m 'old name with spaces' new-valid-name`.
Push the new name to the remote
After renaming locally, push the new branch to the remote: `git push origin new-valid-name`. This creates the new branch on the remote. If the old branch was already pushed, teammates should update their local tracking reference with `git fetch --prune` after you delete the old remote branch.
Delete the old remote branch
Remove the old remote branch: `git push origin --delete old-name`. On GitHub, GitLab, and Bitbucket, you can also rename branches through the web UI under the branch list — this is the safer option when the old name contains characters that are difficult to pass through the CLI without escaping.
Update any open pull requests
If the renamed branch had open pull requests, most platforms (GitHub, GitLab) automatically update the PR's base branch reference when you rename through the web UI. If you renamed via CLI, check your open PRs and update the head branch reference manually if needed. Any CI runs against the old branch name will also need to be re-triggered against the new name.
Warning
Platform-specific naming rules
Git's own refname rules are the baseline. Remote hosting platforms apply additional restrictions on top — a name that passes Git's local validation may still fail on push to GitHub or GitLab. Understanding the platform-specific rules prevents the frustration of a name that works locally but fails remotely.
GitHub additional restrictions
GitHub rejects branch names that end with `.lock` at any path component (not just the final segment), branch names that contain consecutive dots at any position, and names that contain a null byte. GitHub also enforces a maximum branch name length of 255 bytes. The GitHub web interface additionally strips leading and trailing whitespace from branch names created through the UI.
GitLab additional restrictions
GitLab adds restrictions for protected branch patterns — names containing `*` wildcards are reserved for protected branch rules and cannot be used as literal branch names. GitLab also reserves branch names matching its internal namespacing like `protected` and `refs`. Branch names longer than 255 characters are rejected. The GitLab CI pipeline name validation is separate from the Git refname validation — CI variable interpolation errors appear as pipeline failures rather than Git errors.
Windows filesystem considerations
On Windows, the `.git/refs/heads/` directory stores each branch as a file. This means all Windows filename restrictions apply: names cannot contain `<`, `>`, `"`, `|`, `?`, or `*`; names cannot end with a space or period; and names are case-insensitive on NTFS. The case-insensitivity issue is particularly important in mixed teams — `Feature/Login` and `feature/login` are the same branch on Windows but different branches on Linux and macOS.
| Rule | Git core | GitHub | GitLab | Windows filesystem |
|---|---|---|---|---|
| No spaces | ✓ | ✓ | ✓ | ✓ |
| No .lock suffix | ✓ | ✓ any component | ✓ | ✓ |
| No double dots | ✓ | ✓ | ✓ | ✓ |
| No leading hyphen | ✓ | ✓ | ✓ | ✓ |
| Max 255 bytes | ✗ (no limit) | ✓ | ✓ | OS path limit |
| Case-insensitive | ✗ | ✗ | ✗ | ✓ (NTFS) |
| No * as literal name | ✓ | ✓ | ✓ reserved | N/A |
Branch naming conventions by team
Valid is the floor, not the ceiling. A branch name can be valid according to Git's rules while still being unclear, inconsistent, or unusable in your team's workflow. Established conventions add predictability on top of technical validity — every team member can read a branch name and immediately understand its purpose, scope, and lifecycle.
Gitflow convention
Gitflow uses five branch types: `main` (production), `develop` (integration), `feature/description`, `release/version`, and `hotfix/description`. Branch names use the category as a prefix followed by a forward slash and a hyphen-separated description. Release branches include the version number (`release/1.4.0`). This convention is well-supported by most Git GUI clients and CI tools, which recognise the prefixes as branch categories.
GitHub Flow and trunk-based conventions
GitHub Flow uses a simpler structure: `main` plus short-lived feature branches named descriptively (`add-oauth-login`, `fix-pagination-bug`). Trunk-based development similarly uses `main` plus very short-lived branches that are merged within hours. Both approaches prefer short, lowercase, hyphen-separated names without category prefixes — the assumption is that branch names are temporary and the PR title and description carry the context.
Ticket-reference conventions
Many teams prefix branch names with a ticket reference: `JIRA-1234-fix-login-bug` or `feat/GH-456-add-dark-mode`. The ticket ID provides traceability between the branch and the originating work item. When constructing these names programmatically, always sanitise the ticket description portion — ticket titles frequently contain colons, slashes, and other characters that break Git naming rules.
Branch names, like commit messages, are documentation. A consistent naming convention turns your branch list into a readable changelog of work in progress.
Preventing invalid branch names
Fixing individual errors is reactive. The better approach is to prevent invalid names from being created in the first place — through validation tools, editor integrations, and CI checks that catch problems before they disrupt the team.
Pre-push Git hooks
A `.git/hooks/pre-push` script runs before any `git push` and can validate the current branch name against your team's convention. If the name fails, the hook exits with a non-zero code and aborts the push with an explanatory message. Use the `pre-commit` framework to distribute hooks consistently across the team — individual `.git/hooks/` files are not committed to the repository, but a `.pre-commit-config.yaml` is.
CI pipeline name validation
Add a branch name validation step at the start of your CI pipeline. For GitHub Actions, use an early job step that checks the branch name against a regex pattern and fails the workflow if it does not match. This catches names that are technically valid according to Git but violate your team's convention — branch names without a type prefix, names that are too long, or names without a ticket reference. The Branch Name Convention Validator applies this same logic locally in your browser, useful for checking a name before you create the branch.
- Validate locally before creating: Use the Branch Name Convention Validator to check names against both Git rules and team conventions.
- Use a branch creation script: A small shell function that takes a ticket ID and description and produces a correctly-formatted branch name eliminates manual naming errors entirely.
- Add a pre-push hook: Validates the branch name on every push — the last defensive line before an invalid name reaches the remote.
- Lint in CI: A GitHub Actions or GitLab CI step that validates the branch name on every PR prevents convention violations from being merged.
- Document the convention in CONTRIBUTING.md: Team members who know the rules make fewer mistakes than those guessing from examples.
Tip
Key takeaways
- Git validates branch names against its refname spec and immediately rejects names containing spaces, `..`, `~`, `^`, `:`, `?`, `*`, `[`, `\`, `@{`, or names starting/ending with a dot or starting with a hyphen.
- The most common cause is copying a ticket title with spaces directly into a `git checkout -b` command — replace spaces with hyphens before using any title as a branch name.
- Use `git check-ref-format --branch name` on the command line to test a name, or the Branch Name Convention Validator in the browser.
- To rename an existing branch: `git branch -m old-name new-name` locally, then push the new name and delete the old remote branch with `git push origin --delete old-name`.
- Platform rules extend Git's baseline: GitHub and GitLab reject `.lock` at any path component, and Windows NTFS makes branch names case-insensitive — always use lowercase to avoid cross-platform collisions.
- Prevent errors systematically with a pre-push Git hook, a CI pipeline validation step, and a documented branch naming convention in your repository.
- The safest cross-platform convention: `type/lowercase-with-hyphens` (e.g. `feat/add-login-form`, `fix/null-pointer-auth`).