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

时间:2018-02-14 18:07:45

标签: git

我正在我删除了一些文件夹的分支机构上工作。与此同时,在master分支上,所有根文件夹都已重命名,因此所有文件的路径(包括我删除的文件)都已重命名。

当我尝试合并时,我的所有文件夹中的所有文件都被删除(在我的分支上)并重命名(在主服务器上)。我列出了这些(1000+)文件,这些文件在git status的Unmerged路径中显示如下:

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

我想在这个场合恢复它们,当我尝试在我的分支中合并master时,从“他们的”版本恢复它们(尽管你可能希望我想要反过来,并且已经确认了文件删除;这与“我们的”而不是“他们的”是相同的概念。

我以为我可以简单地为每个文件调用以下命令:

git checkout --theirs FolderRenamed/File1.ext

但似乎不会在文件上调用此命令实现任何更改。我的文件仍在“Umerged paths”列表中。

有人可以帮我确定我做错了什么吗? git checkout是否按预期工作,因为本地版本已被删除?

3 个答案:

答案 0 :(得分:3)

TL; DR:你只需要git add他们。

  

当我尝试合并时,我的所有文件夹中的所有文件都被删除(在我的分支上)并重命名(在主设备上)...

是:当你跑步时,例如:

git checkout branch
git merge master

GIT中:

  • 标识您当前的提交(HEAD又名branch:这些通过哈希ID选择一个特定提交,这也是您现在在索引和工作树中提交的提交,也称为作为本地--ours,但我只是称之为 L (左/本地);
  • 标识另一个提交(又名master),也称为远程其他--theirs,但我只是称之为 R (右/远程);
  • 在这两个提交之间找到合并基础。这是最近的共同承诺。我称之为 B 为基础。

(请注意,如果您查看master并运行git merge branch,则只需交换此过程的 L R 。 )

然后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

结果是您在 L 以及 L 中所做的所有事情的列表,以及他们在 R 中所做的一切,因为它们是相同的基础。然后Git结合了这些变化。

如果您重命名文件并删除了“相同”文件(通过重命名检测检测到),则这是重命名/删除冲突。如果他们重命名了一个文件并将其删除,则会发生同样的冲突。无论哪种方式,Git都有冲突。

在冲突的特殊情况下(但在普通情况下不是这样),Git会在你的索引中留下每个文件的所有三个版本:来自< em> B ,Git在索引中留下“第1阶段”;来自 L 的那个,Git在索引中留下“第2阶段”或--ours;以及来自 R 的那个,Git在索引中留下“第3阶段”或--theirs

这些编号较高的舞台文件是Git记得您处于冲突合并中的方式。通常,索引中的所有文件都处于“阶段0”。如果Git能够自行解决冲突,它将删除三个更高的阶段,只留下一个阶段零解析文件。

work-tree 中的文件(大部分)独立于索引中的文件,当然,工作树没有阶段插槽编号。只能有一个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将stage-slot-2版本复制到工作树。运行git checkout --theirs告诉Git将stage-slot-3版本复制到工作树。在任何一种情况下,stage-slot-1条目都没有任何反应,stage-slot-zero条目仍为空。

运行git add告诉Git将文件从工作树复制到第0阶段插槽,完全删除剩余的插槽。该文件现已解决。

由于Git将重命名的文件保留在工作树中(在新名称下),因此在这种情况下您需要做的只是git add重命名的文件。

虽然

,但这不是唯一的方法

如果您运行git checkout commit-specifier -- path,Git会从给定的 path 中提取给定的 commit-specifier 。当Git执行此操作时,它会将路径复制到索引的插槽零中。这会清除该路径的任何插槽1-3条目,因此从特定提交中检出文件的副作用是解析该文件。

这与git checkout --ours--theirs不同,因为它们从现有索引条目中提取 ,因此它们不会写入插槽零。

因此,您还可以使用git checkout MERGE_HEAD -- paths将重命名的文件解压缩到其重命名的名称中,从而解决流程中的合并冲突。

答案 1 :(得分:2)

git checkout --theirs会结帐&#34;他们的&#34;版本,但它从索引中检出,而不是更新它,并且没有标记冲突已解决。

从命名提交中签出更新索引,以及飞行中合并的名称&#34;他们的&#34;提示是MERGE_HEAD。所以

git checkout MERGE_HEAD -- paths/to/files`

简单地声明那些正确的版本。

当然git add也会更新索引,因此您可以git checkout --theirs检查结果,确保结果符合您的意思,然后git add

答案 2 :(得分:1)

原来这样做的正确方法很简单(正如git所建议的那样......):

git add FolderRenamed/File1.ext

或者,因为我想要恢复我重命名的文件夹中的所有文件,只需:

git add FolderRenamed

(如果我想删除文件夹及其内容,我会使用git rm ...)

Git非常强大:)。