从以前的分支制作的分支的PR被压扁并合并显示前一个分支的提交

时间:2017-12-22 15:01:57

标签: git github

注意:抱歉标题。我不确定如何简洁地说出我的挑战,所以将这个问题标记为重复(准确)将非常有帮助。

以下是相关行动的时间表,它将构成我的问题的基础:

  1. 为功能A打开PR以掌握
  2. 功能B从功能A分支, 工作继续。
  3. 功能A被压扁并合并为主。
  4. 为功能B打开PR以掌握
  5. 问题:功能B的PR显示来自功能A的所有先前(未撤销)提交。

    我如何,最好不要手动删除所有功能A提交或挑选功能B提交,在主服务器上重新设置功能B并在PR中仅显示来自A..B的提交?

2 个答案:

答案 0 :(得分:1)

TL; DR

必须挑选,即使你不想。 可以使用git rebase --onto以高度自动化且经常但并非总是轻松无痛的方式进行挑选。

描述

就我所知,GitHub本身(这不是那么远),在这里完全没用。但是,你可以在shell级别的Git中做你需要做的事。

简要背景回顾:当你在Git中构建一个分支时,你真正在做的是添加提交,通常一次一个。 Git的基本单位和raison d'être是提交。每个提交都由哈希ID (如95ec6b1b3393eb6e26da40c565520a8db9796e9f唯一标识。 No two different Git objects ever have the same hash ID.每个提交几乎都是一个独立的实体,包含源代码的完整快照。几乎&#34;&#34;部分是因为大多数提交包含一个之前提交的哈希ID,作为其metadata的一部分,我们将其称为提交的承诺。像feature-A这样的分支名称包含一次提交的哈希ID,Git会调用该分支的 tip 提交。< / p>

当您git checkout feature-A,进行编辑,git add文件以及git commit结果时,您可以创建新的提交。新提交的 提示的提交,您有git checkout - ed。它的快照是原始提交中的所有文件,除了git add用您编辑的新内容覆盖的文件。作为一个全新的提交,它获取一个新的,唯一的哈希ID,然后Git将新ID存储到分支名称中,这样您刚刚提交的新提交现在是feature-A的提示。

问题

到目前为止,这并不是非常有趣,但我们应该注意这些提交是如何在先前提交的基础上一次一个地链接在一起的:

          1   <-- feature-A (HEAD)
         /
...--o--o   <-- master

成为:

          1--2   <-- feature-A (HEAD)
         /
...--o--o   <-- master

最终成为:

          1--2--3--4--5   <-- feature-A (HEAD)
         /
...--o--o   <-- master

然后您提出了拉取请求:&#34;请获取这些新提交1-2-3-4-5并执行某些操作以合并它们。&#34;谁是你的上游最终确实获得了这些提交并将它们合并,但是 - 这就是问题 - 他们这样做是使用GitHub&#34;壁球和合并&#34;功能按钮,内部运行git merge --squash根本不包含这些提交

相反,git merge --squash做的是使用Git的合并机制进行&#34;合并为动词&#34;组合变更的过程,但随后进行全新的提交。在他们的上游,他们可能已经添加了一些其他新的提交,所以当他们提交你的提交时1-2-3-4-5他们有:

          1--2--3--4--5   [imported - no name]
         /
...--o--*--A--B   <-- master

他们让他们的Git(和GitHub)将从提交*(合并基础)到B的更改,即他们所做的更改,以及来自*5,即所做的事情,并从结果中提交新的C因为这是--squash操作,所以新提交不记录其第二个父,使图形看起来像这样:

          1--2--3--4--5
         /
...--o--*--A--B---------C   <-- master

当你希望它看起来像这样:

          1--2--3--4--5
         /             \
...--o--*--A--B---------C   <-- master

但它并没有额外的联系,所以现在你必须处理这个问题。

与此同时,你做了更多提交

您继续在自己的存储库中创建了一个feature-B分支:

          1--2--3--4--5   <-- feature-A, feature-B (HEAD)
         /
...--o--o   <-- master

你现在做了一些提交:

                        6  <-- feature-B (HEAD)
                       /
          1--2--3--4--5   <-- feature-A
         /
...--o--o   <-- master

最终导致:

                        6--7--8  <-- feature-B (HEAD)
                       /
          1--2--3--4--5   <-- feature-A
         /
...--o--o   <-- master

在某些时候,您甚至可能从上游(他们的Git存储库)获得了提交A-B-C。如果你还没有这样做,你现在应该这样做:

                        6--7--8  <-- feature-B (HEAD)
                       /
          1--2--3--4--5   <-- feature-A
         /
...--o--o   <-- master
         \
          A--B--C   <-- upstream/master

请注意,他们的提交C大致相当于添加提交1-2-3-4-5,但CB ,而不是({在此图中仍然是)master的提示。

您现在要做的是创建提交链6-7-8副本,除了您希望基础这些副本在commit {{ 1}},不提交C。也就是说,您想要的结果如下所示:

5

Git命令可以复制提交,并且在此过程中使副本具有新的 base ,为 6--7--8 [old feature-B, to be abandoned] / 1--2--3--4--5 <-- feature-A / ...--o--o <-- master \ A--B--C <-- upstream/master \ C6-C7-C8 <-- feature-B 。但是,如果你只是运行:

git rebase

Git将选择复制可从名称git checkout feature-B && git rebase upstream/master 访问但不能从名称feature-B访问的提交。这里的单词 reachable 意味着如果我们从提示开始,并按照Git的方式向后工作,我们会遇到哪些提交?我们将以提交upstream/master开头,然后到达(通过其父哈希)提交8,然后提交7,依此类推到左侧链。最终,我们会到达您6的提示提交,并继续向左移动。但是,如果我们从master开始并向后工作,我们就会到达您upstream/master的提示提交并继续向左 - 所以这些提交是不是已复制。这样就可以复制提交master

同样,那是问题:这里有太多提交。我们希望之前停止提交1-2-3-4-5-6-7-8,以便我们仅复制 5链。这是我们使用6-7-8而不仅仅是git rebase --onto的地方。

使用git rebase

--onto完成工作时,它必须选择两个的东西,而不只是一个:

  • 我们应该复制哪些提交?更准确地说,哪些提交不应该我们复制?我们将一些提交复制到当前提交,但限制是什么? 我们复制了哪些内容?
  • 我们应该把副本放在哪里?

通常我们只是说git rebase,它从一个名称中找出这两个。副本位于命名提交之后,我们复制的提交是我们无法从命名提交中获取的提交。

使用git rebase upstream/master,我们明确告诉Git:git rebase --onto upstream/master提示后放置副本。这会留下另一个参数来指定限制: Don& #39; t copy。我们想告诉Git:不要复制提交upstream/master或更早。所以我们需要找到commit {的哈希ID {1}},或者用于查找提交5的内容。

分支名称5指向提交5。看看我们上面绘制的图表:它就在那里!或者,运行feature/A并查看Git将绘制的图表。是否有一个提交的名称结束了Git不应该复制的链?如果是这样,您可以使用该名称。如果没有,您只需输入原始哈希ID即可。

在我们的例子中,只要没有名称改变了他们所指向的提交,我们就可以运行:

5

这告诉Git签出(进入提示提交,并记录名称)git log --all --decorate --online --graph;然后,在当前提交结束时,复制一些提交,将提交后的副本放到git checkout feature-B git rebase --onto upstream/master feature-A 个点。副本以当前提交结束,并以删除提交以feature-B结尾后剩下的内容开头。

那当然是提交upstream/master。所以Git将feature-A,使6-7-8直接指向(没有分支名称)提交:

git checkout --detach upstream/master

然后Git将复制提交HEAD,就像在其哈希ID上执行 6--7--8 <-- feature-B / 1--2--3--4--5 <-- feature-A / ...--o--o <-- master \ A--B--C <-- upstream/master, HEAD 一样:

6

如果情况顺利,Git会挑选提交git cherry-pick

                        6--7--8  <-- feature-B
                       /
          1--2--3--4--5   <-- feature-A
         /
...--o--o   <-- master
         \
          A--B--C   <-- upstream/master
                 \
                  C6   <-- HEAD

然后重复7成为 6--7--8 <-- feature-B / 1--2--3--4--5 <-- feature-A / ...--o--o <-- master \ A--B--C <-- upstream/master \ C6-C7 <-- HEAD ;最后,Git会将旧链8上的标签C8撕下来并粘贴到新副本feature-B的末尾,而不是:

6-7-8

标签C6-C7-C8指向 6--7--8 [abandoned] / 1--2--3--4--5 <-- feature-A / ...--o--o <-- master \ A--B--C <-- upstream/master \ C6-C7-C8 <-- feature-B (HEAD) ,Git会将feature-B重新附加到该标签,现在已完成rebase,您可以提出一个请求上游人员将提交C8合并到他们的存储库中。

答案 1 :(得分:0)

我只是遇到了同样的问题。

这是我成功处理的方式:

  1. 在合并“功能A” PR之前,我将该PR的分支设置为“功能B” PR的基本分支,以从中隐藏“功能A”的提交新的PR,并为我的队友提供较小的差异。
  2. 合并“功能A” PR之后,我将master重置为“功能B” PR的基本分支 => GitHub警告与{{1 }}(如果尝试使用master$ git merge master,也会得到此信息)
  3. 要在保留“功能B”的更改的同时更新分支,我运行以下命令–假设您PR的分支称为$ git rebase master
feature_b

=>没有更多冲突。 PR具有与步骤1结束时相同的差异,并且可以将其合并到$ git checkout feature_b $ git merge -s ours master $ git push origin feature_b 中。 ?