我一直认为git重置和git签出是一样的,在某种意义上,两者都将项目带回特定的提交。然而,我觉得它们不可能完全相同,因为那样就多余了。两者之间的实际区别是什么?我有点困惑,因为svn只有svn co来恢复提交。
添加
VonC和Charles很好地解释了git reset和git checkout之间的区别。我目前的理解是git重置将所有的更改恢复到特定的提交,而git签出或多或少为分支做准备。我发现下面两张图对理解这个问题非常有用:
增加了3
从http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html,签出和重置可以模拟rebase。
git checkout bar
git reset --hard newbar
git branch -d newbar
简而言之,关键的区别在于重置移动当前分支引用,而签出则不会(它移动HEAD)。
正如Pro Git书中“Reset Demystified”所解释的那样,
重置要做的第一件事就是移动HEAD所指向的对象。这不是
与更改HEAD本身相同(这是checkout所做的);重置
移动HEAD指向的分支。这意味着如果设置了HEAD
到主分支(即你目前在主分支上),
运行git reset 9e5e6a4将从master point to开始
9 e5e6a4。(强调添加)
另请参阅VonC的答案,以获得来自同一篇文章的非常有用的文本和图表摘录,我在这里不再重复。
当然,还有更多关于签出和重置对索引和工作树的影响的细节,这取决于所使用的参数。这两个命令之间可能有很多相似之处和不同点。但在我看来,最关键的区别在于他们是否移动了当前分支的尖端。
以下是对歧义的澄清:
git checkout会将HEAD移动到另一个提交(也可以使用branchname进行更改),但是:
在任何分支上,指向该分支顶端的指针(例如。,“main”)将保持不变(因此您可能最终处于分离的头部状态)。
同样,暂存区域和工作目录将保持不变(处于签出之前的类似状态)。
例子:
git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
git reset also moves the HEAD, however again, with two differences:
It moves the pointer that points to the commit at the tip of the current branch too. For instance, let's say the pointer to the current branch is named "main", then you perform a git-reset, now, the main pointer will point to another commit, and the HEAD will point to that commit as well(well basically, HEAD points to that commit indirectly through pointing to the main pointer, it is still an attached head(!), but it doesn't make any difference here).
Git-reset doesn't necessarily leave the staging area and the working directory on the same state they were in before the reset was performed. As you know, there are three types of reset: soft, mixed(default) and hard:
With the soft reset, the staging area and the working directory both remain in the state they've been on before the reset(similar to checkout in this regard, but don't forget the difference #1).
With the mixed reset which is the default type of reset, in addition to difference #1, the staging area's proposed next commit(what you've git-added basically), will also be set to the newly pointed-to-by-HEAD commit. BUT in the working directory, all the files will still have your latest edits to them (that's why this type of reset is the default one, so that you don't lose your work).
With the hard reset, in addition to difference #1, all the three trees HEAD, staging-area and ALSO the working-directory will change to the newly pointed-to-by-HEAD commit.
例子:
git reset --soft 3ad2bcf
git reset da3b47