我有两个分支,最近有一个共同的父母。 让我们称它们为feature-br-A和feature-br-B。
两个分支机构的开发工作仍在继续。 feature-br-B主要有bug修复。 feature-br-A有一些错误修复和至少一个新功能。
现在是时候将feature-br-B中的错误修复转移到feature-br-A中。
git checkout feature-br-A
git merge feature-br-B
<< conflicts >>
少数文件冲突简单易懂。但是有一大堆文件仅添加到标记为删除的feature-br-A中。还有一些文件只添加到feature-br-A中,这些文件存在冲突,标记为“被他们删除”。
如何将feature-br-B上所做的更改合并到feature-br-A中,而不会丢失feature-br-A上已经进行的所有更改?
我试过
git merge -Xours --no-commit feature-br-B
但是这产生了同样的问题。
我的另一个问题是,如果添加文件发生了这种情况,是否还会对其他文件进行更改,以便为feature-br-A添加功能?
我想我可以从合并中删除删除,但是它应该删除新文件似乎不正确。
答案 0 :(得分:2)
git merge
首先在当前(或&#34;本地&#34;或--ours
)提交与您的目标(或&#34)之间找到合并基础 ;远程&#34;或--theirs
或&#34;其他&#34;)提交。在这种情况下,您的本地提交是feature-br-A
上最常见的提交,而其他&#34;其他&#34; commit是feature-br-B
上提交最多的提交。
我在这里没有足够的信息来识别合并基础,但是你(和你的Git)这样做了。这是两个分支机构加入的承诺。#34;。在某些情况下,可能存在多个合并库提交,但可能只有一个。如果我们绘制你的两个分支的图表 - 注意git log --graph --decorate feature-br-A feature-br-B
也将绘制这个,以一种不同的形式 1 - 我们会看到类似这样的东西:
...--o--*--o--o--o--o <-- HEAD -> feature-br-A
\
o--o--o--o <-- feature-br-B
请注意,两个分支名称指向要合并的两个提交。我用*
标记的提交是图表&#34;加入&#34 ;;这是合并基础。
现在已经确定了合并基础提交,git merge
通过运行两个git diff
命令来完成它的工作。简化了一下,这些是:
git diff base feature-br-A
git diff base feature-br-B
这两个差异给Git - 你 - 所有执行正常合并所需的信息(当然,添加策略或策略选项会改变合并)。他们告诉你你做了什么 - 你从 base 改为feature-br-A
的提示 - 以及他们做了什么:什么& #34;他们&#34;,无论他们是谁,都从 base 更改为feature-br-B
的提示。
只要Git本身无法协调,就会发生冲突&#34;你做了什么&#34;用&#34;他们做了什么&#34;。
您提到了一些常规冲突,然后:
少数文件冲突简单易懂。但是有一大堆文件仅添加到标记为删除的feature-br-A中。并且还有一些文件只添加到feature-br-A中,这些文件存在冲突,标记为&#39;已删除。
文件已添加到feature-br-A
(与 base 相比)不会被标记为删除。那些是你做过的事情的一部分&#34;。如果它们也添加到feature-br-B
(与 base 相比),它们只会发生冲突。
feature-br-B
中的文件已删除(与 base 相比)也没有冲突,只有一个例外。假设,对于路径 P ,您已更改 feature-br-A
中的内容,以便比较 base 和feature-br-A
,文件 P 已修改。进一步假设在比较 base 和feature-br-B
时,Git将 P 视为已删除。它无法将您的更改(&#34;修改某些行&#34;)与他们的结合(&#34;删除整个文件&#34;)。在这种情况下,它会让您修改已修改的文件,但是在&#34;需要合并&#34;状态。
为了完成合并工作,Git使用了index / staging-area的一个特殊功能。通常,索引每个文件(路径)名称只包含一个条目:文件的状态,就像它在 next 提交中一样,一旦你创建它。
也就是说,git commit
首先将暂存区域转换为树 - 更准确地说,是一系列树,每个目录一个树,顶部有一个顶层Git树对象树 - 播放的任何文件。然后Git创建一个提交对象,引用该树对象并更新分支指针。这就完成了提交的过程,也就是git commit
如此快的原因:由于所有文件都已经在暂存区域,所以很少有工作要做。
然而,在合并期间,Git以不同方式处理暂存区域。索引现在每个路径包含三个条目 - 或者实际上,最多三个。这些条目编号为:stage slot 1是合并库中的文件版本,slot 2是&#34; local&#34;或--ours
版本,插槽3是另一个版本或--theirs
版本。如果在一个或两个分支提示中创建了文件,则插槽1为空。如果在一个分支提示中删除了文件,则插槽2或3中的一个为空。 (如果在两个提示中都删除了该文件,Git会为您解决所有问题,并且不会留下冲突的条目。)
要解决问题,请根据需要编辑工作树文件后git add
(或git rm
)路径。这会清空插槽1,2和3,将文件写入插槽0,这是正常的,不冲突的文件存在的地方。一旦有没有插槽1到3条目,合并就完成了,您可以提交暂存区域。
Git试图猜测重命名了哪些文件(如果有的话)。它在执行两个git diff
步骤时执行此操作。如果你自己手动运行git diff
,你可能需要告诉Git使用相同的&#34;找到重命名&#34;它用于合并的设置。默认情况下,Git使用等效的git diff -M
(50%相似度)。您可以通过各种选项和git config
值控制合并重命名阈值。大多数情况下,默认设置都很好,您可以简单地将它们单独留下。
值得记住的是,Git正在进行这种重命名检测,无论您是否尝试调整设置。这很重要,因为它可以显示在您的冲突中。例如,假设Git决定在{em> base 到lib/foo.py
的更改集中将misc/zap.py
重命名为feature-br-A
,但不是< / em>在 base 的更改集中重命名为feature-br-B
。在这种情况下,Git将尝试通过保持重命名来结合这两个更改,并且还应用&#34;他们的&#34;将其在{em> base 中的lib/foo.py
和lib/foo.py
中的feature-br-B
之间看到的更改为misc/zap.py
中名称为feature-br-A
的文件。< / p>
如果Git是正确的 - 如果这个文件真的被重命名为这样 - 这正是你想要的。但如果Git错了,它就会错误合并。您需要手动更正它,或者使用不同的重命名检测值重试合并。
这里的一般规则是Git保留当前(本地)提交中所做的所有重命名更改 - 在这种情况下为feature-br-A
的提示 - 并设置索引的阶段插槽以便他们的内容反映了文件的内容,因为(Git认为)它们是在 base 和feature-br-B
(其他)提交中命名的。 / p>
如果自动合并失败,您必须手动修复。使用--ours
可能有所帮助。将--theirs
设置为git checkout
也可能有所帮助(我发现它非常有用)。请注意,只要只有一个合并基础提交(搜索&#34;虚拟合并基础&#34;对于更复杂的情况),您可以简化两个git diff
命令。在这种情况下,您当前的提交是merge.conflictstyle
并且您正在合并diff3
,因此这两个命令将为您提供两个差异:
git diff
请注意,此处有三个点。在这种情况下,feature-br-A
找到合并基础提交(或者,如果有多个合并库,则选择一个或多个随机)并将其与右侧上指定的提交进行比较。因此,第一个feature-br-B
命令找到&#34;我们的&#34;变化,第二个发现&#34;他们&#34;。
在任何情况下,与任何合并一样,您必须检查合并的结果。对于几乎没有变化的简单合并,快速浏览(&#34;看起来正确&#34;)和/或传递您拥有的任何测试套件就足够了。对于复杂的合并,测试套件是非常好的主意,对合并结果进行更仔细的眼球检查也不是一个坏主意。
1 这与任何其他git diff feature-br-B...feature-br-A # "our" changes
git diff feature-br-A...feature-br-B # "their" changes
一样,但它添加了图形信息。要获得更简洁的绘图,请添加git diff
。要获得只是两个分支上的提交,不包括两个分支上的提交,请使用三点语法。要将合并基础和其他边界提交添加到此图形,请添加git diff
。因此,更完整但更短的版本是:
git log
请注意,此语法中的分支名称之间存在三个 - 不是两个,而不是任何其他数字,但正是三个 - 点。
答案 1 :(得分:0)
问题(1)如何将feature-br-B上所做的更改合并到feature-br-A中,而不会丢失feature-br-A上已经进行的所有更改?
导致该问题的问题是,在某些时候,feature-br-A中的一些原始提交曾经合并到feature-br-B中,然后被后续提交删除。 git正在尽职尽责地复制删除。目前我不清楚,如果恢复原始合并而不是文件删除,那git会做同样的事情,但我怀疑它仍然是这样。
错误似乎阻止了从feature-br-B自动合并到feature-br-A中。我必须解决的唯一建议是识别在feature-br-B上进行的提交,并使用git cherry-pick将它们移动到feature-br-A中。
我计划进行更多测试,因为我可以从合并中解释已删除的文件。