我一直认为git reset
和git checkout
是相同的,因为它们都会将项目带回特定的提交。但是,我觉得它们不可能完全相同,因为这将是多余的。这两者之间的实际差异是什么?我有点困惑,因为svn只有svn co
来恢复提交。
VonC和Charles非常清楚地解释了git reset
和git checkout
之间的差异。我目前的理解是git reset
将所有更改还原为特定提交,而git checkout
或多或少准备分支。我发现以下两个图对于理解这个理解非常有用:
从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
答案 0 :(得分:170)
git reset
专门针对更新索引,移动HEAD。git checkout
是关于更新工作树(指向索引或指定的树)。只有在结账时才会更新HEAD(如果没有,最后会得到detached HEAD)。相比之下,由于svn没有索引,只有一个工作树,svn checkout
会将给定的修订复制到一个单独的目录中。
git checkout
的等价物越接近:
svn update
(如果您在同一分支中,即相同的SVN网址)svn switch
(如果你签收的是同一个分支,但来自另一个SVN repo URL)所有这三个工作树修改(svn checkout
,update
,switch
)在git中只有一个命令:git checkout
。
但是由于git也有索引的概念(repo和工作树之间的“staging area”),你也有git reset
。
Thinkeye提到in the comments文章“Reset Demystified ”。
例如,如果我们有两个分支,“
master
”和“develop
”指向不同的提交,我们当前处于“develop
”(因此HEAD指向我们运行git reset master
,'develop
'本身现在将指向'master
'所做的相同提交。另一方面,如果我们改为运行
git checkout master
,“develop
”将不会移动,HEAD
本身就会移动。HEAD
现在将指向“master
”。因此,在这两种情况下,我们都在移动
HEAD
指向提交A
,但我们这样做是非常不同的。reset
会将分支HEAD
移动到,结帐移动HEAD
本身指向另一个分支。
在这些方面,但是:
然而,这个答案的第一段是误导性的:“
git checkout
...只有在结帐时才会更新HEAD(如果没有,你最终得到一个分离的HEAD)”。 /> 不正确:git checkout
即使你签出一个不是分支的提交也会更新HEAD(是的,你最终得到了一个分离的HEAD,但它仍然得到了更新)。git checkout a839e8f updates HEAD to point to commit a839e8f.
@LarsH是正确的。
第二个问题是关于HEAD所处的错误概念,只有在您结账时才会更新HEAD HEAD无论你身在何处,都像阴影一样 检查一些非分支引用(例如,标记)或直接提交将移动HEAD。分离头并不意味着你已经脱离了HEAD,这意味着头部与分支参考分离,你可以从中看到,例如git log --pretty=format:"%d" -1
。
- 附加头状态将以
开头(HEAD ->
,- 分离仍将显示
(HEAD
,但不会有箭头指向分支参考。
答案 1 :(得分:61)
以最简单的形式,reset
重置索引而不触及工作树,而checkout
更改工作树而不触及索引。
重置索引以匹配HEAD
,单独留下工作树:
git reset
从概念上讲,这会将索引检出到工作树中。要让它实际执行任何操作,您必须使用-f
强制它覆盖任何本地更改。这是一个安全功能,以确保“无论证”形式不具有破坏性:
git checkout
一旦开始添加参数,就会出现一些重叠。
checkout
通常与分支,标记或提交一起使用。在这种情况下,它将重置HEAD
和给定提交的索引,以及将索引签出到工作树中。
此外,如果您向--hard
提供reset
,则可以要求reset
覆盖工作树以及重置索引。
如果您当前已检出分支,则在提供备用分支或提交时,reset
和checkout
之间存在重要差异。 reset
会将当前分支更改为指向所选提交,而checkout
将仅保留当前分支,但会检出提供的分支或提交。
其他形式的reset
和commit
涉及提供路径。
如果提供reset
的路径,则无法提供--hard
,reset
只会将提供的路径的索引版本更改为提供的提交中的版本(或HEAD
如果你没有指定提交。)
如果您提供checkout
的路径,例如reset
,它将更新所提供路径的索引版本以匹配提供的提交(或HEAD
),但它将始终检查索引提供到工作树中的路径的版本。
答案 2 :(得分:27)
恢复变更时的一个简单用例:
1.如果要撤消已修改文件的暂存,请使用重置
2.如果要放弃对未分段文件的更改,请使用checkout。
答案 3 :(得分:9)
Atlassian为我们提供了关于 git reset , git checkout 以及 git revert 的出色解释。在本文中,将解释这些命令在不同级别上的不同用法 - 文件,暂存快照和提交。
https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting
答案 4 :(得分:8)
简而言之,关键区别是reset
移动当前分支引用,而checkout
则不移动(它移动HEAD)。
正如Pro Git书籍在Reset Demystified下解释,
reset
首先要做的是移动HEAD指向的内容。事实并非如此 与改变HEAD本身相同(这是checkout
所做的);reset
移动HEAD指向的分支。这意味着如果设置了HEAD 到master
分支(即您当前在master
分支上), 运行git reset 9e5e6a4
将从master
指向开始9e5e6a4
。 [强调补充]
另请参阅VonC对同一篇文章中very helpful text and diagram excerpt的回答,我不会在此重复。
当然,有很多细节可以了解checkout
和reset
对索引和工作树的影响,具体取决于使用的参数。两个命令之间可能存在许多相似之处和不同之处。但正如我所看到的,最关键的区别在于它们是否会移动当前分支的尖端。
答案 5 :(得分:1)
两个命令(重置和检出)完全不同。
checkout X
不是reset --hard X
如果X是分支名称,
checkout X
将更改当前分支
虽然reset --hard X
不会。
答案 6 :(得分:1)
简短助记符:
git reset HEAD : index = HEAD
git checkout : file_tree = index
git reset --hard HEAD : file_tree = index = HEAD