如何使用建议的解决方案解决变基期间的 "file location" 冲突?

How to resolve "file location" conflicts during rebase using the suggested resolution?

CONFLICT (file location): path/to/tests/NS/Domain/Projects/Foo/Bar/stories/workspace-public-channel-SOME_UUID.json added in HEAD inside a directory that was renamed in <some hash> (Reorganize tests), suggesting it should perhaps be moved to path/to/tests/unit/NS/Projects/Foo/Bar/stories/workspace-public-channel-SOME_UUID.json.

我检查了这条消息并确定该建议是正确的。

告诉git 继续做确切咒语是什么?我担心 "git add/rm <conflicted_files>", then run "git rebase --continue" 的一般建议在这种特殊情况下可能不够用,或者可能会把事情搞砸。

编辑澄清:这里是 git status 显示的具有这种冲突类型的示例文件:

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)

...
...
        deleted:    old/path/to/some/file.spec.js
...
...

和后面相同的输出git status:

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
...
...
        added by us:     new/path/to/some/file.spec.js
...
...

这是我尝试 git mv old/path/to/some/file.spec.js new/path/to/some/file.spec.js:

时的错误消息
fatal: bad source, source=old/path/to/some/file.spec.js, destination=new/path/to/some/file.spec.js

What is the exact incantation to tell git to go ahead and do it?

题目的形式表明只有一个命令是正确的。事实并非如此。 任何 组 Git 命令在该路径名下 Git 的索引中与该文件一起结束就足够了。

根据您所展示的:

git add new/path/to/some/file.spec.js

应该够了。但是,如果这不起作用或出错,请继续阅读。

这里要理解的是,Git 中的深层(或者,好吧,less-shallow?)魔法是当合并1 停止时对于合并冲突,Git 所做的是将冲突留在 Git 的 index 中。你现在的工作是修复索引中的混乱。

索引,也称为暂存区(有时也称为缓存 ), 包含一系列 name-and-hash-ID 对,你可以看到:

git ls-files --stage

这些名称是将要或将要进入您下一次提交的文件的 名称。 hash ID是Git记录对应文件内容的内部标识符

通常,每个条目都在 阶段编号零 git ls-files --stage 的输出看起来像这样(我从命令 运行 在 Git 存储库中 Git):

100644 b08a1416d86012134f823fe51443f498f4911909 0       .gitattributes
100644 536e55524db72bd2acf175208aef4f3dfc148d42 0       COPYING
100644 80d1908a44ca38058c58dcc4e3444ee96060757b 0       Documentation/Makefile
100644 7074bbdd53cc1141c75546ad6e009b5ac74a63c2 0       wt-status.c
100644 35b44c388edf0cd75cca00e1458b9995c8001538 0       wt-status.h

100644表示文件模式(not-executable),哈希值记录内容,零本身就是stage number,该行的其余部分是路径名,可能包括嵌入的(正斜杠),如本例中的 Documentation/Makefile 文件。

如果现在 运行 git commit,新提交将包含此处列出的文件集。但是,git commit 本身会犹豫——失败——如果这些 阶段数字 中的任何一个不为零。

git merge 运行s时,它扩展了索引,填充了很多非零阶段号。然后它执行合并,每次成功合并 解析 一个文件并将其移回零阶段,折叠非零阶段条目。每个 失败 合并都会留下非零阶段条目。

git status 命令将 stage-zero 路径(即 staged for commit)与 nonzero-stage 路径分开。暂存槽 #1 中的任何内容都是一个 merge base 文件,它来自共享的公共提交。暂存槽 #2 中的任何内容都来自 HEAD 提交,暂存槽 #3 中的任何内容都来自另一个提交。

路径名可能会被合并操作修改,通过重命名请求,但是文件内容可能来自您的 HEAD 提交。实际上可能 他们的 提交没有文件,所以暂存槽 #3 是空的,如果文件也不在合并库中,暂存槽 #1 将是空的以及。在这种情况下,您会看到该文件列为 added by us。即使路径名称以某种方式更改也是如此。

git add命令告诉Git:使该路径名的索引条目与相同路径名的work-tree文件相匹配。这具有删除该路径名的任何阶段 1、2 和 3 条目的副作用,从而解决冲突。它在零阶段添加文件,或者如果文件 缺少 来自 work-tree,则只删除文件的所有索引条目。无论哪种方式,都不再有任何非零阶段编号条目。

大多数 Git 合并案例都非常简单,但是只要有大量重命名,或者目录被重命名,事情就会变得一团糟。某些文件的路径名在合并库中为 old/path/to/file。它可能是您自己的提交中的 old/path/to/file——您正在通过 git rebase 复制到 new-and-improved 提交的提交——或者它可能是 third/name/for/file,以及您的路径想要的是 new/nameoffile 或其他任何东西。 Git 是否以及何时将正确的路径放在某个索引槽中有点不确定。最近有很多改进工作,根据你引用的消息,我认为你有一个更新的 Git.

但是,

All(“全部”?)您真正需要做的是安排 Git 的索引来保存完整的正确文件名集和内容哈希。 Git 的索引中的任何内容,在第 0 阶段,都是当您 运行 git rebase --continue 时将进入新提交的内容。 关于冲突的所有,我们添加的,他们添加的,等等只是描述非零暂存槽编号中的内容的一种方式. changes to be committed 下显示的所有内容都在暂存槽零中,并且显示在那里是因为它与当前 HEAD 中的提交不同

另见脚注 1,我现在将此答案称为“完成”并继续编写(“它”是脚注)。


1你 运行宁 git rebase,而不是 git merge。但是 rebase 使用 git cherry-pick,而 git cherry-pick 使用 Git 的合并引擎。这里的技巧是,当 rebase 对每个 git cherry-pick 进行时,你就在一个 新分支上 Git 正在构建,将重命名为您的分支。这个新分支从与 他们的 分支相同的最后一次提交开始,即您要重新定位的分支。因此,当您看到“由我们添加”时,它的意思是“由某人添加,从他们开始的地方开始”,可能是 他们 而不是我们.它是 extra-messy 因为当你在 rebase 中进行十或二十次提交时,Git 正在处理的“我们的”或 HEAD 提交是十次或二十次提交深度 混合 你复制的提交和它们的原件。

所有这一切的要点是,您应该减少对“我们”和“他们”有时令人讨厌的明显颠倒的关注,而只需将每次提交所需的最终快照放在一起来解决冲突.我发现将 merge.conflictStyle 设置为 diff3 也有帮助。