git rebase合并软链接的冲突

时间:2018-04-24 07:37:49

标签: git rebase merge-conflict-resolution

我的用例是在历史记录中的特定提交后插入新提交。我有提交的哈希值,之后我需要插入一个新的提交。

让我们说吧 3是我想在下面的历史记录中提交2之后插入的新提交。

1 <-- 2 <-- 4 <-- 5 <-- 6

我在主分支上执行了以下步骤。

git checkout -b temp <commit 2 hash>
echo "new commit" > test_file.txt
git add test_file.txt
git commit -a -m "Inserting a new commit"
git rebase -Xours temp master

我从提交2创建了分支临时,在该分支上进行了提交并进行了rebase。希望历史如下所示,

1 <-- 2 <-- 3 <-- 4 <-- 5 <-- 6
如果存在任何文件合并冲突,

-Xours可以正常工作,但其失败会在软链接中显示合并冲突。

错误如下所示

Auto-merging apps/abc/ps_abc
CONFLICT (content): Merge conflict in apps/abc/ps_abc
Auto-merging apps/def/ps_def
CONFLICT (content): Merge conflict in apps/def/ps_def

以上两条路径是我的git repo之外的目录的软链接。 Git diff并不适合他们。如何处理这类冲突?

请帮忙。

1 个答案:

答案 0 :(得分:2)

TL; DR

在Git的估算中,名为 P 的符号链接(其中 P 代表{{1}之类的路径})只是一个名为 apps/abc/ps_abc 的文件,类型为&#34; link&#34;其内容为二进制。由于内容是二进制的,Git无法区分它们。你会认为P会告诉Git使用&#34;我们的&#34;,但它没有,因为它永远不会落入低级代码。

解决方案是选择正确的版本(通过您喜欢的任何方式)并确保它在索引中作为阶段零版本,然后继续操作(在本例中为-Xours)。 / p>

合并 - 的动词形式合并 - 是从一个共同的起点开始组合变化的过程。这个常见的起点是,在Git中,合并基础提交。 Git使用提交图找到合并库:你用git rebase --continue检查一些特定的提交,然后告诉Git git checkout mybranch。这两个名称标识了两个特定的提交; Git查看了每个提交背后的历史,以找到两组工作分歧的最佳起点。

对于在所有三次提交中发生的每个路径 git merge theirbranch ,Git使用<设置 P 的索引/临时区域条目em>所有三个文件,使用包含 P 的每个条目中的插槽来保存尚未合并的文件。基本版本进入插槽1.我们的同一文件的版本在插槽2中,他们的同一文件的版本在插槽3中。然后,当以下所有条件成立时,会发生合并冲突:

  • 基础版本与左侧版本不同。也就是说,由于公共合并库提交,我们使用路径 P 更改了文件。
  • 基础版本与右侧版本不同。他们也使用路径 P 更改了文件。
  • 左侧和右侧的版本也不同。也就是说,我们对他们所做的更改进行了不同的更改。
  • 由于某种原因,Git无法将这两组更改结合起来。

对于 text (非二进制)文件,Git首先观察前三个条件 - 该文件存在于所有三个版本中,但两侧都有变化 - 并且有效地运行了P从左到右,从左到右。然后,Git可以逐行查看这些更改,并将组合更改为单个常见更改。

如果此过程失败,Git通常会声明合并冲突并停止。这将在索引中保留暂存插槽1中的文件 git diff merge base 版本,我们的版本在暂存中然后你可以合并这三个文件 - 也许是使用显示冲突的工作树版本,或者可能使用忽略的合并工具,然后将它们合并到第3个文件中的他们的版本。工作树版完全支持原来的三个输入。但无论你做什么,通常都会运行P来结束这个序列。这告诉Git删除三个更高级的版本并复制工作树中的任何内容现在 - 例如,在您编辑工作树版本之后,或者生成一个新版本使用合并工具 - 将索引/临时区域作为路径 git add P 的正常,未冲突,插槽为零的条目。此解决合并冲突。

使用P-Xours告诉Git它将声明这种合并冲突的位置,它应该简单地覆盖其中一个与另一个冲突的更改。冲突永远不会出现!通常,低级别合并过程会将冲突本身置于路径 -Xtheirs 下的工作树文件中,并保留三个较高级别的条目。不过,这一次,这个低级合并进程通过左/本地/ P更改(--ours)或采取正确/远程来自动解决冲突 / -Xours更改(--theirs),忽略对方对此行的更改。只要-Xtheirs实际上匹配了正确的行集 - 这并非总是如此 - 所得到的行组合可能是有意义的。

在任何情况下,使用此git diff选项,低级文件合并代码会按照您告诉它的方式处理冲突 - 通过支持您告诉它支持的任何一方 - 并替换三个更高级别路径 X 的-stage-number条目,具有正常的,阶段为零,全部与此文件条目良好的条目。所以现在这个特定文件已经成功合并,Git继续进行三次提交中的下一组文件。

这对于二进制文件

都失败了

使用二进制文件,Git甚至不会尝试对文件进行区分:它们只是因为基础而被更改或不更改。它不会尝试使用低级文件合并代码组合两个差异。由于 没有低级文件合并,因此没有任何内容可以查看您的P选项,而是支持一方而不是另一方。

结果是合并失败的方式与您根本没有使用-X完全相同。 -X选项是低级合并的指令 - Git中结合了两个文件差异的部分 - 该代码从未运行过。因此,合并冲突仍保留在索引/暂存区域中,并且合并将因合并冲突而停止。您必须自己解决此合并冲突。

一个rebase是一系列樱桃选择,每个樱桃选择使用merge-as-a-verb

您可能会在此反对并说:我没有正在运行-X,我正在运行git merge答案是:是的,但是git rebase基本上只是一系列git rebase自动重复命令。一个樱桃选择复制一个提交,因此如果rebase需要复制三个提交,例如git cherry-pick,则rebase在这三个提交上运行三个樱桃选择。每个4--5--6都是通过使用执行合并动词的Git部分完成的。 cherry-pick的合并基础是被复制的提交的 parent ;左侧或git cherry-pick提交是提交Git是&#34;站在&#34;因为它复制;而右侧或--ours提交是Git正在复制的提交。

一旦完成一个挑选,​​Git就会检查该提交:现在提交--theirs以进行下一次挑选操作。也就是说,当你开始:

--ours

并运行 D--E--F <-- old-branch / A--B \ C <-- new-branch ,Git将首先提交git checkout old-branch && git rebase new-branch复制到新提交D以便在C之后:

D'

这是一种樱桃挑选式合并操作;合并基础是 D--E--F <-- old-branch / A--B \ C <-- new-branch \ D' <-- temporary 的父DB提交是提交--ours。一旦此合并成功并且提交C,Git就会将提交D'复制到E

E'

这是三次樱桃挑选行动中的第二次。现在,合并基础为 D--E--F <-- old-branch / A--B \ C <-- new-branch \ D'-E' <-- temporary D提交为--theirsE提交为--ours。如果此合并成功,Git继续使用第三个樱桃选择复制三个提交中的最后一个。一旦成功,提交图如下所示:

D'

现在Git需要做的就是完全删除临时分支名称​​移动分支名称 D--E--F <-- old-branch / A--B \ C <-- new-branch \ D'-E'-F' <-- temporary

old-branch

并且已完成rebase。

因为每个符号链接实际上都是二进制文件,所以必须手动合并每个这样的文件:使用 D--E--F [abandoned] / A--B \ C <-- new-branch \ D'-E'-F' <-- old-branch 的低级合并代码永远不会运行。要再次选择-Xours版本,这将是--ours中的那个,然后是C中的那个,然后是D'中的那个 - 您可以运行E'将路径 git checkout --ours -- P 的slot-2版本复制到工作树中,然后P复制路径 git add P的工作树版本回到索引作为阶段0,解决冲突。

(有一个快捷方式:您可以运行P将版本从git checkout HEAD -- P提交复制到索引槽0并进入工作树。由于HEAD或stage-2版本来自 --ours ,这具有相同的效果,但只使用一个Git命令。)