简体   繁体   English

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

[英]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它们。

Longer 更长

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的方法:

  • identifies your current commit ( 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 (左/本地);
  • identifies the other commit (aka master ), also known variously as remote , other , and --theirs , but I just call this R (right/remote); 标识另一个提交(也称为master ),也称为remoteother--theirs ,但我只称其为R (右/远程);
  • finds the merge base between these two commits. 查找这两个提交之间的合并基础 That's the most recent commit-in-common. 这是最新的commit-in-common。 I call this B for base. 我称其为B。

(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 ,则只需要在过程的这一部分交换LR。

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重命名的文件。

That's not the only way to do it though 虽然这不是唯一的方法

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.

相关问题 Git:合并第二个分支后将第三个分支重新设置为第一个分支的更好方法 - Git: Better way to rebase 3rd branch onto 1st branch after 2nd branch merged 当第一个拉取请求尚未合并时,如何从同一分支创建第二个拉取请求 - How to create 2nd pull request from same branch when 1st pull request is not merged yet Git合并显示在两个分支中均已真正重命名的文件的“重命名/删除” - Git merge showing 'rename/deleted' for file really renamed in both branch 将master与第二分支合并并提交给master - Merge master with 2nd branch and commit to master Git Merge与重命名或删除的文件冲突 - Git Merge conflict with renamed or deleted file 如何合并两个分支,其中第一个分支有一个提交 A,第二个分支将提交 A 修改为 B,并且在 B 之上有 3 个提交? 没有合并提交 - how to merge two branches where 1st has one commit A and 2nd has commit A amended to B and 3 commits over top of B? Without a merge commit 解决不同分支之间的合并冲突 - Resolve merge conflict between different branch git merge忽略合并分支上存在的已删除文件(重命名文件) - git merge ignores deleted files, existing on merged branch (renamed files) 如何在不将主分支拉入功能分支的情况下解决 git 合并冲突? - How to resolve git merge conflict without pulling master branch into feature branch? 合并冲突,但 git 存储库已被删除 - Merge conflict but the git repository has been deleted
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM