【问题标题】:Is there a difference between "git reset --hard hash" and "git checkout hash"?“git reset --hard hash”和“git checkout hash”有区别吗?
【发布时间】:2011-02-02 05:58:07
【问题描述】:

虽然resetcheckout 在大多数情况下都有不同的用法,但我看不出这两者之间有什么区别。

可能会有人或没有人会费心添加--hard 选项来做一些基本的checkout 可以做的事情。

也许你会以不同的方式看待历史?

【问题讨论】:

  • 我在对您之前的一个问题的回答的更新中介绍了这一点 - 看看顶部附近的 ascii 艺术,特别是它说“离题:......”的地方(就像我一样我喜欢更多的代表在这里重新回答)
  • 我认为您可以在这里发布您的答案并从中获得代表。如果有人搜索此特定知识,他将找不到其他帖子。这个针对一个非常具体的主题,它应该有它的单独页面。顺便说一句,看来你是我的 Git 导师 :-) harigato,senseï!
  • 但是我明白了吗,不同的是reset会移动分支而不是结帐。
  • @e-satis:是的,你是对的。答案现在就在这里,如果可以的话,我会撤回我的近距离投票!不客气——我很高兴能够利用我在工作之外积累的所有知识。

标签: git git-checkout git-reset


【解决方案1】:

这个答案主要来自我对上一个问题的回答: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 来检查该提交。你可以摆弄它,做你喜欢做的事,但你已经把你的分支抛在脑后了。如果您也希望分支也移动,请使用重置。

【讨论】:

  • 像往常一样+1。这个线程 (marc.info/?l=git&m=120955970704567&w=2) 还添加了一个副作用:如果您在合并中(例如,当有合并冲突时,或者在 git merge --no-commit 之后),git reset --hard 忘记了合并,但 git checkout -f才不是;因此,后者之后的 git commit 会创建一个合并提交,这通常不是你想要的。
【解决方案2】:

如果 Git 提供的文档对您没有帮助,请查看 Mark Lodato 的 A Visual Git Reference

特别是如果您将git checkout <non-branch>git reset --hard <non-branch>(热链接)进行比较:


(来源:github.com

请注意,在 git reset --hard master~3 的情况下,您会留下部分 DAG 修订版 - 任何分支都不会引用某些提交。 reflog 保护(默认)30 天;它们最终会被修剪(移除)。

【讨论】:

    【解决方案3】:

    git-reset hash 将分支引用设置为给定的哈希值,并可选择使用--hard 将其检出。

    git-checkout hash 将工作树设置为给定的哈希值;除非 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]
    

    【讨论】:

      猜你喜欢
      • 2015-03-24
      • 1970-01-01
      • 2011-07-04
      • 2020-04-07
      • 2015-11-20
      • 2017-12-10
      • 2011-09-06
      • 2015-08-26
      • 1970-01-01
      相关资源
      最近更新 更多