【问题标题】:Reset/revert a whole branch to another branches state?将整个分支重置/恢复到另一个分支状态?
【发布时间】:2015-04-30 16:53:17
【问题描述】:

我有一个分支 A 和一个分支 B(以及其他一些分支)。

假设 A 的提交历史如下:

  • 提交 5
  • 提交 4
  • 提交 3
  • ...

以及B的提交历史:

  • 其他一些提交
  • 提交 4
  • 从分支 C 合并其他东西(到分支 B
  • 提交 3
  • ...

基本上我想要的是“删除”提交所做的所有更改其他一些提交将其他东西从分支C合并到分支B。

我希望分支 B 的工作树与分支 A 的工作树完全相同。

我如何做到这一点?

【问题讨论】:

    标签: git git-merge git-reset git-revert


    【解决方案1】:

    实现此目的的一种方法是通过git reset。在分支B 上执行

    git reset --hard A
    

    此后,分支B 指向A 的head-commit。 --hard 选项重置索引和工作树,以便所有跟踪的文件都重置为分支A 中的版本。 A 的旧 HEAD 提交 ID 存储在 .git/ORIG_HEAD 中,以便撤消更改。

    或者 - 虽然不在分支 B 上 - 您可以删除分支 B 并像这样重新创建它:

    git branch -d B     # delete branch B
    git branch B A      # re-create branch B and let it point to the commit of branch A
    

    除了第一个建议之外,这将使索引和工作树保持不变。

    【讨论】:

    • 谢谢。 reset --hard A 正是我正在寻找的。但是:我如何将这个(重置的分支)推回原点? origin 拒绝推送,因为有分歧的提交..
    • 您可以在push 命令中添加--force 选项来覆盖远程分支。但是您应该清楚地了解后果,例如描述了herehere
    • 有时候,在处理git的时候,你需要一些hard A来冷静一下。
    【解决方案2】:

    如果您希望您的分支 B 看起来与分支 A 完全相同。你可以做一个reset --hard

    git checkout branch-B
    
    git reset --hard branch-A
    

    请注意,在这种情况下您将丢失提交。您的分支-B 看起来与分支-A 完全一样,对分支-B 所做的任何提交,在分支-A 中不存在的任何提交,都将丢失。另外如果branch-B与其他人共享,不建议执行此操作。

    在这种情况下,您可以尝试在分支 B 中还原您不想要的提交

    git revert <sha-of-"some other commit">
    git revert <sha-of-"merge of other stuff from branch C (into branch B)"> 
    

    第二个提交看起来像一个合并提交,因此您可能还必须传递父级。

     git revert <sha-of-"merge of other stuff from branch C (into branch B)"> -m1
    

    【讨论】:

      【解决方案3】:

      为了完成,让我们添加这个非常简单的方法来实现它:

      git branch -f branchB branchA
      

      它利用了 git 中的分支仅仅是指针这一事实。此命令只是将一个分支的提示提交的 ref 替换为另一个。无需进行复杂的结构更改即可构建您已有的东西。

      (见doc

      【讨论】:

        【解决方案4】:

        我意识到(很晚,我承认)OP 实际上从未要求删除 B 的所有历史,而是更改,所以我的第一个答案和大多数其他人一样以上,确实实现了预期的工作树,但不幸的是,它以牺牲分支B的历史为代价,丢失了。

        因此,让我们在这里建议一种管道方法,以保留完整历史并获得您想要获得的确切树git commit-tree(请参阅doc

        # to be executed from branch B
        git reset --hard $(git commit-tree -m "Reset to A" -p $(git rev-parse --abbrev-ref HEAD) $(git rev-parse A)^{tree})
        

        说明

        git commit-tree 命令分解:

        git commit-tree -m <message> -p <parent> <tree>
        
        1. &lt;tree&gt; 需要在这里成为分支 A 的树,我们将使用 $(git rev-parse A)^{tree} 获取它。
        2. &lt;parent&gt;必须指向B的提示:$(git rev-parse --abbrev-ref HEAD)
        3. 那么上面两个参数加上消息被命令用来产生一个新的提交,
        4. 最后 git reset --hardgit commit-tree 返回的新提交上设置当前分支 (B)。

        一开始看起来很复杂,但是一个很棒的工具。

        【讨论】:

          【解决方案5】:

          正如其他人所表明的那样,git reset --hard 确实会使分支 B 看起来与分支 A 完全相同。但是,这将删除 B 的历史记录。避免此问题的另一种方法是创建并应用补丁文件:

          git checkout A
          git diff B > /tmp/AtoB.patch # Generate changes needed to make B match the current branch A
          git checkout B
          git apply /tmp/AtoB.patch # Update files to match the state of A
          git add -A # Track any deleted or newly created files
          git commit -a -m "Make B match A" # Commit the changes
          

          现在我们不是在“改写历史”,所以当你推到原点时不会有争议。这种方法的好处是同步是 B 历史中的离散提交,可以随时恢复。但是请注意,来自分支 A 的提交历史记录在翻译中会丢失。

          顺便说一句:如果您收到有关二进制文件的错误,请将 --binary 标志添加到您的 diff 命令中,如下所示 git diff --binary B &gt; /tmp/AtoB.patch

          【讨论】:

            猜你喜欢
            • 2017-02-15
            • 1970-01-01
            • 2020-02-20
            • 2021-03-20
            • 1970-01-01
            • 2012-09-02
            • 2014-02-22
            • 2022-11-09
            相关资源
            最近更新 更多