【问题标题】:How can I to do `git reset --soft <some-commit>` bypassing commits with merge?我怎样才能做`git reset --soft <some-commit>`绕过合并提交?
【发布时间】:2018-08-27 18:46:44
【问题描述】:

我有两个分支 - mastersome

  C2---M3---C4---C5 some
 /    /
C1---C3---C6---C7 master

C1C2... - 它是提交,M3 - 合并提交 C3

我想做:

git checkout some
git reset --soft C1

但我想绕过合并提交 M3

我该怎么做?

【问题讨论】:

  • 您的最终图表是什么样的?鉴于存在合并提交,我不确定这是否会按您的预期工作。
  • @TimBiegeleisen,因此,我想看到在分支 some 中完成的工作,但没有提交。
  • @ktretyak 您确实希望从提交 C2C4C5 中进行更改,而不是从合并 M3 中进行更改,不是吗?
  • @phd,是的,你是对的。

标签: git git-reset


【解决方案1】:

我喜欢挑选樱桃的方法,但另一种方法是:

git checkout some
git rebase --interactive --preserve-merges C2

...然后编辑显示的选项列表,将合并提交 M3 行前的 pick 更改为 drop。你最终会得到C5-&gt;C4-&gt;C2 作为some 上的一组提交,这些提交不在master 中。

【讨论】:

    【解决方案2】:

    首先,让我们注意提交是(完全)只读和(大部分)永久的。给定一个像这样的提交图片段:

      C2---M3---C4---C5  <-- some
     /    /
    C1---C3---C6---C7  <-- master
    

    无论reset-ing 我们做什么,这些相同的提交将继续存在,至少在一段时间内。如果我们添加一个保存名称(分支或标签名称)也指向提交 C5,那么无论我们对名称 some 做什么,我们仍然可以将提交命名为 C5C4、@987654328 @ 和 C2

    其次,记住每个提交都存储一个完整的、独立的快照。这包括合并提交M3。我们可以通过运行 git diff 将快照的内容与提交的父项的内容进行比较,将合并提交转换为一组更改——但是对于具有 两个 父项的合并提交,我们必须选择两个父母之一。

    第三,既然你提到了git reset --soft,请注意,除了提交之外,Git 为我们提供了一个 工作树,我们在其中进行实际工作(并且可以查看提交),还有一个 index——也称为 staging areacache——我们用来在每次提交之前构建它。如果我们运行:

    git checkout some
    

    Git 将从名称 some 当前指向的提交内容中填充索引和工作树,即 C5,并将我们的 HEAD 附加到名称 some。让我们在此时附加第二个名称tmp,使用git branch tmp

      C2---M3---C4---C5  <-- some (HEAD), tmp
     /    /
    C1---C3---C6---C7  <-- master
    

    此时运行git reset --soft &lt;hash-of-C1&gt; 将使名称some 指向提交C1,同时保持我们的索引和工作树不变。也就是说,索引和工作树内容将继续匹配C5

      C2---M3---C4---C5  <-- tmp
     /    /
    C1---C3---C6---C7  <-- master
     .
      ... <-------------- some (HEAD)
    

    如果我们现在进行新的提交,通过运行git commit,我们会得到一个新的提交C8,其内容与C5 的内容匹配。这是因为新的提交是根据索引的内容进行的,它与C5 的内容相匹配。 C8 的父级将是 C1,但是,给我们:

      C2---M3---C4---C5  <-- tmp
     /    /
    C1---C3---C6---C7  <-- master
     \
      C8  <-------------- some (HEAD)
    

    之后git diff some tmp 将完全没有区别。

    您在 cmets 中提到,您想要的,在索引中或者可能作为新提交 C8,是 content,可以通过挑选 C2C4C5 在提交 C1 之上。单独使用git reset 无法获得此信息。

    通过采摘构建

    最直接的方法是设置分支名称指向提交C1,同时设置索引和工作树以匹配C1

    git checkout -b new <hash-of-C1>
    

    然后使用git cherry-pick,可选择使用-n,如phd's answer,在我输入时输入。您也可以使用git reset --hard,而不是git reset --soft,移动@987654367 @ 指向C1,同时保留提交名称C5(如上图中使用tmp)。然后,您构建的新分支的 name,通过挑选三个所需的提交,将是 some

    通过还原构建

    最后,如果您愿意,您可以尝试通过 减法 过程构建您的新提交。这可能有点容易出错,因为它取决于合并 M3,1 的内容,但它的工作原理如下:

    • 我们知道C5 实际上是C1,加上C2-as-changeset,加上C1-vs-C3 作为changeset-via-merge,加上@987654378 @-as-changeset,加上C5-as-changeset。

    • 我们可以通过git diff-ing 直接计算C1-vs-C3

    • 更好:我们可以通过 git diffing C2M3 间接计算 C1-vs-C3 。这将处理某些重复情况,其中C1-vs-C3C1-vs-C2 具有相同 更改,因此它们不会被双重包含在@ 987654391@-vs-M3.

    • 我们可以(至少尝试)反向应用任何我们喜欢的补丁。也就是说,将提交变成变更集(通过与父项进行比较),我们可以撤消,而不是将这些更改复制到没有的提交中确实有它们的提交中的那些更改。执行此操作的命令是 git revert

    然后,假设我们像以前一样检查提交 some,以便我们只有初始设置:

      C2---M3---C4---C5  <-- some (HEAD)
     /    /
    C1---C3---C6---C7  <-- master
    

    现在我们运行git revert -m 1 &lt;hash-of-M3&gt;。这告诉 Git 比较 C2M3 以查看发生了什么变化。2 结果是一个新的提交 C8

      C2---M3---C4---C5---C8  <-- some (HEAD)
     /    /
    C1---C3---C6---C7  <-- master
    

    其中很可能具有您想要的 内容C1 作为快照加上 C2 作为变更集以获取 C2 作为内容,加上 M3C2 作为变更集获取 M3 作为内容(但最终 minus M3 vs C2 作为最后的变更集),依此类推。由于C8 un-does M3 做了什么,C8 应该有所需的内容。

    此时您可以,如果您愿意,git reset --soft &lt;hash-of-C1&gt;,让索引和工作树按照您想要的方式设置,然后运行 ​​git commit 以创建提交 C9

      C2---M3---C4---C5---C8
     /    /
    C1---C3---C6---C7  <-- master
     \
      C9  <-------------- some (HEAD)
    

    由于没有 name 可以找到它们,这里图表顶行的所有提交都变得不可见,并且在 30 天左右后,Git 在运行其垃圾收集器时真正将它们删除.


    1特别是,如果我们使用git revert &lt;hash-of-C3&gt;,我们可能会还原太多。这就是为什么我们在这里git revert -m 1 &lt;hash-of-M3&gt;

    2这假设M3 的第一个父级实际上是C2。在任何正常的提交增长过程中,都会出现这种情况,但值得仔细检查。

    【讨论】:

      【解决方案3】:

      因此,您希望从提交 C2C4C5 中进行更改,而不是从合并 M3 中进行更改。我会用一个新的分支来做到这一点:

      # Create a new branch started at C1
      git checkout -b some-new C1
      
      # Cherry-pick commits
      git cherry-pick C2 C4 C5
      
      # Delete the old branch and rename the new
      git branch -D some
      git branch -m some
      

      【讨论】:

        猜你喜欢
        • 2014-05-23
        • 2020-05-13
        • 1970-01-01
        • 1970-01-01
        • 2020-11-27
        • 1970-01-01
        • 2018-06-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多