Type git checkout and Git does one of two quite different jobs, depending on what comes next. Hand it a branch or a commit and it moves HEAD there, rewriting the working tree and index to match. Hand it a file and it restores that file.
Developers use it to switch branches and look at old releases, and also to throw away unstaged edits.
The manual page lists nine invocation forms under that one name, split into two modes (Git documentation, 2026).
The newer git switch and git restore commands each took over one of those modes. The original keeps working.
What is git checkout?

The command does two jobs. It moves HEAD to a branch or commit and updates the working tree and index to match, and it restores individual files from the index or from any commit.
Git’s manual splits these into a branch-switching mode, where git checkout branch-name points HEAD at that branch and rewrites the files in the working directory, and a file-restoring mode, where git checkout commit filename (or plain git checkout filename) replaces a file with an earlier version.
Git guesses whether the argument is a branch, a commit or a path. When a name is ambiguous, Git treats it as a branch or commit, and a double dash (git checkout -- file.txt) forces the path reading.
As in any version control system, a checkout selects which version of the project you are looking at.
That double duty is why Git 2.23, released on 16 August 2019, added git switch and git restore as dedicated replacements (Git documentation changelog). The older command still works in current releases.
What does git checkout change in the repository?

Depending on the form, the command rewrites where HEAD points, what the index holds, the file contents in the working tree, or some mix of those.
| Form | HEAD | Index | Working tree |
|---|---|---|---|
git checkout branch | Points to the branch | Matches the branch | Matches the branch |
git checkout commit | Points to the commit (detached) | Matches the commit | Matches the commit |
git checkout -- path | Unchanged | Unchanged | File reset to index version |
git checkout commit -- path | Unchanged | File updated | File replaced |
Pass a branch or commit and HEAD moves. Pass a path and it stays put.
The last row also touches the staging area. Git adds the restored file to the index, so it shows up as a staged change.
The blocking rule is narrower than most tutorials claim. A branch switch fails only when an uncommitted change touches a file that differs between your current commit and the target.
Every other uncommitted change comes along to the new branch.
Adding -m changes the failure case. Git saves the conflicting edits in a stash, switches, and reapplies them, and if reapplying conflicts, the entry stays in the stash list.
Nothing here contacts a remote. The command reads refs and objects already stored in the local repository.
How to switch, create and track branches with git checkout

Switching takes git checkout branch-name, and git checkout -b new-branch creates a branch and lands on it in one step. Name a branch that exists only on a remote and checkout builds a tracking branch instead.
Switching to an existing branch
git checkout feature-login sets the current branch to feature-login and updates the working directory to its contents.
git checkout -jumps back to the previous branch (Git reads the dash as shorthand for@{-1})- Running
git checkoutwith no argument changes nothing and only prints tracking information for the current branch
Creating a new branch with -b
The -b flag starts the new branch at the current commit unless you name a start point.
Because a Git branch is only a pointer to a commit, the pointer costs almost nothing to create.
-b fails when the name is taken, while -B resets the existing branch to the start point instead.
For instance, git checkout -b hotfix-1.4 v1.4.0 starts the branch at the v1.4.0 tag.
Checking out a remote branch

git checkout downloads nothing, so the remote-tracking branch must already exist locally. Start by fetching from the remote to refresh that list.
- Run
git fetch originto update the remote-tracking branches - Run
git checkout feature-login, using the plain name without origin/ - Read the confirmation line, which reports that the new local branch tracks origin/feature-login
Git builds the local branch only when exactly one remote has a matching name, per the git-checkout reference. With two remotes carrying the same name, the command fails unless checkout.defaultRemote names a winner, for example origin.
The explicit form, git checkout --track origin/feature-login, skips the guessing. Pass --no-guess, or set checkout.guess, to turn the shortcut off.
How to check out a commit or a tag
Pass a commit hash or a tag name, such as git checkout a1b2c3d or git checkout v2.0, and HEAD points straight at that commit instead of a branch.
Find the commit hash with git log, which prints one per commit. A Git tag labels one commit by name, so it is the cleanest way to read the code of a release.
Checkout accepts a few kinds of target:
- a full or abbreviated hash copied from git log
- a tag name, as in
git checkout v2.0 - a relative ref, so
git checkout main~2reads the code two commits behind main git checkout --detach main, which detaches at the tip of main without moving the branch
The Git manual frames this mode as inspection and throwaway experiments. It suits questions like when a bug first appeared.
Edits made in this state are safe to discard. Commits are another matter.
What is detached HEAD, and how are its commits recovered?
HEAD normally points at a branch name. In a detached state it points at a commit, so any new commit belongs to no branch.
The detached HEAD state is harmless for reading code. Trouble starts with the first commit.
The manual’s own example makes the risk concrete. Check out a tag, commit twice, then switch back to a branch, and those two commits have nothing pointing at them.
Garbage collection can delete unreferenced commits, and the reflog is the safety net with an expiry. Git drops reflog entries older than 90 days by default, and entries no longer reachable from the current tip after 30 days (git-gc documentation).
If you are still sitting on the detached commits, run git checkout -b rescue-branch. The commands git branch rescue-branch and git tag rescue-tag also keep the commits, but leave HEAD detached.
If you already left them behind, recover through the reflog:
- Run
git reflogto list where HEAD pointed recently (git reflog -2 HEADshows only the last two positions) - Find the entry for your last detached commit and copy its hash
- Run
git branch rescue-branchfollowed by that hash - Check the result with
git log rescue-branch
Past the expiry window, a gc run can remove the commits for good.
How to restore files with git checkout
Add a path to git checkout and it restores files instead of switching branches. Name no commit and the file comes from the index, name a commit and it comes from that commit.
git checkout -- src/app.jsresets the file to its staged version, which discards your unstaged edits- After
rm hello.c, runninggit checkout hello.cbrings the file back from the index git checkout main~2 Makefileswaps in the version from two commits backgit checkout -- '*.c'matches index entries, so deleted C files return too (keep the quotes so Git expands the glob, not the shell)
Check what will be lost with git diff before running any of these. Unstaged edits exist only in the working tree, so once a restore overwrites them, Git holds no copy to bring back.
Checkout also never deletes anything by default. In its default overlay mode it removes no files from the index or working tree, so restoring a directory from an old commit leaves files added since then in place (git-checkout manual).
To pick individual hunks, use git checkout -p. It walks through the differences and discards only the ones you accept. Unlike the plain path form, -p runs in no-overlay mode and has no overlay option.
A path with an unresolved merge conflict makes the restore fail until you stage it. --ours and --theirs pick one side, -m rebuilds the conflict markers, and -f skips unmerged files.
During git rebase and git pull --rebase the two labels swap, so --ours gives the branch you are rebasing onto and --theirs gives your own work. The surrounding workflow is covered in a guide to resolving merge conflicts in Git.
Which git checkout options matter?
A handful of options change behavior in ways worth knowing, and the table covers them.
| Option | Effect | Example |
|---|---|---|
--track (-t) | Sets upstream configuration, implies branch creation, names the local branch from the remote one | git checkout --track origin/hack |
--no-track | Skips upstream setup even when branch.autoSetupMerge is true | git checkout --no-track -b scratch origin/main |
--orphan | Starts an unborn branch whose first commit has no parent | git checkout --orphan clean-history |
-f | Switches regardless of local changes and untracked files in the way | git checkout -f main |
-p | Interactively discards the hunks you pick | git checkout -p -- src/app.js |
With --track, origin/hack becomes a local branch named hack. If the remote name has no slash, or Git’s guess comes out empty, pass the name yourself with -b.
The manual gives --orphan one concrete use: publishing a clean tree without its full history, such as an open source release of a project whose past contains proprietary code.
The index and working tree stay as if you had checked out the start point. Run git rm -rf . right after if the new history should begin empty.
Be careful with -f. It discards uncommitted changes and any untracked files in the way, with no stash and no prompt, so it is the one option to type last and slowly.
Why does git checkout fail, and how is each error fixed?

Most failures trace back to one of two messages: “Your local changes to the following files would be overwritten by checkout” and “pathspec … did not match any file(s) known to git”.
The first one means Git found an uncommitted edit in a file that differs on the target, so it aborted before touching anything. A few fixes exist, and they are not equal.
| Fix | Keeps your edits | Cost |
|---|---|---|
| Commit | Yes | Adds a commit you may amend later |
| Stash | Yes | Sits outside history, easy to forget |
| Discard the files | No | Unstaged work cannot be recovered |
git checkout -f | No | Also removes untracked files in the way |
Run git status first to see which files triggered the block.
Sources disagree on the wording. The manual’s example still shows “You have local changes to ‘frotz’; not switching branches”, while the text that current Git versions print in a terminal is the “would be overwritten by checkout” message.
The pathspec message means no branch, tag or commit carries that name, so Git read the argument as a file path. It says “file(s)” because the same command restores files.
- List local and remote-tracking names with
git branch -aand compare the spelling - If the branch is missing, run
git fetchand retry - If the hint says the name matched more than one remote tracking branch, run
git checkout --track origin/name - If you meant a file, confirm it is tracked, because checkout restores only paths Git knows about
Both errors abort before any file changes.
Is git checkout deprecated, and when to use git switch or git restore?

No. The git-checkout manual is still a full reference page. It was last revised in Git 2.55.0, dated 29 June 2026, and Git 2.56.0 (28 September 2026) left it unchanged.
The page points readers to git switch and git restore under SEE ALSO. The experimental label from the 2019 launch (GitHub Blog) does not appear in the current manual pages of either command.
| Task | git checkout | Newer command |
|---|---|---|
| Switch branch | git checkout feature | git switch feature |
| Create and switch | git checkout -b feature | git switch -c feature |
| Previous branch | git checkout - | git switch - |
| Detach at a commit | git checkout --detach HEAD~3 | git switch --detach HEAD~3 |
| Start an unborn branch | git checkout --orphan docs | git switch --orphan docs |
| Discard unstaged edits | git checkout -- app.js | git restore app.js |
| File from another commit | git checkout main~2 Makefile | git restore --source main~2 Makefile |
Everyday branch switching in Git is what git switch was built for. The mapping is not one to one, though.
git switch -cleaves the branch uncreated and unreset when the switch failsgit switch --orphanremoves all tracked files, whilegit checkout --orphankeeps the index and working tree as the start point had themgit restoredefaults to no-overlay and deletes tracked files absent from the source, where checkout path restores remove nothing
The manual also ties the two worlds together. git restore --staged hello.c does for one path what git reset does, and git restore --source=HEAD --staged --worktree hello.c matches the checkout path form.
Switch and restore make sense on Git 2.23 or newer, and especially when a mistyped argument must never be read as a file path (the manual’s own example is a branch named hello.c).
Keep git checkout on machines running a Git older than 2.23, in scripts and CI jobs that already work, and on teams with muscle memory and no reason to retrain it.
Rewriting working scripts buys nothing, since the manual still documents every form. New habits are another matter.
git checkout FAQ
Is git checkout the same as svn checkout?
Not at all. Subversion’s checkout downloads a working copy from a central server. Git’s version never downloads anything and only moves between versions already stored in the local repository.
How is git checkout different from git clone?
git clone copies an entire repository from a remote and checks out its default branch. Cloning runs once per machine, while checkout runs constantly inside a repository that already exists.
Does git checkout work like git reset?
Not really. Checkout moves HEAD and leaves branches where they are, while reset moves the current branch itself to another commit. Reset can also rewrite the index and working tree, so the two commands change different things.
Does it matter whether I check out main or master?
Only the name must match. git checkout accepts whichever branch name the repository uses and has no preference between them.
Run git branch to see the exact name, since a repository created years ago often says master where a new one says main.
Can I check out a branch that another worktree already has open?
Not unless you pass –ignore-other-worktrees. A git worktree gives each branch its own working directory, which removes the need to switch at all.
Protecting Uncommitted Work Before You Switch

Uncommitted work survives a git checkout only when it is saved first, and the safe order runs from reversible actions to irreversible ones.
- Run
git statusto see what is at risk - Commit or stash everything worth keeping
- Discard or force only what is disposable
Commit and stash can be undone later, while a discard or -f cannot, so they always come first.
The price is one extra commit or stash per switch, a few seconds against unstaged edits Git cannot bring back.
The order flips only when the edits are disposable, such as generated build files, where -f is the faster path.
A one-page cheat sheet for Git covers the commands that sit next to checkout.
- Notepad++ Android Options: Apps That Come Close - October 21, 2026
- Data Management Services: A Practical Guide for Growing Companies - October 21, 2026
- MongoDB Cheat Sheet - October 20, 2026




