Introduction
If you've been using Git for a while, you've probably reached for git checkout out of habit—it works, and it's everywhere in tutorials. But modern Git offers clearer, more focused commands: git restore and git switch: patterns, pitfalls and fixes address the root problem that checkout tried to solve by doing too much at once. Learning when and how to use these newer commands will make your workflow faster, safer, and easier to explain to teammates.
Why checkout became a problem
git checkout was the Swiss Army knife of Git: switch branches, discard changes, unstage files, restore deleted files. That flexibility meant every developer learned it first, but it also meant the command's intent was ambiguous. Was git checkout file.txt supposed to switch to a branch or restore a file? Context mattered, and context is easy to misread when you're moving fast.
Git 2.23 (August 2019) introduced git restore and git switch to split checkout into two purposeful commands. They're not replacements—git checkout still works—but they're the right tool for the job, and they've become standard in modern workflows.
git restore: Discarding working changes safely
The most common use of git restore is undoing changes to files in your working directory. If you've modified a file and want to throw away those changes, git restore makes that intention explicit.
git restore src/payment.tsThat command resets src/payment.ts to the version in the current HEAD commit. Your changes are gone, but it's clear what happened: you restored a file to its last committed state.
This is safer than git checkout src/payment.ts because the verb "restore" doesn't suggest branch switching. A teammate reading your command knows exactly what you did, no ambiguity.
Restoring multiple files
You can restore several files at once by listing them, or use a pattern:
git restore src/*.ts
git restore .Restore the entire working directory with git restore ., but use it with care—you'll lose all uncommitted work in one go. It's useful after a messy merge or when you want to start fresh on a branch.
Restoring from a specific commit
By default, git restore pulls from HEAD, but you can restore from any commit or branch:
git restore --source=main src/config.js
git restore --source=abc1234 src/utils.tsThis is powerful when you need a file from an earlier state but don't want to check out the entire branch. In a real scenario, imagine your team broke a feature in main three commits ago, but you need the old version of a config file right now. Rather than switching branches or hunting through history, you pull just that file from the commit that had it working.
git restore --staged: Unstaging changes
The other half of what git checkout did was unstaging files. If you've run git add and then changed your mind, git restore --staged removes the file from the staging area without touching your working changes.
git add src/auth.ts src/database.ts
git restore --staged src/database.tsNow src/auth.ts is staged and ready to commit, but src/database.ts is back in your working directory as modified but unstaged. The file itself hasn't changed; you've just removed it from the staging area.
Compare this to the old git reset HEAD src/database.ts. Both work, but git restore --staged is more explicit about what you're doing: you're restoring the file to its unstaged state.
Unstaging everything
If you've staged too much and want to start over:
git restore --staged .All staged changes move back to your working directory, uncommitted. This is equivalent to git reset, but again, the verb is clearer.
git switch: Changing branches with clarity
git switch does one thing: change branches. It's what git checkout branch-name did, but without the baggage of file restoration.
git switch feature/payment-retryYou're now on feature/payment-retry, and it's immediately obvious that you switched branches. There's no way to accidentally restore a file—you can't pass a file path to git switch.
Creating and switching in one step
Like git checkout -b, you can create a new branch and switch to it:
git switch -c feature/refund-flowThis is slightly more readable than git checkout -b because the verb "switch" immediately tells you what's happening. You're creating a branch and switching to it, not checking something out.
Switching based on a remote branch
A handy shortcut: if you try to switch to a branch that doesn't exist locally but matches a remote branch, Git creates a local tracking branch automatically:
git switch feature/rate-limitingIf origin/feature/rate-limiting exists but you don't have it locally, Git sets up a local branch tracking that remote. This saves you from typing git switch -c feature/rate-limiting --track origin/feature/rate-limiting.
Detached HEAD state
Switching to a commit (rather than a branch) puts you in a detached HEAD state:
git switch --detach abc1234You can now inspect that commit or test it without being on a branch. When you're done, git switch - takes you back to your previous branch. This is useful for quick investigations without cluttering your branch list.
Common mistakes
Confusing restore and switch
A common slip: trying to use git restore to switch branches, or git switch to discard changes. The commands are strict about their purpose, which is actually a safety feature. If you run git restore main, Git won't switch you to main—it'll try to restore a file named "main" from the index.
Forgetting --staged when you mean to unstage
git restore src/file.ts discards changes in your working directory. git restore --staged src/file.ts removes the file from the index. It's easy to forget the flag and lose work. If you're unsure, git status will tell you exactly what you need to do.
Using git restore . without thinking
git restore . nukes all your working changes. It's fast and sometimes necessary, but it's unforgiving. Make sure you've stashed anything important first, or use git diff to review what you're about to lose.
Mixing old and new commands on a team
If your team has folks on older versions of Git (pre-2.23), they won't have git restore and git switch. Document what you're using in your onboarding and contributing guides, or stick with git checkout and git reset if compatibility is critical. Most modern teams have moved on, but it's worth checking.
When checkout is still the right call
You don't have to abandon git checkout entirely. It's still useful in a few scenarios where its dual purpose shines:
- Quick one-liners: If you're switching branches and restoring a file in one command for some reason,
git checkoutcan do it in waysrestoreandswitchcan't. - Legacy codebases: Older team projects might have scripts that rely on
git checkout. - Shell history: If you've been using it for years, the muscle memory is there. Consistency within a team matters more than adopting the newest command.
But for new code, new teams, and new documentation, git restore and git switch are the clearer choice.
Key takeaways
git restore <file>discards working changes;git restore --staged <file>unstages without changing the file itself.git switch <branch>changes branches;git switch -c <branch>creates and switches in one step.git checkoutstill works but conflates branch switching and file restoration, making intent unclear.- Use
git restore --source=<commit>to pull a file from a specific point in history without switching branches. - Use
git switch --detach <commit>to inspect a commit without being on a branch. - The new commands are strict by design—they prevent accidental branch switches or file overwrites.
- Review
git statusandgit diffbefore runninggit restore .to avoid losing work. - Adopt
git restoreandgit switchin documentation, scripts, and team guidelines for consistency and clarity.






Comments
Loading comments…