假设我具有以下git历史记录:以提交A
开始的主分支,以提交feature-1
和{{1}从A
分支出来的B
分支},以及第二个功能分支C
,该分支基于提交feature-1
和C
的提交D
而构建。
E
现在假设提交master A
\
feature-1 B--C
\
feature-2 D--E
已经过测试,可以合并了,因此我们使用C
。
git switch master; git merge feature-1 --squash
master的历史记录很不错,只提交了master A------C'
\ /
feature-1 B--C
\
feature-2 D--E
和A
,但是如果我们现在想比较C'
和master
(例如{{1 }}),我们最终看到feature-2
中所有已合并的提交。
问题1:是否有一种简单的方法来压缩git log master..feature-2
的历史记录以匹配压缩后的合并?如果历史稍微复杂些,并且在feature-1
的分支点feature-2
之后有更多提交被压入母版,该怎么办?
问题2:假设重写历史记录很困难(或者只能用C
来繁琐;我在每个分支上的提交都超过了两次)有什么方法只能查看feature-1
中没有被压入母版中的提交?在github或bitbucket上为git rebase -i
执行一次pull请求时,有什么方法只能列出那些真正的新提交吗?
答案 0 :(得分:2)
现在假设提交
C
已经过测试,可以合并了,因此我们使用git switch master; git merge feature-1 --squash
。master A------C' \ / feature-1 B--C \ feature-2 D--E
这幅图不太正确:它应该阅读我在下面绘制的方式。请注意,我也将名称也移到了右边,原因很快就会变得更加清楚。我也将其称为壁球提交BC
,这是为了明确表明只有一次提交可以完成B-and-C的共同工作。
您绘制的是一个真正的合并(尽管您将合并提交称为C'
)。与matt said一样,“南瓜合并”根本不是合并。
A--BC <-- master
\
B--C <-- feature-1
\
D--E <-- feature-2
目前,几乎没有理由保留名称feature-1
。如果删除它,我们可以像这样重新绘制图形:
A--BC <-- master
\
B--C--D--E <-- feature-2
请注意,提交A-B-C-D-E
都在分支feature-2
上(无论我们是否删除名称feature-1
);提交BC
仅在master
上。
保留名称feature-1
的主要原因是它标识了提交C
,这很容易将提交D
和E
(无其他)复制到新的和改进的提交D'-E'
。
问题1:是否有一种简单的方法来压缩
feature-2
的历史记录以匹配压缩后的合并?
我不清楚您所说的“压榨历史”是什么意思。但是,运行以上git merge --squash
后,提交BC
中的快照将与(完全匹配)提交C
中的快照,因此运行:
git switch feature-2 && git rebase --onto master feature-1
(注意这里的--onto
1 )将告诉Git复制提交D
和E
(仅),并在提交{{1 }},像这样:
BC
现在可以安全删除名称 D'-E' <-- feature-2 (HEAD)
/
A--BC <-- master
\
B--C <-- feature-1
\
D--E [abandoned]
,因为我们不再需要记住提交feature-1
的哈希ID。如果我们停止绘制废弃的提交,那么最终结果是:
C
这可能就是您想要的。
1 通常,A--BC <-- master
\
D'-E' <-- feature-2
使用一个名称或提交哈希ID。然后:
git rebase
; git switch --detach
还原为在步骤4中刚刚移动的分支名称。如果不使用git switch
,则步骤1和2中的提交哈希ID 相同。当使用--onto
时,步骤1和2中的提交哈希ID是(或至少可以是) 。因此,使用--onto
,我们可以告诉Git:仅复制一些提交,而不是许多提交。
具体来说,如果没有--onto
,我们将复制所有可从 --onto
到达的提交,但 不能从(单个)到达)参数,副本将转到(单个)参数。使用HEAD
,我们可以说:可以将--onto
而不是我指定的限制器中的提交提交复制到我单独的HEAD
参数指定的位置。让我们说不要尝试复制--onto
和B
的情况。
另一方面,您也可以简单地运行:
C
如果您只想将D-E链球一次合并:
git switch master # if needed - you're probably already there
git merge --squash feature-2
此A--BC--DE <-- master (HEAD)
\
B--C <-- feature-1
\
D--E <-- feature-2
通常也会很顺利,因为与常规git merge --squash
一样,git merge
的开头是:
git merge --squash
)A
进行比较,因为BC
是HEAD
,它标识提交master
);和BC
,因为E
的名称提交feature-2
)来区分合并基础。第一个差异显示E
所做的是因为B+C
的快照匹配了BC
,而第二个差异显示了C
的做了,因为B+C+D+E
'快照是E
加B
加C
加D
的结果。因此,除非E
和/或D
特别是 un -做E
和/或B
做某事,否则两组更改很可能会自动合并。
(请注意,即使C
和/或D
撤消某些操作,此处的重新设置也总是很顺利。)
“不完全合并”和“真正合并”之间的区别仅限于最终提交:该南瓜只有一个父级(在这种情况下为E
)的提交,而真正合并与两个父母有约定。在这种情况下,真正的合并会给您BC
作为一个父级,而BC
作为另一个父级。如果您想使用E
壁球合并,则可能要重新设置B
的基础,然后C
首先提交。
如果历史稍微复杂一点,并且在特征1的分支点
BC
之后有更多提交被压入母版,该怎么办?
一如既往,诀窍是绘制实际图形。我们可以从这里开始:
C
在A <-- master
\
B--C--F--G <-- feature-1
\
D--E <-- feature-2
之后产生的内容:
git switch master && git merge --squash feature-1
现在适合使用:
A--BCFG <-- master
\
B--C--F--G <-- feature-1
\
D--E <-- feature-2
请注意,这与我们在较早情况下使用的命令相同。它表示(与上面的脚注1中的步骤比较):
列出从git switch feature-2 && git rebase --onto master feature-1
(在feature-2
之后的位置)可以到达的提交,但从git switch
不能到达。从feature-1
可以到达的提交是feature-2
,从A-B-C-D-E
可以到达的提交是feature-1
。从A-B-C-F-G
中减去A-B-C-F-G
将留下A-B-C-D-E
。
在D-E
上进入一个独立的HEAD,即,提交master
。
复制步骤1中列出的提交,即BCFG
和D
。
表示分支名称(E
)我们现在所在的位置(提交feature-2
)。
再次执行E'
的等效操作。
结果是:
git switch feature-2
在此之后可以安全删除名称 D'-E' <-- feature-2 (HEAD)
/
A--BCFG <-- master
\
B--C--F--G <-- feature-1
\
D--E [abandoned]
:我们不再需要通过提交feature-1
查找提交C
的简便方法。
问题2:假设重写历史记录很困难(或者只能用
G
来乏味;我在每个分支上的提交都超过了两次)
正如您在上面看到的,这不一定是正确的假设。变基的难度取决于您每次要复制的提交会遇到多少合并冲突,这取决于在上一次公共提交(上图中的git rebase -i
之后发生的情况)。还是:
...有什么方法可以仅查看
C
中没有被压入feature-2
中的提交?
master
对此具有简单的语法,只要您仍具有git log
的名称即可标识适当的提交,如上图所示即可。
feature-1
就是那样。此语法表示从git log feature-1..feature-2
开始并向后工作可到达的所有提交,减去从feature-2
开始并向后工作可到达的所有提交。请注意,这是同一组提交我们在上面的示例中使用feature-1
操作复制的内容。 2
在github或bitbucket上为
git rebase
执行拉取请求时,有什么方法只能列出那些真正的新提交吗?
否,因为这些系统没有等效的语法。但是,一旦您使用rebase复制所需的提交,并强制推动GitHub或Bitbucket存储库匹配,它们就会显示您想要的内容。
2 上面没有提到的是,feature-2 -> master
在默认情况下故意忽略了步骤1中的某些提交。在您的情况下,这里没有应该忽略的提交,因此这并不是很重要,但是值得一提:
git rebase
忽略所有 merge 提交。git rebase
还使用与git rebase
或git cherry
相同的计算,以从复制中消除其{{3 }}与上游提交集中的提交匹配。 (如果不详细介绍git log --cherry-pick
对称差异表示法的工作原理,很难定义此集合。)在您的情况下,这都不重要,因为在这里这种补丁ID匹配极不可能。对于上游人员故意使用A...B
将您提交的一项或多项提交复制到您要重新建立基础的分支的情况,这意味着更多。git cherry-pick
默认运行git rebase
来查找要忽略的提交,这会产生令人惊讶的结果。从历史上讲,rebase文档对于提及这些内容比较松懈,可能是因为它们并不经常出现。就您而言,它们不应该出现。最新的rebase文档得到了极大的改进。
答案 1 :(得分:0)
在简单的情况下,如果您只是在rebase
上feature-2
master
,那么您将只有非空的提交。
在更复杂的情况下,我建议执行以下操作:
git switch feature-2
git merge origin/master
git reset --soft origin/master
git commit -m 'feature 2'
这将导致一次提交,该提交将feature-2
上的所有更改有效地压缩到master
上