“git reset”和“git checkout”有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3639342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the difference between "git reset" and "git checkout"?
提问by prosseek
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.
我一直认为git reset
和git checkout
是一样的,从某种意义上说,两者都将项目带回到特定的提交。但是,我觉得它们不能完全相同,因为那是多余的。两者之间的实际区别是什么?我有点困惑,因为 svn 只svn co
需要恢复提交。
ADDED
添加
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:
VonC和查尔斯解释之间的差异git reset
和git checkout
真的很好。我目前的理解是git reset
将所有更改还原回特定的提交,而git checkout
或多或少地为分支做准备。我发现以下两个图表对于理解这种理解非常有用:
ADDED 3
添加 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.
从http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html,结帐和重置可以模拟变基。
git checkout bar
git reset --hard newbar
git branch -d newbar
采纳答案by VonC
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).
(actually, with Git 2.23 Q3 2019, this will begit restore
, not necessarilygit checkout
)
git reset
特别是关于更新索引,移动 HEAD。git checkout
是关于更新工作树(到索引或指定的树)。只有当您签出分支时,它才会更新 HEAD(如果没有,您最终会得到一个分离的 HEAD)。
(实际上,对于 Git 2.23 Q3 2019,这将是git restore
,不一定是git checkout
)
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 没有索引,只有一个工作树,svn checkout
将在单独的目录中复制给定的修订。
更接近的等价物是git checkout
:
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)
svn update
(如果你在同一个分支,意思是同一个SVN URL)svn switch
(例如,如果您签出相同的分支,但来自另一个 SVN 存储库 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
.
所有这三个工作树修改(svn checkout
, update
, switch
)在 git 中只有一个命令:git checkout
.
但是由于 git 也有索引的概念(repo 和工作树之间的“暂存区”),你也有git reset
.
Thinkeyementions in the commentsthe 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 rungit 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 commitA
, but how we do so is very different.reset
will move the branchHEAD
points to, checkout movesHEAD
itself to point to another branch.
例如,如果我们有两个分支,'
master
' 和 'develop
' 指向不同的提交,并且我们当前在 'develop
'(所以 HEAD 指向它)并且我们运行git reset master
,'develop
' 本身现在将指向相同的提交,'master
' 做。另一方面,如果我们改为运行
git checkout master
, 'develop
' 不会移动,HEAD
它本身会移动。HEAD
现在将指向“master
”。所以,在这两种情况下,我们都
HEAD
指向 commitA
,但我们这样做的方式却大不相同。reset
将分支HEAD
点移动到,结帐将HEAD
自身移动到另一个分支。
On those points, though:
不过,在这些方面:
LarsHadds in the comments:
The first paragraph of this answer, though, is misleading: "
git checkout
... will update the HEAD only if you checkout a branch (if not, you end up with a detached HEAD)".
Not true:git checkout
will update the HEAD even if you checkout a commit that's not a branch (and yes, you end up with a detached HEAD, but it still got updated).git checkout a839e8f updates HEAD to point to commit a839e8f.
但是,此答案的第一段具有误导性:“
git checkout
...仅当您签出分支时才会更新 HEAD(如果没有,您最终会得到一个分离的 HEAD)”。
不正确:git checkout
即使您签出一个不是分支的提交,也会更新 HEAD(是的,您最终得到了一个分离的 HEAD,但它仍然得到了更新)。git checkout a839e8f updates HEAD to point to commit a839e8f.
De Novoconcurs in the comments:
@LarsH is correct.
The second bullet has a misconception about what HEAD is in will update the HEAD only if you checkout a branch.
HEAD goes wherever you are, like a shadow.
Checking out some non-branch ref (e.g., a tag), or a commit directly, will move HEAD. Detached head doesn't mean you've detached from the HEAD, it means the head is detached from a branch ref, which you can see from, e.g.,git log --pretty=format:"%d" -1
.
- Attached head states will start with
(HEAD ->
,- detached will still show
(HEAD
, but will not have an arrow to a branch ref.
@LarsH 是正确的。
第二个项目符号对 HEAD 的内容存在误解,只有在您检出分支时才会更新 HEAD。
HEAD 无处不在,就像影子一样。
检出一些非分支引用(例如,标签)或直接提交,将移动 HEAD。分离的头部并不意味着你已经从 HEAD 分离,这意味着头部与分支引用分离,你可以从例如git log --pretty=format:"%d" -1
.
- 附加的元首状态将以
(HEAD ->
,- detached 仍会显示
(HEAD
,但不会有指向分支引用的箭头。
回答by CB Bailey
In their simplest form, reset
resets the index without touching the working tree, while checkout
changes the working tree without touching the index.
最简单的形式是reset
在不接触工作树的情况下重置索引,而checkout
在不接触索引的情况下更改工作树。
Resets the index to match HEAD
, working tree left alone:
将索引重置为 match HEAD
,单独留下工作树:
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:
从概念上讲,这会将索引检出到工作树中。为了让它真正做任何事情,你必须使用-f
它来强制它覆盖任何本地更改。这是一项安全功能,可确保“无参数”表单没有破坏性:
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.
checkout
通常与分支、标签或提交一起使用。在这种情况下,它会将HEAD
索引重置为给定的提交,并将索引检出到工作树中。
Also, if you supply --hard
to reset
you can ask reset
to overwrite the working tree as well as resetting the index.
此外,如果您提供--hard
给reset
您可以要求reset
覆盖工作树以及重置索引。
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.
如果您当前有一个分支被检出,那么在您提供替代分支或提交之间reset
和checkout
何时提供一个关键的不同。reset
将更改当前分支以指向选定的提交,而checkout
将保留当前分支,但会检出提供的分支或提交。
Other forms of reset
and commit
involve supplying paths.
其他形式的reset
和commit
涉及供应路径。
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).
如果您提供路径,reset
则无法提供,--hard
并且reset
只会将提供的路径的索引版本更改为提供的提交中的版本(或者HEAD
如果您未指定提交)。
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.
如果您提供路径checkout
,就像reset
它会更新所提供路径的索引版本以匹配所提供的提交(或HEAD
),但它会始终将所提供路径的索引版本检出到工作树中。
回答by John Doe
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.
还原更改时的一个简单用例:
1. 如果要撤消修改文件的暂存,请使用重置。
2. 如果要放弃对未暂存文件的更改,请使用 checkout。
回答by LarsH
The key difference in a nutshell is that reset
moves the current branch reference, while checkout
does not (it moves HEAD).
简而言之,关键区别在于reset
移动当前分支引用,而checkout
不会(它移动 HEAD)。
As the Pro Git book explains under Reset Demystified,
正如 Pro Git 书在Reset Demystified下解释的那样,
The first thing
reset
will do is move what HEAD points to. This isn't the same as changing HEAD itself(which is whatcheckout
does);reset
moves the branchthat HEAD is pointing to. This means if HEAD is set to themaster
branch (i.e. you're currently on themaster
branch), runninggit reset 9e5e6a4
will start by makingmaster
point to9e5e6a4
. [emphasis added]
首先
reset
要做的是移动 HEAD 指向的内容。这与更改 HEAD 本身不同(这是这样checkout
做的);reset
移动HEAD 指向的分支。这意味着如果 HEAD 设置为master
分支(即您当前在master
分支上),运行git reset 9e5e6a4
将通过master
指向9e5e6a4
. [强调]
See also VonC's answer for a very helpful text and diagram excerptfrom the same article, which I won't duplicate here.
另请参阅 VonC 的回答以获取来自同一篇文章的非常有用的文本和图表摘录,我不会在此处重复。
Of course there are a lot more details about what effects checkout
and reset
can have on the index and the working tree, depending on what parameters are used. There can be lots of similarities and differences between the two commands. But as I see it, the most crucial difference is whether they move the tip of the current branch.
当然,根据使用的参数,还有更多关于索引和工作树的影响checkout
和reset
可能产生的详细信息。这两个命令之间可能有很多相似之处和不同之处。但在我看来,最关键的区别是它们是否移动了当前分支的尖端。
回答by wiki1000
The two commands (reset and checkout) are completely different.
这两个命令(reset 和 checkout)是完全不同的。
checkout X
IS NOT reset --hard X
checkout X
不是 reset --hard X
If X is a branch name,
checkout X
will change the current branch
while reset --hard X
will not.
如果 X 是分支名称,
checkout X
则将更改当前分支而reset --hard X
不会。
回答by Филя Усков
brief mnemonics:
简短的助记符:
git reset HEAD : index = HEAD
git checkout : file_tree = index
git reset --hard HEAD : file_tree = index = HEAD