注意:抱歉标题。我不确定如何简洁地说出我的挑战,所以将这个问题标记为重复(准确)将非常有帮助。
以下是相关行动的时间表,它将构成我的问题的基础:
问题:功能B的PR显示来自功能A的所有先前(未撤销)提交。
我如何,最好不要手动删除所有功能A提交或挑选功能B提交,在主服务器上重新设置功能B并在PR中仅显示来自A..B的提交?
答案 0 :(得分:1)
你必须挑选,即使你不想。 可以使用git rebase --onto
以高度自动化且经常但并非总是轻松无痛的方式进行挑选。
就我所知,GitHub本身(这不是那么远),在这里完全没用。但是,你可以在shell级别的Git中做你需要做的事。
简要背景回顾:当你在Git中构建一个分支时,你真正在做的是添加提交,通常一次一个。 Git的基本单位和raison d'être是提交。每个提交都由哈希ID (如95ec6b1b3393eb6e26da40c565520a8db9796e9f
唯一标识。 No two different Git objects ever have the same hash ID.每个提交几乎都是一个独立的实体,包含源代码的完整快照。几乎""部分是因为大多数提交包含一个之前提交的哈希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
,但C
的父为B
,而不是({在此图中仍然是)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)
我只是遇到了同样的问题。
这是我成功处理的方式:
master
重置为“功能B” PR的基本分支 => GitHub警告与{{1 }}(如果尝试使用master
或$ git merge master
,也会得到此信息)$ git rebase master
:feature_b
=>没有更多冲突。 PR具有与步骤1结束时相同的差异,并且可以将其合并到$ git checkout feature_b
$ git merge -s ours master
$ git push origin feature_b
中。 ?