如何解决在第一个分支中已删除并在第二个分支中重命名的文件的合并冲突?

3

我正在处理一个分支,其中我已经删除了一些文件夹。与此同时,在主分支上所有根文件夹都已被重命名,因此所有文件(包括我已删除的文件)的路径都已被重命名。

当我尝试合并时,我会在所有已删除(在我的分支上)和已重命名(在主分支上)的文件夹的所有文件上遇到冲突。我列出了这些文件(1000+),它们在git状态的未合并路径中显示为:

added by them:   FolderRenamed/File1.ext
added by them:   FolderRenamed/File2.ext

我希望在这个机会上能够将它们从“theirs”版本中恢复,当我尝试将主分支合并到我的分支时(虽然您可能期望我想做相反的事情,并确认文件已被删除;如果使用“ours”而不是“theirs”,这将是相同的概念)。
我认为我可以简单地为每个文件调用以下命令:
git checkout --theirs FolderRenamed/File1.ext

但是似乎在文件上调用这个命令并没有实现任何变化。我的文件仍然在“未合并路径”列表中。

有人能帮我确定我做错了什么吗?由于本地版本已被删除,git checkout是否不像我期望的那样工作?

3个回答

3

TL;DR: 你只需要使用git add命令。

详细说明

当我尝试合并时,我会在所有已经被删除(在我的分支上)和重命名(在主分支上)的文件夹的所有文件上遇到冲突...

是的:当你运行例如:

git checkout branch
git merge master

Git:

  • 识别您当前的提交(HEAD,也称为分支:通过哈希 ID 选择一个特定的提交,这是您目前在索引和工作树中拥有的提交),也称为本地或--ours,但我只称其为L(左侧/本地);
  • 识别另一个提交(也称为master),也称为远程、其他和--theirs等多种方式,但我只称其为R(右侧/远程);
  • 找到这两个提交之间的合并基础。那是最近的共同提交。我将此称为B

(请注意,如果您检出master并运行git merge branch,则仅在此过程的一部分中交换了LR。)

然后,Git 实际上运行启用重命名检测的两个git diff

git diff --find-renames B L > /tmp/b-vs-l.patch
git diff --find-renames B R > /tmp/b-vs-r.patch

结果是一个列表,它包含了自从基础版本B以来你在L中所做的所有更改,以及他们在R中自相同基础版本B以来所做的所有更改。Git然后合并这些更改。
如果您重命名了一个文件,而他们删除了“相同”的文件(由重命名检测检测到),则会出现重命名/删除冲突。如果他们重命名了一个文件,而您将其删除,则会出现相同的冲突。无论哪种情况,Git都会发生冲突。 在冲突的特殊情况下(但不是在普通情况下),Git会在您的索引中保留每个文件的三个版本:B中的版本,Git会将其作为“stage 1”保留在索引中;来自L的版本,Git将其作为“stage 2”或--ours保留在索引中;和来自R的版本,Git将其作为“stage 3”或--theirs保留在索引中。
这些较高编号的阶段文件是Git记住您处于冲突合并中的方式。通常,索引中的所有文件都在“stage zero”。如果Git能够自行解决冲突,它将删除三个更高的阶段,并留下一个解决了冲突的零阶段文件。
您的工作树中的文件(大多数情况下)与索引中的文件无关,当然,您的工作树没有阶段槽编号。只能有一个somepath/file1.ext。在重命名/删除冲突的情况下,基础文件有一个阶段1条目,而--ours--theirs文件有一个阶段2或阶段3条目。另一个阶段槽(分别为3或2)为空。git status命令以added by us(占用1和2,3为空)或added by them(占用1和3,2为空)的形式向您显示此信息。
运行git checkout --ours告诉Git将阶段2版本复制到工作树中。运行git checkout --theirs告诉Git将阶段3版本复制到工作树中。在任何一种情况下,阶段1条目不会发生任何变化,阶段0条目保持为空。
运行git add告诉Git将文件从工作树复制到阶段0插槽中,完全抹去其余插槽。文件现在已经解决。
由于Git将重命名的文件留在工作树中(以新名称),因此在这种情况下,您只需要git add重命名的文件即可。

当然,这不是唯一的方法

如果您运行git checkout commit-specifier -- path,Git会从给定的commit-specifier中提取给定的路径path。当Git这样做时,它将路径复制到索引的零号槽中。这将清除该路径的任何1-3号槽位条目,因此从特定提交中检出文件的副作用是解析该文件。
这与git checkout --ours--theirs不同,因为它们从现有的索引条目中提取,所以它们不会写入零号槽。
因此,您还可以使用git checkout MERGE_HEAD -- paths将重命名的文件提取到其重命名名称中,在此过程中解决合并冲突。

2
原来这里处理的正确方法只是(正如git所建议的...):
git add FolderRenamed/File1.ext

或者,如果我想恢复重命名文件夹中的所有文件,只需执行以下操作:
git add FolderRenamed

(如果我想要删除文件夹及其内容,我就会使用git rm...)
Git非常强大 :)。

2

git checkout --theirs命令可以检出“他们”的版本,但是它是从索引中检出的,而不是更新索引,并且这不会标记冲突已解决。

从命名提交检出会更新索引,正在进行合并的“theirs”提示的名称为MERGE_HEAD

git checkout MERGE_HEAD -- paths/to/files`

仅需声明那些正确的版本即可。

当然,git add 同样会更新索引,因此您可以使用 git checkout --theirs 命令,检查结果以确保它是您想要的,然后将其添加到索引中(使用 git add 命令)。


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