“git reset --hard hash”和“git checkout hash”之间有区别吗?

时间:2010-03-29 21:55:02

标签: git git-checkout git-reset

虽然resetcheckout大部分时间都有不同的用法,但我看不出这两者之间存在什么差异。

可能有一个或者没有人愿意添加--hard选项来执行基本checkout可以执行的操作。

也许你会看到历史的方式有所不同?

3 个答案:

答案 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]