git git重命名/删除混淆

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3100032/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 04:21:59  来源:igfitidea点击:

git rename/delete confusion

gitgit-merge

提问by Sabya

I having one confusion about a particular git behavior:

我对特定的 git 行为感到困惑:

Following are the steps and situation (the list of commands are also given later):

以下是步骤和情况(命令列表也在后面给出):

  1. I have two branches: master and XBranch
  2. There is a file src/a.txt in both of them. It's content is "Old Content"
  3. In XBranch I rename src/a.txt to src/b.txt, using: mv, git rm, git add.
  4. In master rename the file a.txt. During commit I did git rm src/a.txtbut forgot to do git add src/b.txtIn master I do: git rm src/a.txtand git commit

  5. In master, I edit the content of the file b.txt to "New Content

  6. In master I do git add src/b.txtand git commit
  7. In master I do: git merge XBranch
  1. 我有两个分支:master 和 XBranch
  2. 它们中都有一个文件 src/a.txt。它的内容是“旧内容”
  3. 在 XBranch 中,我将 src/a.txt 重命名为 src/b.txt,使用:mv, git rm, git add
  4. 在 master 中重命名文件 a.txt。在提交期间我做了git rm src/a.txt但忘了做git add src/b.txt在 master 我做:git rm src/a.txtgit commit

  5. 在 master 中,我将文件 b.txt 的内容编辑为“New Content

  6. 在主人我做git add src/b.txtgit commit
  7. 在主人我做: git merge XBranch

The file src/b.txt conflicts, which is perfectly understandable. But the content is "Old Content". Why?

文件 src/b.txt 冲突,这完全可以理解。但内容是“ Old Content”。为什么?

Why notis it something like:

为什么不是这样的:

<<<<<<< HEAD
New Content
=======
Old content
>>>>>>> XBranch

List of Commands:

命令列表:

sabya@SABYA-PC d:/merge_temp/test/case2
$ mkdir source

sabya@SABYA-PC d:/merge_temp/test/case2
$ git init
Initialized empty Git repository in d:/merge_temp/test/case2/.git/

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ mkdir src

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ vi src/a.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ cat src/a.txt
Old Content

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git add src/

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git commit
[master (root-commit) 148500e] added src/a.txt
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 src/a.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git branch XBranch

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git checkout XBranch
Switched to branch 'XBranch'

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ mv src/a.txt src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git rm src/a.txt
rm 'src/a.txt'

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git add src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git commit
[XBranch b3ff8fa] changed a.txt to b.txt in XBranch
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename src/{a.txt => b.txt} (100%)

sabya@SABYA-PC d:/merge_temp/test/case2 (XBranch)
$ git checkout master
Switched to branch 'master'

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ mv src/a.txt src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git rm src/a.txt
rm 'src/a.txt'

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git commit
[master bfeaecb] removed src/a.txt
 1 files changed, 0 insertions(+), 1 deletions(-)
 delete mode 100644 src/a.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ vi src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ cat src/b.txt
New Content

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git add src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git commit
[master 2361d5e] changed content of b.txt
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 src/b.txt

sabya@SABYA-PC d:/merge_temp/test/case2 (master)
$ git merge XBranch
CONFLICT (rename/delete): Rename src/a.txt->src/b.txt in XBranch and deleted in HEAD
Automatic merge failed; fix conflicts and then commit the result.

sabya@SABYA-PC d:/merge_temp/test/case2 (master|MERGING)
$ cat src/b.txt
Old Content

采纳答案by VonC

There is a conflict, but not about the filecontent. It is about the treecontent.

存在冲突,但与文件内容无关。这是关于 树的内容。

  • In one tree, the case2directory (in master), there is a newfile b.txt
  • in the same directory (in XBranch), there is a renamedfile a.txt => b.txt
  • 在一棵树中,case2目录(在 master 中),有一个文件b.txt
  • 在同一个目录中(在 XBranch 中),有一个重命名的文件a.txt => b.txt

When you are resolving the conflict, you are in effect choosing one file or the other (not one line within the file). Hence the "Old Content" in the resulting file.

当您解决冲突时,您实际上是在选择一个文件或另一个文件(而不是文件中的一行)。因此,结果文件中的“旧内容”。



The OP adds in the comments:

OP 在评论中添加:

But then how logically is it different from the following situation:

  1. I add a file a.txtin masterwith "Old Content" and commit it.
  2. I add a file a.txtin XBranchwith "New Content" and commit it.
  3. I merge XBranchinto master. This time it is showing both contents in that file!

但是,它与以下情况在逻辑上有何不同:

  1. 我想补充文件a.txtmaster与“老内容”并提交。
  2. 我想补充文件a.txtXBranch与“新内容”并提交。
  3. 我合并XBranchmaster. 这次它显示了该文件中的两个内容!

This time, both trees (the case2 directory in branches masterand XBranch) reference a newfile a.txt: its content get merged, with conflict resolution. Before, there was a conflict between a a.txt(renamedas b.txt) and a newb.txt: both files cannot exist in the same branch, a choice (of file, not of file content) had to be made.

这一次,两个树(分支中的 case2 目录masterXBranch)都引用了一个文件a.txt:它的内容被合并,并解决了冲突。之前, a a.txt重命名b.txt)和新的b.txt之间存在冲突:两个文件不能存在于同一分支中,必须做出选择(文件,而不是文件内容)。

In step 4 of my question, if I do "git rm" and "git add" in a single commit, it works as I expect! I fail to understand that now. How can I predict when the file will have both contents? When it will just have the content of XBranchand when will it have just the content of master?

在我的问题的第 4 步中,如果我在一次提交中执行“ git rm”和“ git add”,它会按我的预期工作!我现在不明白。我如何预测文件何时将同时包含这两个内容?什么XBranch时候只有 的内容,master什么时候只有 的内容?

That means that:

这意味着:

  • instead of merging XBranch(a.txtrenamed as b.txt) to mastercommit with a new b.txtfrom step 6 (conflict of tree),
  • you would merge XBranch(a.txtrenamed as b.txt) with master from new step 4 (a.txtalso renamedas b.txt): same tree content, but different blob content: conflict of lines.
  • 而不是合并XBrancha.txt重命名为b.txt)以master提交b.txt第 6 步中的新内容(树冲突),
  • 您将与新步骤 4 中的 master合并XBrancha.txt重命名为b.txt)(a.txt也重命名b.txt):相同的树内容,但不同的 blob 内容:行冲突。


That being said, the OP still thinks there must be a bug:

话虽如此,OP 仍然认为一定存在错误:



Note: Git 2.18 (Q2 2018) changes that conflict detection report with a merge recursive.
See commit 6e7e027(19 Apr 2018) by Elijah Newren (newren).

注意:Git 2.18(2018 年第二季度)使用合并递归更改了冲突检测报告。
请参阅Elijah Newren ( ) 的commit 6e7e027(2018 年 4 月 19 日newren

merge-recursive: avoid spurious rename/rename conflict from dir renames

If a file on one side of history was renamed, and merely modified on the other side, then applying a directory rename to the modified side gives us a rename/rename(1to2)conflict.
We should only apply directory renames to pairs representing either adds or renames.

Making this change means that a directory rename testcase that was previously reported as a rename/deleteconflict will now be reported as a modify/deleteconflict.

merge-recursive: 避免目录重命名的虚假重命名/重命名冲突

如果历史记录一侧的文件被重命名,而只是在另一侧进行了修改,那么将目录重命名应用于修改后的一侧会给我们带来rename/rename(1to2)冲突。
我们应该只将目录重命名应用于表示添加或重命名的对。

进行此更改意味着以前报告为rename/delete冲突modify/delete的目录重命名测试用例 现在将报告为 冲突



When a binary file gets modified and renamed on both sides of history to different locations, both files would be written to the working tree but both would have the contents from "ours".

当一个二进制文件在历史记录的两边被修改和重命名到不同的位置时,两个文件都将被写入工作树,但都将包含来自“ ours”的内容。

This has been corrected with Git 2.27 (Q2 2020), so that the path from each side gets their original content.

这已在 Git 2.27(2020 年第二季度)中得到纠正,以便每一方的路径都获得其原始内容。

See commit 95983da(13 May 2020) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster--in commit abbd1d9, 20 May 2020)

请参阅Elijah Newren ( ) 的提交 95983da(2020 年 5 月 13 日(由Junio C Hamano合并-- --abbd1d9 提交中,2020 年 5 月 20 日)newren
gitster

merge-recursive: fix rename/rename(1to2) for working tree with a binary

Reported-by: Chunlin Zhang
Signed-off-by: Elijah Newren

With a rename/rename(1to2) conflict, we attempt to do a three-way merge of the file contents, so that the correct contents can be placed in the working tree at both paths.

If the file is a binary, however, no content merging is possible and we should just use the original version of the file at each of the paths.

merge-recursive:使用二进制修复工作树的重命名/重命名(1to2)

报告人
:张春林 签字人:Elijah Newren

由于重命名/重命名(1to2)冲突,我们尝试对文件内容进行三向合并,以便将正确的内容放置在两个路径的工作树中。

但是,如果文件是二进制文件,则无法合并内容,我们应该只在每个路径上使用文件的原始版本。