首先,我知道--squash
,但这不能单独解决我的问题。
我有两个分支A
和B
,其中A
需要定期合并到B
中。出于所有意图和目的,这两个分支代表了不同的项目,不同的团队负责这些项目,但是A
包含的通用代码类似于B
中的库。现在,忽略了这是一个简化的示例,答案并不像“将公共库代码提取到新的分支/存储库C
那样简单,我如何定期将A
合并到{{1 }}并没有牵涉到B
的全部历史记录?
我们不想要历史记录的原因是因为它们实际上是两个单独的项目,A
上90%以上的更改对A
来说都无关紧要(从开发人员了解了什么从历史的角度来看)。更复杂的是,我们仍然希望支持一种功能分支方法,即开发人员应该能够从B
创建一个功能分支,然后从A
创建另一个功能分支,并最终合并从B
的功能分支更改为A
的功能分支。
我们考虑过的选项:
一切正常,除了我们在B
中拥有A
的全部历史。
Squash摆脱了历史,但是当我们继续从B
合并到A
时,除非我们手动跟踪已合并的提交,否则将陷入冲突。这对于功能分支工作流来说是一个问题,因为每个开发人员都必须仔细地进行合并,以排除之前(或选择摘录)之前被压缩的所有内容。
据我们所知,不很好地支持分支。当开发人员创建两个功能分支时,他们将必须以某种方式更新子树以指向B
的功能分支,而不是A
本身。合并功能分支以掌握功能时,开发人员将不得不再次还原/更正此子树指针。
与子树相同的问题,但还添加了许多其他问题。
关于如何实现主要目标的任何建议(频繁的合并而没有完整的历史记录)?
答案 0 :(得分:1)
在您施加的限制内,没有一个好的解决方案。有一个解决方案,我将在下面概述。但首先我想清楚-我不认为这是一个好的解决方案,我认为您可能最终会遇到问题。[1]
但是如果出于某种原因您仍然必须尝试:
您将必须创建一种桥分支。该分支将包含A
的简要历史记录。您将仅使用B
的有用信息来定期更新它;然后将其合并到B
中。
因为您说的是简单合并,但合并会带来太多的历史记录,因此我认为不需要对内容进行任何转换-因此,您所需要的只是稀疏的历史记录。这意味着尽管B
中的历史记录将减少为更少的提交,但所有更改仍在那些更少的提交中。如果您甚至需要避免这种情况,我想在评论中让我知道...但是解决方案变得更加复杂。
同样因为合并将起作用,所以我假设存在分支A
和B
的共同祖先,我将其称为O
。
... O -- x -- x -- x -- P <--(A)
\
y -- y -- y <--(B)
B
与O
是“最新的”,但与A
之后的任何更改都不相同。您希望对P
中的B
进行更改,但不想看到x
历史中的B
提交。首先,我们将在O
处创建“ bridge branch”。我们需要一个解析为O
的表达式-它可以是O
的提交ID,但是在本示例中,我们可以使用A~4
(A
指的是{{1} },因此我们希望P
的第4个父级。
A
现在的问题是如何重复地更新git checkout A~4
git checkout -b bridge
。如您所述,您第一次可以做
bridge
但是这是不可重复的,因为您第二次尝试使用git不会知道正确的合并基础。同样,您第一次可以进行交互式git merge --squash
并使用TODO列表将rebase
的所有提交放在一起,但是要重复一次,您必须跟踪{{1} }已经被复制到squash
,并且容易出错。
但是bridge分支为您提供的保证是-A
的唯一更改来源是bridge
的合并,因此在每个“合并”中,可以假设所有更改都是“他们的”。换句话说,我们总是只想将bridge
的特定状态(可能是当前状态)提交到A
上。
有几种方法可以做到这一点。从
开始bridge
一种瓷器的方法是
A
现在有
x -- x -- x -- P <--(A)
/
... O <--(bridge)
\
y -- y -- y <--(B)
所以你可以
git checkout --detach A
git reset --soft bridge
git checkout bridge
git commit -m "Update from A through P"
获得
x -- x -- x -- P <--(A)
/
... O -- P' <--(bridge)
\
y -- y -- y <--(B)
现在,您已经最小化了git checkout B
git merge bridge
中将显示 x -- x -- x -- P <--(A)
/
... O ----------- P' <--(bridge)
\ \
y -- y -- y -- M1 <--(B)
的历史记录的数量。您仍然可以看到所有的更改,当然,我们再次修改了历史记录,但仍合并了所有内容更改。
现在发生了更多的工作,您进入了一个新状态,在A
的提交B
中,公用代码已再次更新。
A
再次注意,Q
不会从任何其他来源进行更改;它仍然与 x -- x -- x -- P -- x -- x -- Q <--(A)
/
... O ----------- P' <--(bridge)
\ \
y -- y -- y -- M1 -- y -- y -- y <--(B)
匹配,因此您仍然只想更新它以匹配bridge
。所以你重复这个过程
P
尽管此过程中没有任何“知道” Q
在git checkout --detach A
git reset --soft bridge
git checkout bridge
git commit -m "Update from A through Q"
git checkout B
git merge branch
的情况,但我们仍然以
branch
您可以根据需要重复多次。
[1]-我假设仅在P
命令上使用诸如 x -- x -- x -- P -- x -- x -- Q <--(A)
/
... O ----------- P' ----------------- Q' <--(bridge)
\ \ \
y -- y -- y -- M1 -- y -- y -- y -- M2 <--(B)
之类的选项是不合适的解决方案,因为这也可能会切断{{ 1}}您要查看的项目。但是您可能要考虑从这个角度看问题是否可以简化任何事情……
而且,尽管您已经排除了它,但是最好的解决方案可能是将通用代码提取到库中,并使其成为两个项目的依赖项(在此过程中,我会将项目移到单独的位置回购而不是单独的分支)。那也许“说起来容易做起来难”,但是如果这样的话,那可能就指出了一个体系结构问题,如果不解决,它将导致您头疼。