能否使用Git合并两个文件并忽略它们的共同祖先?

6
例如,我有以下文件:
// first part
function() {
    var timer = 1;
}

// second part
function() {
    var timer = 2;
}

// third part
function() {
    var timer = 3;
}

现在有两个不同的分支对其进行更改。我进行了更改:
在分支1中:
// first part
function() {
    var timer = "changed in branch1";
}

// second part
function() {
    var timer = 2;
}

// third part
function() {
    var timer = 3;
}

在branch2分支中:
// first part
function() {
    var timer = 1;
}

// second part
function() {
    var timer = "changed in branch2";
}

// third part
function() {
    var timer = 3;
}

使用三方合并,这些更改将会干净地合并,因为每个分支都修改了与另一个分支不同的代码块。然而,在合并时,我希望得到以下结果:

// first part
function() {
<<<<<<< branch1
    var timer = "changed in branch1";
=======
    var timer = 1;
>>>>>>> branch2
}

// second part
function() {
<<<<<<< branch1
    var timer = 2;
=======
    var timer = "changed in branch2";
>>>>>>> branch2
}

// third part
function() {
    var timer = 3;
}

有没有办法在git中实现这种合并?根据评论,我认为这种合并的步骤如下:
  1. 制作文件的差异
  2. 将不在差异中的块插入最终版本
  3. 使用冲突标记标记不同的块

只是好奇,你为什么想要那样做? - Anshul Goyal
@mu無,主要是出于好奇心:)。此外,我们有一个团队成员,有时会在我处理其他功能时更改我的master中的featureA代码,而我不会触碰featureA代码,因此合并后我没有冲突。但是,未来的某个时候,我发现featureA已经损坏了。因此,也许我想合并一些没有共同祖先的文件,以查看master中的featureA代码是否与我在不同分支中版本中的相同代码不同。 - Max Koretskyi
如果原因是其他开发人员的更改,我认为最好通过适当的代码审查流程来处理。话虽如此,你可以像下面的答案建议的那样随时检查差异 :) - Anshul Goyal
2
@mu無,進行適當的代碼審查或解雇該開發人員確實是應該採取的措施,但我只是告訴你是什麼情況讓我考慮這種合併。 - Max Koretskyi
3个回答

1
如果你只想查看你的代码与某个提交之间的差异,只需执行以下操作:
git diff HEAD..<sha-commit2>

或者,如果您想将当前提交与另一个分支的最新版本进行比较:

git diff HEAD..other_branch

编辑 如@Maximus在评论中所问:如果您想查看某人所做的更改

  • 在主分支上
  • 特定文件中
  • 自您分支以来

因此,我们需要先找到共同的祖先:(我假设您在您的分支上;因此我使用HEAD。可以替换为您的分支名称)

git merge-base HEAD master

然后你可以在特定文件中看到自那个共同祖先以来的更改(使用git log -pgit diff;取决于你喜欢的输出):

git log -p <sha-common-ancestor>..master -- <the files and dirs you want>
git diff <sha-common-ancestor>..master -- <the files and dirs you want>

不,我确实想要合并。我希望Git为我执行git diff任务,合并相同的代码并将冲突放入文件中。请查看我的评论以了解原因。 - Max Koretskyi
我理解您的问题;您想在合并之前检查另一个开发人员的工作;因此,我建议您在合并之前先检查差异。另一种选择是检查他的分支(如果有的话);看看他在做什么... - Chris Maes
是的,但这是代码审核过程,我在谈论的是合并。换句话说,我希望在特定文件中的代码自从我分支以来有所更改时得到通知,而不是每次手动检查它。 - Max Koretskyi
@Maximus 我编辑了我的回答,希望这更好地回答了你的问题。这使你可以轻松地创建一个bash oneliner或脚本(甚至是git别名)。 - Chris Maes
感谢您的编辑,虽然还没有回答我的问题,但可能会有所帮助! - Max Koretskyi

1
使用git merge--no-commit,然后在提交合并结果之前,在事实上进行修复。这是处理一次性情况最简单的方法(远远超过其他方法)。
如果您需要一种可重复自动执行的方法,可以定义一个自定义合并驱动程序(请参见,例如this nabble thread)。但是,您必须制定一些系统规则来组合明显非冲突的更改。

“--no-commit” 只是跳过合并后的提交,但合并仍然使用“3-way merge”策略,因此我问题中的示例将干净地合并。 - Max Koretskyi
2
没错。然后你编辑文件并使用 git add 命令添加结果,以覆盖 Git 生成的合并结果,然后再提交。哦,我明白了,你现在不关心 结果,而是想要 冲突标记。据我所知,没有内置的工具可以做到这一点。 - torek
是的,“冲突标记”是合并时忽略共同祖先的副产品,这种合并会执行以下操作:对文件进行差异比较,在最终版本中插入未在差异中的块,并使用冲突标记标记不同的块。 - Max Koretskyi

1
Git提供了管道命令git merge-file,允许您在没有基础的情况下合并两个文件,但是没有简单的方式来调用它。如果您正在将branch合并到master并想要进行一次无基础合并某个文件foo.txt
git show master:foo.txt > /tmp/master.foo.txt
git show branch:foo.txt > /tmp/branch.foo.txt
echo -n > /tmp/empty.txt
git merge-file -p -L master -L base -L branch /tmp/master.foo.txt /tmp/empty.txt /tmp/branch.foo.txt > foo.txt

在上面的例子中,这将产生:


// first part
function() {
<<<<<<< master
    var timer = 1;
=======
    var timer = "changed in branch1";
>>>>>>> branch
}

// second part
function() {
<<<<<<< master
    var timer = "changed in branch2";
=======
    var timer = 2;
>>>>>>> branch
}

// third part
function() {
    var timer = 3;
}

(编写脚本留给读者自行练习。)

谢谢,它会按照那里描述的方式合并我的问题文件吗? - Max Koretskyi
@Maximus 是的,就像你提出的那样。我更新了我的答案以反映这一点。 - Edward Thomson
我明白了,谢谢,我稍后会尝试并有问题再回来问您 :) - Max Koretskyi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接