In Git, how does git switch differ from git checkout for changing branches?
answer
- One verb was doing two unrelated jobs
- One of those jobs destroys uncommitted work
- Two narrower commands appeared in 2.23
- Detaching now needs an explicit flag
basics
~20 sgit switch only moves HEAD between branches or commits; git checkout does that plus restoring files from a commit into the index or working tree. Switch was added with git restore to split one overloaded command into two focused ones.
solid answer
~40 s`git checkout` historically did two unrelated jobs: move `HEAD` to a different branch or commit, and overwrite files in the working tree from some commit. Those share nothing except the name, and the file-restoring form is destructive, so a typo like `git checkout main.py` when you meant a branch silently discarded work. Git 2.23 split it: `git switch` changes which branch you are on, and `git restore` restores file contents. `git switch -c <name>` replaces `git checkout -b <name>`, and `git switch -` goes back to the previous branch. `git switch` also refuses to leave you on a bare commit unless you ask with `--detach`, whereas `git checkout <commit>` detaches silently. `git checkout` still works and is not going away — the split is about clarity and safety, not deprecation.
code
bash · 8 linesgit switch main # same as: git checkout main
git switch -c hotfix v1.2 # same as: git checkout -b hotfix v1.2
git switch - # back to the previous branch
git switch 9f2b6c1 # refuses: not a branch
git switch --detach 9f2b6c1 # explicit detached HEAD
git restore src/app.py # same as: git checkout -- src/app.pygo deeper
Know that git switch <branch> and git switch -c <branch> are the modern way to change and create branches, and that git checkout still does the same thing.
Explain the overload being split: switching HEAD versus rewriting file contents, why the second is destructive, and that git restore took over that half in Git 2.23.
Demonstrate the diagnostic value — when someone loses work, identify whether they switched branches (recoverable by hash) or restored files over uncommitted edits (unrecoverable), and know that switch requires --detach explicitly.
Own the tooling standard: which verbs your docs, scripts and onboarding teach, weighing the safety of switch/restore against the portability of checkout on older Git versions in build images.
## The problem being solved `git checkout` accumulated two fundamentally different behaviors: 1. **Branch/commit switching** — `git checkout main` repoints `HEAD` and updates the working tree to match. 2. **File restoration** — `git checkout -- src/app.py` throws away your edits to that path and rewrites it from the index; `git checkout <commit> -- path` rewrites it from that commit. The first is normally reversible; the second silently destroys uncommitted work that Git never recorded, so it cannot be undone by any Git command. Sharing one verb between them is a usability trap, made worse by the fact that a name can be ambiguous: if a branch and a file share a name, Git has to guess what you meant (and `--` exists precisely to disambiguate). ## The split Git 2.23 introduced two narrower commands: - **`git switch`** — only changes which branch (or commit) you are on. - **`git restore`** — only rewrites file contents in the working tree and/or the index. Both are additions. `git checkout` retains every behavior it ever had, so scripts and muscle memory keep working. ## Mapping the old forms | Old | New | |---|---| | `git checkout <branch>` | `git switch <branch>` | | `git checkout -b <new>` | `git switch -c <new>` | | `git checkout -B <new>` | `git switch -C <new>` | | `git checkout -` | `git switch -` | | `git checkout <commit>` | `git switch --detach <commit>` | | `git checkout -- <path>` | `git restore <path>` | ## The safety differences that matter **Detaching is now explicit.** `git checkout 9f2b6c1` or `git checkout v1.2` drops you onto a detached `HEAD` with a warning message. `git switch 9f2b6c1` refuses: it tells you that is not a branch and asks for `--detach`. That single change removes a large share of accidental detached-`HEAD` sessions, where people commit onto no branch and think the work vanished. **File destruction has its own verb.** `git restore <path>` reads as "put this file back", which is what it does; nobody types it expecting to change branches. Its options are explicit too: `--staged` targets the index, `--worktree` targets the files, `--source=<commit>` chooses where the content comes from. **Ambiguity is reduced.** Because `git switch` takes branch-ish arguments and `git restore` takes paths, the old "is this a branch or a file?" guess mostly disappears in day-to-day use. ## What is identical between them Switching semantics are the same in both commands. Both refuse to switch when the change would clobber local modifications that differ between the two commits, both carry uncommitted changes across when the affected files are the same on both sides, and both accept `-m` to attempt a merge of your local changes into the destination. `git switch` also supports `--orphan <name>` for starting a branch with no parent history, and `-c` accepts a start point, e.g. `git switch -c hotfix v1.2`. ## What to say when asked "which should I use?" For new work and for teaching, prefer `switch`/`restore`: the commands say what they do and the destructive one is named honestly. For scripts and documentation that must run against very old Git versions, `checkout` is the portable choice since `switch` and `restore` only exist from 2.23 onward. Do not claim `git checkout` is deprecated — Git has not deprecated it, and asserting that in an interview is an easy factual miss. ## Diagnosing with them When someone reports "my changes disappeared", the first question is which of the two jobs they actually ran. If they ran a branch switch, the work is almost certainly still committed and findable by hash. If they ran the file-restoring form on uncommitted edits, there is nothing in Git to recover — the content was never in the object database. Being able to make that distinction quickly is the real reason to understand the split.
- Is git checkout deprecated now that git switch exists?No. Git kept `git checkout` fully functional and it remains the only one of the three available on pre-2.23 versions. The split was about giving each job a clear, honestly named verb; `checkout` is still correct, just overloaded.
- Why is git switch's refusal to detach considered a safety feature?Committing on a detached HEAD leaves commits with no branch name pointing at them, so they look lost and eventually become garbage-collection candidates. Requiring `--detach` means you only end up there when you meant to, instead of by mistyping a branch name or checking out a tag.
- Can you switch branches with uncommitted changes in the working tree?Yes, when the modified files are identical between the two commits — Git carries the changes across. If switching would overwrite local modifications, both `switch` and `checkout` refuse and list the files, so you commit, stash, or discard first.
saying these in an interview costs you the question
- Says git checkout is deprecated and removed
- Thinks switch and checkout differ in how they update files on switch
- Believes git switch can restore a single file's contents
- Cannot say why one command doing both jobs was dangerous
- Claims git switch works on any Git version