[英]How to resolve a merge conflict on a file that has been deleted in 1st branch and renamed in 2nd branch?
I am working on a branch where I have deleted some folders. 我正在删除某些文件夹的分支上工作。 In the meantime on the master branch all the root folders have been renamed, so the path of all files (including the ones I have removed) has been renamed. 同时,在master分支上,所有根文件夹都已重命名,因此所有文件(包括我已删除的文件)的路径都已重命名。
When I attempt to merge I get a conflict on all the files of all the folders that have been both deleted (on my branch) and renamed (on master). 当我尝试合并时,所有已删除(在我的分支上)和重命名(在母版上)的所有文件夹的所有文件都发生冲突。 I made a list of these (1000+) files which appear like this in git status's Unmerged paths : 我列出了这些(1000多个)文件的列表,这些文件在git status的Unmerged path中显示为:
added by them: FolderRenamed/File1.ext
added by them: FolderRenamed/File2.ext
I would like to restore them at this occasion, from the "theirs" version when I attempt to merge master in my branch (although you could have expected me to want to do the opposite, and have the files deletion been confirmed ; which would be the same concept with "ours" instead of "theirs"). 我想在此时恢复它们,当我尝试在分支中合并master时从“ theirs”版本恢复(尽管您可能希望我做相反的事情,并且已确认文件删除;这将是相同的概念,用“我们的”代替“他们的”)。
I thought I could simply call the following command for every file : 我以为我可以为每个文件简单地调用以下命令:
git checkout --theirs FolderRenamed/File1.ext
But it does not seem like calling this command on a file achieves any change. 但是在文件上调用此命令似乎并没有实现任何更改。 My file is still in the "Umerged paths" list. 我的文件仍在“合并路径”列表中。
Can somebody help me identify what I am doing wrong ? 有人可以帮助我确定我在做什么错吗? Is git checkout not working as I expected because the local version had been deleted ? git checkout是否无法正常工作,因为本地版本已被删除?
TL;DR: you just need to git add
them. TL; DR:您只需要git add
它们。
When I attempt to merge I get a conflict on all the files of all the folders that have been both deleted (on my branch) and renamed (on master) ... 当我尝试合并时,所有已删除(在我的分支上)和重命名(在主文件上)的所有文件夹的所有文件都发生冲突...
Yes: when you run, eg: 是:运行时,例如:
git checkout branch
git merge master
Git: Git的方法:
HEAD
aka branch
: these select one particular commit by hash ID, which is the commit you have in your index and work-tree right now as well), also known as local or --ours
, but I just call this L (left/local); 标识您当前的提交( HEAD
aka branch
:它们通过哈希ID选择一个特定的提交,这也是您现在在索引和工作树中的提交),也称为local或--ours
,但我只是调用L (左/本地); master
), also known variously as remote , other , and --theirs
, but I just call this R (right/remote); 标识另一个提交(也称为master
),也称为remote , other和--theirs
,但我只称其为R (右/远程); (Note that if you check out master
and run git merge branch
you are just swapping L and R for this part of the process.) (请注意,如果您检出master
并运行git merge branch
,则只需要在过程的这一部分交换L和R。 )
Git then, in effect, runs two git diff
s with rename detection enabled: 实际上,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
The result is a list of everything you did in L since the base B , and everything they did in R since the same base B . 结果列出了自基B以来您在L中所做的所有操作的列表,以及自相同基B以来他们在R中所做的所有操作的列表。 Git then combines these changes. 然后,Git结合了这些更改。
If you renamed a file and they deleted "the same" file (as detected by the rename detection), this is a rename/delete conflict. 如果重命名文件,并且他们删除了“相同”文件(通过重命名检测检测到),则这是重命名/删除冲突。 If they renamed a file and you deleted it you get the same conflict. 如果他们重命名了文件而您删除了该文件,则会遇到相同的冲突。 Either way Git has a conflict. 无论哪种方式,Git都有冲突。
In the special case of conflicts (but not in ordinary cases), Git will leave, in your index, all three versions of every file : the one from B , which Git leaves in the index as "stage 1"; 在发生冲突的特殊情况下 (但在通常情况下则不是),Git将在您的索引中保留每个文件的所有三个版本 : B中的一个,Git在索引中保留为“阶段1”; the one from L , which Git leaves in the index as "stage 2" or --ours
; L中的一个,Git在索引中--ours
为“阶段2”或--ours
; and the one from R , which Git leaves in the index as "stage 3" or --theirs
. 和R中的一个,Git在索引中--theirs
为“ stage 3”或--theirs
。
These higher-numbered stage files are how Git remembers that you are in the middle of a conflicted merge. 这些编号较高的舞台文件是Git记住您处于冲突合并中的方式。 Normally, all the files in the index are at "stage zero". 通常,索引中的所有文件都处于“零阶段”。 If Git were able to resolve the conflict on its own, it would erase the three higher stages and leave just a stage-zero resolved file in place. 如果Git能够自行解决冲突,它将擦除三个较高的阶段,仅保留零阶段解决文件。
The files in your work-tree are (mostly) independent of the files in your index, and of course you work-tree has no stage slot numbers. 工作树中的文件(大多数)独立于索引中的文件,当然,工作树没有阶段插槽号。 There can only be one somepath/file1.ext
. 只能有一个somepath/file1.ext
。 In the case of a rename/delete conflict, there's a stage 1 entry for the base file and a stage 2 or stage 3 entry for the --ours
or --theirs
file. 如果发生重命名/删除冲突,则基本文件有一个阶段1条目, --ours
或--theirs
文件有一个阶段2或阶段3条目。 The other stage-slot (3 or 2 respectively) is left empty. 另一个级插槽(分别为3或2)保留为空。 The git status
command shows this to you as added by us
(1 and 2 occupied, 3 empty) or added by them
(1 and 3 occupied, 2 empty). git status
命令向您显示这是added by us
(1和2占用,3个为空)或added by them
(1和3占用,2个为空)。
Running git checkout --ours
tells Git to copy the stage-slot-2 version to the work-tree. 运行git checkout --ours
告诉Git将stage-slot-2版本复制到工作树中。 Running git checkout --theirs
tells Git to copy the stage-slot-3 version to the work-tree. 运行git checkout --theirs
告诉Git将stage-slot-3版本复制到工作树中。 In either case, nothing happens to the stage-slot-1 entry, and the stage-slot-zero entry remains empty. 在这两种情况下,stage-slot-1条目都没有任何反应,stage-slot-zero条目保持为空。
Running git add
tells Git to copy the file from the work-tree to the stage-zero slot, wiping out the remaining slots entirely. 运行git add
告诉Git将文件从工作树复制到阶段0插槽,完全清除剩余的插槽。 The file is now resolved. 现在文件已解析。
Since Git leaves the renamed file in the work-tree (under the new name), all you need to do in this case is git add
the renamed file. 由于Git将重命名的文件保留在工作树中(使用新名称),因此在这种情况下,您需要做的就是git add
重命名的文件。
If you run git checkout commit-specifier -- path
, Git extracts the given path
from the given commit-specifier
. 如果运行git checkout commit-specifier -- path
,则Git将从给定的commit-specifier
提取给定的path
。 When Git does this, it copies the path into slot zero of the index. 当Git执行此操作时,它将路径复制到索引的插槽0中。 This wipes out any slot 1-3 entries for that path, so a side effect of checking out a file from a specific commit is that this resolves the file. 这会清除该路径的所有插槽1-3条目,因此从特定提交中检出文件的副作用是可以解析该文件。
This is different from git checkout --ours
and --theirs
because those extract from the existing index entries , so they don't write into slot zero. 这与git checkout --ours
和--theirs
不同,因为它们是从现有索引条目中提取的 ,因此它们不会写入插槽0。
Hence you can also use git checkout MERGE_HEAD -- paths
to extract the renamed files into their renamed names, resolving the merge conflict in the process. 因此,您还可以使用git checkout MERGE_HEAD -- paths
将重命名的文件提取到其重命名的名称中,从而解决了该过程中的合并冲突。
git checkout --theirs
does checkout "their" version, but it's checking out from the index, not updating it, and that doesn't mark the conflict resolved. git checkout --theirs
会检出“其”版本,但它是从索引中检出,而不是对其进行更新,并且这并不表示已解决冲突。
Checking out from a named commit updates the index, and the name of an in-flight merge's "theirs" tip is MERGE_HEAD
. 从命名提交中检出将更新索引,并且运行中合并的“其”提示的名称为MERGE_HEAD
。 So 所以
git checkout MERGE_HEAD -- paths/to/files`
to simply declare those the correct versions. 简单地声明那些正确的版本。
Of course git add
also updates the index, so you could git checkout --theirs
, inspect the result to be sure it's what you meant, then git add
it. 当然git add
也会更新索引,因此您可以git checkout --theirs
,检查结果以确保它是您的意思,然后git add
它。
Turns out the right way to proceed here was simply (as suggested by git...) : 事实证明,正确进行此操作的方式很简单(如git ...所建议):
git add FolderRenamed/File1.ext
Or, as I want to restore all the files inside my renamed folders, simply : 或者,由于我要还原重命名文件夹中的所有文件,因此只需:
git add FolderRenamed
(And I would have used git rm if I had wanted to remove the folders and their content...) (如果我想删除文件夹及其内容,我将使用git rm ...)
Git is so powerful :). Git非常强大:)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.