虽然reset
和checkout
大部分时间都有不同的用法,但我看不出这两者之间存在什么差异。
可能有一个或者没有人愿意添加--hard
选项来执行基本checkout
可以执行的操作。
也许你会看到历史的方式有所不同?
答案 0 :(得分:54)
这个答案主要是从我对上一个问题的回答中引用的:git reset in plain english。
这两者非常不同。它们导致索引和工作树的状态相同,但生成的历史记录和当前分支不同。
假设您的历史记录如下所示,当前已检出主分支:
- A - B - C (HEAD, master)
然后您运行git reset --hard B
。你会得到这个:
- A - B (HEAD, master) # - C is still here, but there's no
# branch pointing to it anymore
如果你使用--mixed
或--soft
,你实际上会得到这种效果 - 唯一的区别是你的工作树和索引会发生什么。在--hard
案例中,工作树和索引匹配B
。
现在,假设你改为运行git checkout B
。你会得到这个:
- A - B (HEAD) - C (master)
你最终处于分离的HEAD状态。 HEAD
,工作树,索引全部匹配B
,与硬重置相同,但主分支留在C
。如果此时你做了一个新的提交D
,你会得到这个,这可能不是你想要的:
- A - B - C (master)
\
D (HEAD)
所以,你使用checkout来检查那个提交。你可以摆弄它,做你喜欢的事,但你已经离开了你的分支。如果你想移动分支,你可以使用reset。
答案 1 :(得分:14)
如果Git提供的文档对您没有帮助,请查看Mark Lodato的A Visual Git Reference。
特别是如果您要将git checkout <non-branch>
与git reset --hard <non-branch>
进行比较(热链接):
git checkout master~3 http://marklodato.github.com/visual-git-guide/checkout-detached.svg.png
git reset --hard master~3 http://marklodato.github.com/visual-git-guide/reset-commit.svg.png
请注意,在git reset --hard master~3
的情况下,您留下了修订版DAG的一部分 - 某些提交未被任何分支引用。这些受到 reflog 的保护(默认情况下)为30天;他们最终会被修剪(删除)。
答案 2 :(得分:6)
git-reset hash
设置对给定哈希的分支引用,并可选择使用--hard
将其检出。
git-checkout hash
将工作树设置为给定的哈希值;除非哈希是一个分支名称,否则你最终会得到一个分离的头。
最终,git处理了3件事:
working tree (your code)
-------------------------------------------------------------------------
index/staging-area
-------------------------------------------------------------------------
repository (bunch of commits, trees, branch names, etc)
默认情况下, git-checkout
只更新索引和工作树,并且可以选择更新存储库中的某些内容(使用-b
选项)
git-reset
只更新存储库和索引,以及可选的工作树(使用--hard
选项)
你可以这样想到存储库:
HEAD -> master
refs:
master -> sha_of_commit_X
dev -> sha_of_commit_Y
objects: (addressed by sha1)
sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A ....
git-reset
操纵分支引用指向的内容。
假设您的历史记录如下:
T--S--R--Q [master][dev]
/
A--B--C--D--E--F--G [topic1]
\
Z--Y--X--W [topic2][topic3]
请记住,分支只是在您提交时自动前进的名称。
所以你有以下分支:
master -> Q
dev -> Q
topic1 -> G
topic2 -> W
topic3 -> W
您当前的分支是topic2
,也就是说,HEAD指向topic2。
HEAD -> topic2
然后,git reset X
会将名称topic2
重置为指向X;意思是如果你在分支topic2上提交P,事情将如下所示:
T--S--R--Q [master][dev]
/
A--B--C--D--E--F--G [topic1]
\
Z--Y--X--W [topic3]
\
P [topic2]