Create a new branch in Git before you touch a file
Creating a branch is the cheapest operation in Git and the one most often done too late. A branch is a name pointing at a commit, so making one costs nothing and changes nothing. The expensive version is the one that happens after an hour of editing, when the changes on disk belong to a branch that does not exist yet and the question becomes how to move them without losing any. Both situations have clean answers, and they are different answers.
Creating a branch and standing on it are two operations
The most common early confusion has a precise cause. git branch <name> creates a new branch head pointing at the current HEAD, or at a start point if one is given, and it does not switch the working tree to it. The manual says so plainly, then points at git switch for the second half.
git branch feature/export
git switch feature/export
git switch -c <name> does both, and it is not merely shorthand. It is the transactional equivalent of the two commands: the branch is not created or reset unless the switch succeeds. If the branch is in use in another worktree, the failure leaves nothing half-done, whereas the two-command version would have created the branch already.
Three spellings are in circulation, and the differences are worth keeping straight.
| Command | Creates | Switches | Notes |
|---|---|---|---|
git branch <name> [<start>] |
Yes | No | Leaves you where you are. Good for labelling a commit |
git switch -c <name> [<start>] |
Yes | Yes | Fails as a unit rather than partially |
git switch -C <name> [<start>] |
Yes, or resets an existing one | Yes | Equivalent to git branch -f then switch |
git checkout -b <name> [<start>] |
Yes | Yes | The older spelling, still supported |
git switch and git restore were introduced to split the many jobs of git checkout into two commands with narrower scope, and both still carry a notice in their documentation stating that the behaviour may change. In practice git checkout -b is what older scripts and older colleagues use, and it is not deprecated. Pick one and stop translating between them.
Switching does not require a clean working tree. Uncommitted changes travel with you when they do not conflict with the target, and the operation aborts rather than proceeding when it would lose local work, unless told otherwise with --discard-changes or --merge. That refusal is what makes branching-first safe: there is no state in which switching quietly eats an edit. The full option list is in the git switch documentation.
Four things worth knowing before you create it
The branch itself is trivial. What makes it right or wrong is the state of the repository at the moment it is made, and that is four short questions.
git branch --show-current
git status --short
git fetch origin
git log --oneline -1
Where are you now. git branch --show-current prints one name and nothing else, which is more reliable than reading a shell prompt that may be cached or configured to shorten names.
What is uncommitted. Changes travel with a switch, so knowing what is in flight tells you whether the new branch will start with a clean tree or with an inherited edit.
Is the remote newer. A branch created from a local main that is four days behind will produce a diff full of other people's work at review time. Fetching first costs seconds.
Which commit is the starting point. The last line of the log is what the new branch will point at unless a start point is given, so reading it once removes any doubt about where the branch begins.
For an existing branch, git branch --contains <commit> answers whether a particular commit is already included, and --merged and --no-merged list branches by whether they have been integrated. Those are the same questions asked later, when deciding what is finished.
Choose the start point on purpose
Left alone, a new branch starts at whatever HEAD points at now, which is frequently not what was intended. Passing a start point takes one extra word and removes the most common cause of an unexpectedly large diff later.
git fetch origin
git switch -c fix/login origin/main
git switch -c spike v2.4.0
git switch -c retry HEAD~3
Branching from origin/main right after a fetch is the useful default in a shared repository, because it starts the work from what the remote currently has rather than from a local branch that has been sitting for three days. When a local branch is started from a remote-tracking branch, Git also sets branch.<name>.remote and branch.<name>.merge so that git pull knows where to pull from. branch.autoSetupMerge controls that behaviour globally, and --track or --no-track override it per command.
Two shorthands are worth memorising. A...B with three dots names the merge base of A and B when there is exactly one, which is how to branch from the point where two lines of work diverged rather than from either tip. And @{-N} refers to the Nth last branch or commit switched to, with - as a synonym for @{-1}, so git switch - returns to the previous branch and git switch -c hotfix @{-1} starts a branch from wherever you were before the current detour.
There is also a convenience that is easy to mistake for magic. Naming a branch that does not exist locally but does exist in exactly one remote makes git switch <branch> create a local branch tracking it. That is --guess, and it is the default. When the name exists in several remotes, checkout.defaultRemote decides, and checkout.guess turns the behaviour off entirely.
When the editing already happened
This is the situation the advice about branching first is meant to prevent, and it is completely recoverable.
If the changes are still uncommitted, simply create the branch and switch to it. The edits come along, because switching preserves local modifications that do not conflict with the target.
git status --short
git switch -c feature/export
git add -p
git commit
If the changes were already committed to the wrong branch, move the branch pointer rather than the files. Create a branch at the current tip so the commits stay reachable under a name, then rewind the branch that should not have them.
git branch feature/export
git reset --hard origin/main
git switch feature/export
That sequence is worth understanding rather than copying, because the order is what makes it safe. The new branch is created first, so the commits are reachable from something before anything moves. Only then does the rewind happen, and the rewind is safe only when the working tree is clean and the branch has not been pushed.
If the work is sitting in a stash and belongs on a branch of its own, there is a command for exactly that. git stash branch <name> creates a branch starting at the commit the stash was made from and applies the stash there, which sidesteps the conflicts that appear when a stash is applied to a tree that has moved on since.
Names that will not cause trouble later
Branch names are references, and references have rules. The ones that matter in daily use are short.
Slashes group names hierarchically, which is why feature/export and fix/login-timeout are conventional. No slash-separated component may begin with a dot or end with .lock. Names cannot contain two consecutive dots, a space, a tilde, a caret, a colon, a question mark, an asterisk, an open bracket, a backslash, or any ASCII control character. They cannot begin or end with a slash, contain consecutive slashes, end with a dot, contain the sequence @{, or consist of the single character @. A branch name also may not begin with a dash, which is stricter than the rule for references in general.
git check-ref-format --branch 'feature/export-v2'
That command answers the question without creating anything, which is useful in a script that builds branch names from ticket titles.
Two local considerations apply on a Mac. APFS is case-insensitive in its usual configuration, so treating Feature/Export and feature/export as two separate branches invites trouble that will not reproduce on a Linux build machine. And the initial branch in a newly created repository is currently named master unless --initial-branch or init.defaultBranch says otherwise, so setting that variable once is how to stop every new repository from disagreeing with the rest of your projects.
Throwaway branches and detached HEAD
Not every experiment deserves a name. git switch --detach <commit> moves to a commit for inspection and discardable experiments without any branch involved. Commits made there are reachable from nothing once you leave, which is the point, and also the risk: anything worth keeping needs a branch created before you switch away.
git switch --detach v2.4.0
git switch -c keep/that-idea
The second command is the rescue. While still sitting on the commit, three commands will capture it: git switch -c <name> creates a branch and leaves you on it, git branch <name> creates the branch and leaves HEAD detached, and git tag <name> creates a tag and also leaves HEAD detached. Any of the three is enough, because what matters is that something refers to the commit.
Move away without doing that and the commits are referenced by nothing, and routine garbage collection will eventually remove them. Until it does, the object name is recoverable from the reflog.
git reflog -2 HEAD
git log -g -2 HEAD
git branch keep/that-idea <hash>
This is the entire reason branching first is advice rather than pedantry. A branch created before the work exists costs one command. A branch created after the fact costs a reflog search, and after 30 days of not looking, it may cost the work.
Working on two branches at the same time
Stashing to look at another branch is a habit worth breaking, because Git can check out more than one branch at once. A repository has one main working tree and any number of linked ones.
git worktree add <path> creates a new working tree at that path and, in its simplest form, a new branch named after the final component of the path. git worktree add <path> <branch> uses an existing branch instead, and git worktree add -d <path> creates a throwaway worktree with a detached HEAD at the same commit as the current branch.
git worktree add ../hotfix
git worktree list
git worktree remove ../hotfix
The result is two ordinary folders on disk, each on its own branch, sharing one object database. Reviewing a colleague's branch while your own work stays exactly as it was becomes a matter of opening another folder rather than stashing, switching, switching back and hoping. Deleting a linked worktree by hand instead of with git worktree remove leaves administrative files behind, which git worktree prune clears, and which are eventually removed according to gc.worktreePruneExpire.
This is where the shape of the desktop starts to matter, since two worktrees mean two folders and two terminals that must not be confused with each other. A file manager with a built-in terminal makes the current directory and the branch visible in the same window, and the comparison with other file managers sets out which tools put those together.
What to change first
Set init.defaultBranch once so new repositories stop surprising you, then make git switch -c <name> origin/main the way work starts, after a fetch rather than before. For the next branch you only need to read, use git worktree add instead of stashing. If keeping track of which folder is on which branch means switching windows, Atriens puts both in one view.
Frequently asked questions
What is the difference between git branch and git switch -c?
git branch <name> creates the branch and leaves you on the current one. git switch -c <name> creates it and switches to it in a single transaction, so if the switch cannot happen the branch is not created or reset either. Use the first to label a commit, the second to start working.
Should git switch or git checkout -b be used to create a branch?
Both work. git switch exists because git checkout did too many unrelated jobs, and its documentation still carries a notice that the behaviour may change, while git checkout -b remains supported and is what most existing scripts use. Consistency within a team matters more than the choice itself.
Can a branch be created after the files have already been edited?
Yes. Uncommitted changes travel with you when you switch, as long as they do not conflict with the target, and the switch aborts rather than discarding work if they would. Create the branch, switch to it, then commit. If the changes were already committed to the wrong branch, create a branch at the current tip first, then rewind the other branch.
How do you create a branch from a specific commit or tag?
Pass a start point: git switch -c <name> <start>, where the start can be a commit hash, a tag, a remote-tracking branch such as origin/main, or an expression like HEAD~3. A...B names the merge base of two references when exactly one exists, which is how to branch from the point where two lines of work diverged.
What characters are not allowed in a Git branch name?
Spaces, tildes, carets, colons, question marks, asterisks, open brackets, backslashes and ASCII control characters are all rejected, as are two consecutive dots, a trailing dot, the sequence @{, a leading dash and a bare @. Slashes are allowed for grouping, but no component may start with a dot or end with .lock. git check-ref-format --branch <name> checks a name without creating it.
How can two branches be open at once without stashing?
Use a linked worktree. git worktree add ../hotfix creates a second working directory with its own branch, sharing the same repository, so the main working tree keeps its state untouched. Remove it with git worktree remove <path> when finished, which also cleans up the administrative files a manual deletion would leave behind.