Programming and IT
git checkout
Historically `git checkout` does several unrelated things at once: it moves your working copy to another branch, creates a branch and pulls a single file out of a commit. Because it was so overloaded, Git 2.23 added two separate commands — `switch` and `restore`. Here are both sides: the old way and its modern replacement.
In this article
Three jobs in one command#
The command changes what your working copy is looking at. What happens next depends on what you pass to it.
Pass a branch name, and HEAD moves to that branch while the files in your
project folder are rewritten to match its latest commit. Pass a commit hash, and
the files are rewritten to match that commit, but there is no branch pointer
there, so you end up in a detached state. Pass a file path after two dashes, and
the branch does not change at all — instead that file is overwritten with the
version from the given commit, and any unsaved edits in it are gone without a
warning.
That last case is the only truly dangerous use. Git cannot recover changes that were never committed or staged: they are not stored anywhere. So before rolling a file back, either commit or set your edits aside with git stash.
Syntax#
Since Git 2.23 two narrow commands do the same jobs:
The split is useful precisely because switch physically cannot touch files and
restore cannot change branches. Wiping out your work with one typo becomes much
harder.
Example: switching with uncommitted edits#
## feature-search
Your edit in app/views.py came with you: switching carries uncommitted changes
over to the new branch as long as they do not get in the way. They get in the
way when the target branch changes the same file. Then Git refuses:
error: Your local changes to the following files would be overwritten by checkout:
app/views.py
Please commit your changes or stash them before you switch branches.
Aborting.
This is not a failure but a safeguard: Git did not quietly throw your work away.
You have three options — commit, stash with git stash push, or switch with the
edits: git switch -m other-branch tries to carry them over with a merge.
Example: pulling a file out of the past#
You need an old version of a config file, but the history must stay untouched:
The file from commit 8a94f0c is now both in your working copy and in the index
(the M in the first column). The branch did not change, other files were not
touched. From here it is an ordinary edit: commit it or undo it.
Detached HEAD: what it is and how to get out#
Checking out a commit hash prints a fifteen-line warning whose point is in the first lines:
Note: switching to '9c1f8ab'.
You are in 'detached HEAD' state.
You are looking at a specific commit, and no branch points here. You can look
around and run the code freely. There is one danger: commits made in this state
are not attached to anything. Once you switch to a branch, the only way back to
them is git reflog.
There are two ways out. If you did not commit anything, just go back:
git switch -. If you did commit and want to keep the result, pin it with a
branch right where you are:
Now the commits belong to experiment and will not get lost. More on branches
in the article on git branch.
Common mistakes#
Forgetting the two dashes. If a branch called config exists,
git checkout config switches to that branch instead of restoring the file. The
two dashes tell Git: what follows are paths, not refs. git restore does not
have this ambiguity.
Expecting to undo a file restore. You cannot. git checkout -- file and
git restore file destroy unsaved edits for good — unlike operations on commits,
which the reflog can almost always bring back. The difference between "losing a
commit" and "losing unsaved work" is covered in detail in the article on
git reset.
The branch is not found. error: pathspec 'feature-x' did not match any file(s) known to git usually means the branch exists only on the server. Run
git fetch origin, and then git switch feature-x will automatically create a
local branch that tracks the remote one.
Step-by-step plan
- See where you aregit status -sb: the current branch and uncommitted files.
- Decide what to do with your editsCommit them, stash them, or make sure they will not block the switch.
- Switchgit switch <branch> or git checkout <branch>; for a new branch add -c or -b.
- Check that you switchedgit branch --show-current should print the name you expect.
- Restore a file if neededgit restore <file> or git checkout <commit> -- <file>; remember that unsaved edits in that file are lost.
Start learning this in your own space
The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.
Check yourself
1.Which command creates a branch called hotfix and switches to it at once?
2.You edited notes.md and ran git restore notes.md. What happened to your edits?
3.You are on commit 9c1f8ab in detached HEAD and made two commits. How do you keep them?
Sources
-
git switch referenceThe modern command for switching branchesfree
-
git restore referenceRestoring files with no risk of touching branchesfree
-
git checkout referenceThe full list of the old command's modesfree
-
Pro Git bookThe branching chapters — what happens to the pointers when you switchfree
Was this helpful?