git merge而不会丢失merge-to branch上的新文件

时间:2016-05-31 22:47:55

标签: git git-merge

我有两个分支,最近有一个共同的父母。 让我们称它们为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添加功能?

我想我可以从合并中删除删除,但是它应该删除新文件似乎不正确。

2 个答案:

答案 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.pylib/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中。

我计划进行更多测试,因为我可以从合并中解释已删除的文件。