Switch Git Branches Safely with git switch
You will finish with a small, reliable set of git switch commands for changing branches, starting work, inspecting an old commit and returning to where you were. The examples match Git 2.43.0, provided here by git-man package version 1:2.43.0-1ubuntu7.3.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need Git and an existing repository. These commands are ordinary user commands. They do not need sudo; using elevated privileges can leave root-owned files in your working tree.
Checkpoint
Run the following from the repository you intend to change:
$ git --version
git version 2.43.0
$ git status --short --branch
## current-branch
Your branch name and status will differ. Read the status before switching. Git can carry compatible local changes between branches, but it stops when the switch would overwrite them.
1. Switch to an existing local branch
Give git switch the exact local branch name:
$ git switch feature/login
Switched to branch 'feature/login'
Verify the result without relying on the feedback message:
$ git branch --show-current
feature/login
$ git status --short --branch
## feature/login
The working tree and index are updated to match the target branch. Switching does not require a clean tree in every case, but Git refuses when keeping your local edits would lose data.
2. Return to the previous branch
A single hyphen means the branch or commit used immediately before the current switch. It is useful when you changed branches by mistake:
$ git switch -
Switched to branch 'main'
$ git branch --show-current
main
This history includes switches made with git switch and git checkout. It is not a general undo for file edits or commits. If you need to recover an earlier position, inspect git reflog before changing anything else.
3. Create a branch and switch to it
Use -c when starting work from the current commit:
$ git switch -c fix/login-timeout
Switched to a new branch 'fix/login-timeout'
$ git branch --show-current
fix/login-timeout
The new branch starts where HEAD currently points. To start from another revision, put the start point after the branch name:
$ git switch -c backport-fix HEAD~3
Switched to a new branch 'backport-fix'
$ git log -1 --oneline
abc1234 Earlier commit subject
The abbreviated commit ID is repository-specific. The useful check is that git log -1 shows the intended starting commit.
4. Handle a branch that exists on a remote
When a local branch is absent but exactly one remote has a matching branch, git switch guesses that remote branch and creates a local tracking branch. This guessing is enabled by default:
$ git switch release/2026-09
Branch 'release/2026-09' set up to track remote branch 'release/2026-09' from 'origin'
Switched to a new branch 'release/2026-09'
Remote names and output vary. Confirm the upstream explicitly:
$ git branch --show-current
release/2026-09
$ git rev-parse --abbrev-ref --symbolic-full-name '@{u}'
origin/release/2026-09
If several remotes contain that name, Git may need help. Set checkout.defaultRemote to a preferred remote only when that is genuinely your repository policy:
$ git config checkout.defaultRemote origin
$ git switch release/2026-09
Use --no-guess when an absent local branch must be treated as an error rather than a possible remote branch:
$ git switch --no-guess release/2026-09
fatal: invalid reference: release/2026-09
Do not copy that failure text literally into a script as a success test. Check the command's exit status and inspect the branch list if the name is ambiguous.
5. Protect local changes before switching
If the target branch changes a file you have edited, the normal command stops:
$ git switch main
error: Your local changes to the following files would be overwritten by checkout:
app/config.yml
Please commit your changes or stash them before you switch branches.
Aborting
The exact wording can vary. At this point, choose deliberately. Commit work that belongs on the current branch, or stash it if it is unfinished and you understand how to restore it:
$ git stash push -m 'unfinished login timeout fix'
$ git switch main
Switched to branch 'main'
$ git stash pop
git stash pop can produce conflicts. Resolve them as you would a merge, then use git add to mark resolved files. The stash may remain in the stash list when applying it conflicts, so check with git stash list before deleting anything.
Destructive option: git switch --discard-changes TARGET, also available as -f, restores the index and working tree to the target. It throws away local changes that are overwritten. Do not use it as a routine fix. Save a patch or stash first if there is any chance the edits matter:
$ git diff > /tmp/login-timeout.patch
$ git switch --discard-changes main
Switched to branch 'main'
$ git diff --stat
$ test -s /tmp/login-timeout.patch && echo 'patch saved'
The patch is only a fallback for ordinary tracked text changes. Untracked files are not a complete backup, and binary or ignored files need separate handling.
6. Inspect a commit without creating a branch
Use --detach for a temporary inspection or experiment:
$ git switch --detach HEAD~3
HEAD is now at abc1234 Earlier commit subject
$ git status --short --branch
## HEAD (no branch)
This is a detached HEAD. Commits made here are not on a named branch and can become difficult to find after you leave. If the experiment is worth keeping, create a branch before switching away:
$ git switch -c keep-experiment
Switched to a new branch 'keep-experiment'
$ git branch --show-current
keep-experiment
To discard an uncommitted experiment, check git status first, then switch back or remove the changes intentionally. Detached HEAD does not itself delete files or commits.
7. Know the sharp edges
-C NAME creates a branch like -c, but resets an existing branch of that name to the selected start point. Treat it as a history-changing operation and verify the branch name before running it:
$ git switch -C rebuild-test HEAD~1
Switched to and reset branch 'rebuild-test'
$ git log -1 --oneline rebuild-test
Git also refuses to switch to a branch already checked out by another worktree. That protection prevents two worktrees from moving the same branch unexpectedly. Do not bypass it with --ignore-other-worktrees unless you understand the coordination risk.
Submodules are not updated by default. If the target commit records different submodule commits, use --recurse-submodules only when you intend to update those nested working trees too. A submodule may end up with a detached HEAD.
Done means
git switchreports the branch or detached commit you intended.git branch --show-currentconfirms a named branch, or deliberately prints nothing for detached HEAD.git status --short --branchshows what local work remains.- Unfinished edits were committed or stashed before a conflicting switch.
- You did not use
--discard-changesor-Cwithout checking the recovery implications. - An experiment worth keeping has a branch name before you leave it.