What's the difference between "git reset" and "git checkout"?
I've always thought of git reset
and git checkout
as the same, in the sense that both bring the project back to a specific commit. However, I feel they can't be exactly the same, as that would be redundant. What is the actual difference between the two? I'm a bit confused, as the svn only has svn co
to revert the commit.
ADDED
The following diagram explains the difference, albeit in an either possibly oversimplified or incorrect manner. What do you think? Is it wrong or overly simplified?
ADDED 2
VonC and Charles explained the differences between git reset
and git checkout
really well. My current understanding is that git reset
reverts all of the changes back to a specific commit, whereas git checkout
more or less prepares for a branch. I found the following two diagrams quite useful in coming to this understanding:
ADDED 3
From http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html, checkout and reset can emulate the rebase.
git checkout bar
git reset --hard newbar
git branch -d newbar
git reset
is specifically about updating the index , moving the HEAD. git checkout
is about updating the working tree (to the index or the specified tree). It will update the HEAD only if you checkout a branch (if not, you end up with a detached HEAD). By comparison, since svn has no index, only a working tree, svn checkout
will copy a given revision on a separate directory.
The closer equivalent for git checkout
would:
svn update
(if you are in the same branch, meaning the same SVN URL) svn switch
(if you checkout for instance the same branch, but from another SVN repo URL) All those three working tree modifications ( svn checkout
, update
, switch
) have only one command in git: git checkout
.
But since git has also the notion of index (that "staging area" between the repo and the working tree), you also have git reset
.
Thinkeye mentions in the comments the article "Reset Demystified ".
For instance, if we have two branches, ' master
' and ' develop
' pointing at different commits, and we're currently on ' develop
' (so HEAD points to it) and we run git reset master
, ' develop
' itself will now point to the same commit that ' master
' does.
On the other hand, if we instead run git checkout master
, ' develop
' will not move, HEAD
itself will. HEAD
will now point to ' master
'.
So, in both cases we're moving HEAD
to point to commit A
, but how we do so is very different. reset
will move the branch HEAD
points to, checkout moves HEAD
itself to point to another branch.
In their simplest form, reset
resets the index without touching the working tree, while checkout
changes the working tree without touching the index.
Resets the index to match HEAD
, working tree left alone:
git reset
Conceptually, this checks out the index into the working tree. To get it to actually do anything you would have to use -f
to force it to overwrite any local changes. This is a safety feature to make sure that the "no argument" form isn't destructive:
git checkout
Once you start adding parameters it is true that there is some overlap.
checkout
is usually used with a branch, tag or commit. In this case it will reset HEAD
and the index to the given commit as well as performing the checkout of the index into the working tree.
Also, if you supply --hard
to reset
you can ask reset
to overwrite the working tree as well as resetting the index.
If you current have a branch checked out out there is a crucial different between reset
and checkout
when you supply an alternative branch or commit. reset
will change the current branch to point at the selected commit whereas checkout
will leave the current branch alone but will checkout the supplied branch or commit instead.
Other forms of reset
and commit
involve supplying paths.
If you supply paths to reset
you cannot supply --hard
and reset
will only change the index version of the supplied paths to the version in the supplied commit (or HEAD
if you don't specify a commit).
If you supply paths to checkout
, like reset
it will update the index version of the supplied paths to match the supplied commit (or HEAD
) but it will always checkout the index version of the supplied paths into the working tree.
One simple use case when reverting change:
1. Use reset if you want to undo staging of a modified file.
2. Use checkout if you want to discard changes to unstaged file/s.
上一篇: 我如何将我的更改推送到远程分支