"git reset"和"git checkout"有什么区别?

pro*_*eek 415 git git-checkout git-reset

我一直在想,git reset并且git checkout同样地,在这个意义上,两者都将项目带回特定的提交.但是,我觉得它们不可能完全相同,因为这将是多余的.这两者之间的实际差异是什么?我有点困惑,因为svn只svn co需要恢复提交.

添加

下面的图解释了差别,尽管在一个或者可能过于简化的或不正确的方式进行.你怎么看?是错误还是过度简化?

http://a.imageshack.us/img192/5440/screenshot20100903at416.png

增加2

VonC和Charles解释了两者之间的差异,git reset并且git checkout非常好.我目前的理解是git reset将所有更改还原为特定提交,而git checkout更多或更少的准备分支.我发现以下两个图对于理解这些图非常有用:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

增加3

http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html,checkout和reset可以模拟反叛.

在此输入图像描述

git checkout bar 
git reset --hard newbar 
git branch -d newbar 
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Von*_*onC 183

  • git reset具体是关于更新索引,移动HEAD.
  • git checkout是关于更新工作树(到索引或指定的树).只有在结帐时才会更新HEAD(如果没有,最终会得到一个分离的HEAD).

相比之下,因为SVN没有索引,只有一个工作树,git restore将复制在一个单独的目录中指定的修订版本.
更接近于等于git checkout:

  • svn checkout (如果您在同一分支中,表示相同的SVN URL)
  • git checkout (如果您签比如同一个分支,但是从另一个SVN回购URL)

所有这些三个工作树的修改(svn update,svn switch,svn checkout)在Git中只有一个命令:update.
但由于git的也有指数的概念(即"集结地"回购之间和工作树),你也有switch.


Thinkeye 在评论中提到文章" 重置揭秘 ".

例如,如果我们有两个分支,' git checkout'和' git reset'指向不同的提交,我们当前正在' master'(因此HEAD指向它)并且我们运行develop,' develop'本身现在将指向同一个提交' git reset master'确实.

另一方面,如果我们反而跑develop,' master'将不会移动,git checkout master它本身也会移动.develop现在将指向' HEAD'.

因此,在这两种情况下,我们都转向HEAD指向提交master,但我们如何这样做是非常不同的.HEAD将分支A点移动到,checkout移动reset自己指向另一个分支.

http://git-scm.com/images/reset/reset-checkout.png

但是,在这些方面,:

LarsH 在评论中补充道:

然而,这个答案的第一段是误导性的:" HEAD......只有在你结账时才更新HEAD(如果没有,你最终得到一个分离的HEAD)".
不是这样:HEAD即使你签出一个不是分支的提交,也会更新HEAD(是的,你最终得到了一个分离的HEAD,但它仍然得到了更新).

git checkout a839e8f updates HEAD to point to commit a839e8f.
Run Code Online (Sandbox Code Playgroud)

De Novo赞同评论:

@LarsH是正确的.
第二个问题是关于HEAD所处的错误概念,只有在你结账时才会更新HEAD.
HEAD无论你身在何处,都像阴影一样.
检查一些非分支引用(例如,标记)或直接提交将移动HEAD.分离头并不意味着你已经脱离HEAD,这意味着头部与分支ref分离,你可以从中看到,例如git checkout.

  • 附属国家将首先git checkout,
  • 分离仍将显示git log --pretty=format:"%d" -1,但不会有箭头到分支参考.

  • 我会说'git reset`是关于修改分支"label"并可选地更新索引或工作树作为副作用.`git checkout`是关于更新工作树和切换当前"选中"分支(`HEAD`). (7认同)
  • 进一步阅读搜索引擎发送到这里的所有失落的灵魂,我认为这是值得的:http://git-scm.com/blog/2011/07/11/reset.html (3认同)
  • @MikkoRantalainen不.`git reset`是关于`HEAD`的100%.它甚至可以在分离的HEAD模式下工作(http://stackoverflow.com/a/3965714/6309),这意味着它有*no*branch(!).git checkout也可以在分离的HEAD模式下工作,或者可以用于在分离的HEAD模式下签出SHA1:在这种情况下再次没有涉及分支. (2认同)
  • @Thinkeye很好的参考.我已将其与相关摘录一起包含在答案中以获得更多可见性. (2认同)
  • Reset Demystified的解释非常好.然而,这个答案的第一段是误导性的:"git checkout ......**只有在结账时才会更新HEAD**(如果没有,你最终得到一个分离的HEAD)".不正确... git checkout**将更新HEAD,即使你签出一个不是分支的提交**(是的,你最终得到了一个分离的HEAD,但它仍然得到了更新).也许我误解了"更新"的含义?`git checkout a839e8f`更新HEAD指向提交`a839e8f`. (2认同)
  • @LarsH 是正确的。第二个项目符号对“HEAD”的内容存在误解*仅当您签出分支时才会更新 HEAD*。无论你在哪里,“HEAD”都会像影子一样。检查一些非分支引用(例如,标签),或直接提交,将移动“HEAD”。分离的头并不意味着你已经与`HEAD`分离,它意味着头与分支引用分离,你可以从`git log --pretty=format:"%d" -1 中看到。 `。附加的头状态将以 `(HEAD ->` 开头,分离的状态仍将显示 `(HEAD`,但不会有指向分支引用的箭头。 (2认同)

CB *_*ley 66

在最简单的形式中,reset重置索引而不触及工作树,同时checkout更改工作树而不触及索引.

重置索引以匹配HEAD,单独保留工作树:

git reset
Run Code Online (Sandbox Code Playgroud)

从概念上讲,这会将索引检出到工作树中.要让它实际执行任何操作,您必须使用-f它来强制覆盖任何本地更改.这是一个安全功能,以确保"无参数"形式不具有破坏性:

git checkout
Run Code Online (Sandbox Code Playgroud)

一旦开始添加参数,就会发生一些重叠.

checkout通常与分支,标记或提交一起使用.在这种情况下,它将重置HEAD和给定提交的索引以及执行将索引签出到工作树中.

此外,如果您提供--hardreset您,可以要求reset覆盖工作树以及重置索引.

如果你当前有一个分支签出出之间有一个关键的不同resetcheckout当你提供一个选择分支或提交.reset将当前分支更改为指向所选提交,而checkout将仅保留当前分支,但将检出提供的分支或提交.

其他形式resetcommit涉及供应路径.

如果您提供的路径reset无法提供--hard,reset则只会将提供的路径的索引版本更改为提供的提交中的版本(或者HEAD如果您未指定提交).

如果您提供路径checkout,就像reset它将更新提供的路径的索引版本以匹配提供的提交(或HEAD),但它将始终检查提供的路径的索引版本到工作树.

  • 说"结帐"不会改变索引是不正确的:它在用于从分支转到另一个分支时会改变它. (2认同)

Joh*_*Doe 33

还原更改时的一个简单用例:
1.如果要撤消已修改文件的暂存,请使用reset.
2.如果要放弃对未分段文件的更改,请使用checkout.


Lar*_*rsH 9

简而言之,关键区别在于reset 移动当前分支参考,而checkout不是(它移动HEAD).

正如Pro Git的书在重置揭秘中解释的那样,

首先reset要做的是移动HEAD指向的内容.这与改变HEAD本身不同(这是做什么的checkout); reset 移动 HEAD指向的分支.这意味着如果HEAD设置为master分支(即您当前在master分支上),则运行git reset 9e5e6a4将从master指向开始 9e5e6a4.[强调补充]

另请参阅VonC的答案,以获取同一篇文章中非常有用的文本和图表摘录,我在此不再赘述.

当然也有什么影响了很多详细信息checkout,并reset可以对索引和工作树,这取决于使用什么参数.两个命令之间可能存在许多相似之处和不同之处.但正如我所看到的,最关键的区别在于它们是否会移动当前分支的尖端.

  • 良好的反馈,除了我的老答案.+1 (2认同)

Фил*_*ков 6

简短的助记符:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Run Code Online (Sandbox Code Playgroud)