0

我想通过接受所有远程(他们的)修改来进行拉动,而不需要任何手动解决冲突。但是,如果没有自动解决方案,我仍然会遇到冲突:

$ git merge -s recursive -X theirs local/master

CONFLICT (rename/delete): rcS.d/S08kmod deleted in HEAD and renamed in local/master. Version local/master of rcS.d/S08kmod left in tree.
Auto-merging php5/cli/conf.d/20-xdebug.ini
CONFLICT (add/add): Merge conflict in php5/cli/conf.d/20-xdebug.ini
Auto-merging apt/sources.list
CONFLICT (rename/rename): Rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf.conf" in branch "HEAD" rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf" in "local/master"

使用拉:

$ git pull local master
From ssh://192.168.1.101/etc
 * branch            master     -> FETCH_HEAD
warning: Cannot merge binary files: console-setup/cached_UTF-8_del.kmap.gz (HEAD vs. ada82813d27e5bef846ee086d07a87a82cfbb020)
CONFLICT (rename/delete): rcS.d/S08kmod deleted in HEAD and renamed in ada82813d27e5bef846ee086d07a87a82cfbb020. Version ada82813d27e5bef846ee086d07a87a82cfbb020 of rcS.d/S08kmod left in tree.
CONFLICT (add/add): Merge conflict in php5/cli/conf.d/20-xdebug.ini
CONFLICT (rename/rename): Rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf.conf" in branch "HEAD" rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf" in "ada82813d27e5bef846ee086d07a87a82cfbb020"

我也试过:

git merge --allow-unrelated-histories --strategy-option theirs local/master

但同样的冲突。

在第一个示例中使用 git v2.8.1。在第二个示例之前升级到 GIT v2.9.2。

我的用例: 我使用 GIT(更准确地说是使用 ETCKEEPER)跟踪 /etc 中的 Debian 升级更改。现在升级完成一些更改后,我愿意接受 Debian 所做的所有更改。当然,我相信 Debian 升级所做的更改,所以我想覆盖(合并)所有所做的更改,而不需要任何交互。

知道如何自动解决他们的修改冲突吗?

4

1 回答 1

5

你期望的-X theirs比 Git 所能提供的更多。

首先请记住,git merge使用通常的(递归)策略:

  • 找到合并基地;1
  • 区分合并基础与当前提示提交以获得“我们的”更改;和
  • 将合并基础与您命名的提交(通常是其他分支的尖端,但您可以命名任何提交)进行比较,以获取“他们的”更改。

这两个差异有一系列差异大块显示“我们做了什么”和“他们做了什么”,Git 现在将尝试将它们组合起来,以便我们获得每个更改的一个副本。这意味着如果我们在某个文件的第 49 行修正了一个单词的拼写,而他们没有,我们得到了我们的修正。如果他们修正了拼写,而我们没有,我们会得到他们的修正。如果我们都做了相同的拼写修复,我们得到一次修复,而不是两次,尽管“修复拼写”表示为:

      “首先,删除一个旧行。然后,插入一个新的、不同的行。”

并且“进行每个更改”的过于幼稚的应用程序会尝试两次删除一行,和/或插入新行的两个副本。Git(或任何体面的版本控制系统的合并)注意到这两个更改是相同的,并且只保留一份副本。

但是,如果两个不同 diff 中的两个 diff hunk 对同一原始源区域进行不同的更改,Git 通常只会声明合并冲突。它继续做它可以做的任何事情,但它会记住冲突,并在合并结束时停止,使冲突出现在工作树(以熟悉的<<<<<<< ... >>>>>>>形式)和索引中。

也称为“暂存区”或“缓存”,索引通常每个工作树文件有一个条目,2但在冲突合并期间,每个此类文件最多有三个条目:一个来自合并基地,一个来自“我们的”,一个来自“他们的”。“正常”(无冲突)条目进入“暂存槽零”,但这次该槽不用于该文件。相反,文件的合并基础版本进入暂存槽 1,其他两个版本位于槽 2 和 3(我们可以使用--oursand--theirs来获取它们,而不是记住这些槽号,但它们记录在gitrevisions如果您想随时查找它们)。我们必须解决冲突——通常,只需编辑工作树中的文件——然后告诉 Git 将索引中“未合并”插槽中的三个副本替换为正常的单个副本,“准备进入下一个提交”阶段零插槽。


1这假设有一个单一的基于合并的提交。如果有多个合并库,则操作取决于策略。默认的“递归”策略查找所有合并基,并将它们合并以生成单个“虚拟合并基”。“解决”策略只是(显然)随机选择一个合并基础。“章鱼”策略声明合并失败。

2更准确地说,每个跟踪的文件都有一个条目,对于HEAD提交中但由于git rm. 真正未跟踪的文件根本没有索引暂存槽。


-X ours-X theirs

意思-X是:在这种特殊情况下声明冲突(冲突的差异块),只需采用我们的更改(-X ours)或它们的更改(-X theirs),丢弃其他差异块。

一个简单的例子是我们将第一个单词的拼写固定在一行,而他们将第五个单词的拼写固定在同一行。这里-X ours将保留我们的修复并丢弃他们的修复,-X theirs并将保留他们的修复并丢弃我们的修复。

在更复杂的情况下,我们可能已经添加或删除了一些行,他们添加或删除了不同的行,因此更难考虑冲突。例如,有时git diff可能会在空白行或由单个右大括号组成的行上错误地同步,从而导致某些人或真正了解要合并的材料的人能够成功合并的冲突。再次,-X简单地丢弃他们的差异大块或我们的,取我们告诉它的任何一个。

文件冲突

就目前而言,这很好,但它只处理差异大块差异。您看到的冲突是不兼容的文件更改:

CONFLICT (rename/delete): rcS.d/S08kmod deleted in HEAD and renamed
 in local/master. Version local/master of rcS.d/S08kmod left in tree.

在这种情况下,一个git diff(查找“我们的”更改)发现我们(HEAD)完全删除 rcS.d/S08kmod了,而他们(local/master重命名了文件。在任何 delete-file-vs-rename-file 冲突中,Git 将文件保留在新名称下,因为我们删除它 ( git rm newname) 比弄清楚新名称是什么并检索我们或他们的文件版本。

Auto-merging php5/cli/conf.d/20-xdebug.ini

(这个进展顺利,也许是-X theirs用来解决 diff hunk 冲突)

CONFLICT (add/add): Merge conflict in php5/cli/conf.d/20-xdebug.ini

在这里,合并基础没有名为php5/cli/conf.d/20-xdebug.ini. Git 将两个版本都保留在索引中;我们可以使用git checkout --ours将我们的放在工作树中,git checkout --theirs并将他们的放在工作树中。不幸的是,我们仍然必须手动合并和解析这个文件。我还没有检查 Git 2.8 版在这里做了什么(添加/添加冲突解决方案最近已经完成了一些工作)。

Auto-merging apt/sources.list

(另一个自动合并进展顺利,可能再次使用-X

CONFLICT (rename/rename): Rename "apache2/sites-available/default-ssl"->
"apache2/sites-available/default-ssl.conf.conf" in branch "HEAD"
rename "apache2/sites-available/default-ssl"->
"apache2/sites-available/default-ssl.conf" in "local/master"

在这种情况下,合并库中的文件(在 name 下apache2/sites-available/default-ssl.conf.conf)从两个差异中出现,在我们的更改和它们的更改中被重命名为不同。我再次不确定 Git 对文件中的更改做了什么(如果有的话)尽管从逻辑上讲,-X theirs 应该在我们和他们冲突的任何地方应用并采用“他们的”差异大块。但是,Git 不知道该文件使用哪个最终名称,因此它声明了冲突。

声明这些冲突后,Git 停止并让用户像往常一样手动解决剩余的问题。您可以git addgit rm您想要的每个文件的任何版本,然后git commit是结果。当然,无论何时使用-X theirsor ,在提交之前以某种方式(通过观察差异,或运行手动或自动测试,或其他方式)测试-X ours工作树是明智的。

于 2016-08-08T17:44:43.030 回答