2010-03-29 170 views
41

虽然resetcheckout大多数时候有不同的用法,但我不明白这两者之间有什么区别。“git reset --hard hash”和“git checkout hash”有区别吗?

有可能是一个或没有人会打扰增加一个--hard选项来做一些基本的checkout可以做的事情。

也许有区别是你会看到历史的方式?

+1

我介绍了这个在更新到我的回答对你以前的问题之一 - 看看ASCII艺术上方附近,特别是在它说:“Digression:...”(尽可能多我喜欢更多的代表在这里重新回答它) – Cascabel 2010-03-29 22:02:40

+0

我认为你可以在这里发布你的答案,并从中获得代表。如果有人搜索这个特定的知识,他不会找到其他职位。这一个目标是一个非常具体的主题,它应该拥有独立的页面。顺便说一句,看来你是我的Git导师:-) harigato,senseï! – 2010-03-29 22:10:40

+1

但是我得到它,区别在于重置移动分支而不是结帐。 – 2010-03-29 22:12:05

回答

52

这个答案大多是从我对前一个问题的回答引用的:git reset in plain english

这两者非常不同。它们导致索引和工作树的状态相同,但生成的历史和当前分支不相同。

假设你的历史看起来像这样,与当前已签出master分支:

- 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) 

因此,您使用结账时,好了,检查出承诺。你可以摆弄它,做你喜欢的事,但是你已经把你的分支留下了。如果您希望分支也移动,则使用重置。

+5

+1。这个线程(http://marc.info/?l=git&m=120955970704567&w=2)也增加了一个副作用:如果你在一个合并中(例如,当合并冲突,或者在'git合并 - ),'git reset --hard'忘记了合并的 ,但是'git checkout -f'没有;因此,在后者创建一个合并提交后,一个'git commit'通常不是你想要的。 – VonC 2010-03-29 22:18:41

+0

@VonC:和往常一样,你的优秀附加点! – Cascabel 2010-03-29 22:25:21

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的一部分的情况 - 一些提交没有被任何分支引用。那些受保护的(默认)30天,由reflog;他们最终将被修剪(删除)。

6

git-reset hash将分支引用设置为给定的散列,并且可以选择将其检出,并使用--hard

git-checkout hash将工作树设置为给定散列;除非散列是一个分支名称,否则最终会有一个分离的头部。

最终,有三件事情git的交易:

    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,即,头指向标题2。

HEAD -> topic2 

然后,git reset X将重置名称topic2指向X;这意味着,如果你犯了一个提交的分支标题2 P,事情会是这样的:

  T--S--R--Q [master][dev] 
     /
    A--B--C--D--E--F--G [topic1] 
        \ 
        Z--Y--X--W [topic3] 
          \ 
          P [topic2] 
相关问题