Git 合并删除文件

2024-05-26

这是第二次发生这种情况,当我进行合并时,我后来意识到正在合并的分支中的一些文件不再位于正在合并的分支中。

最新的例子是我们有一个功能分支,我一直在合并主开发分支中的更改,合并后我们丢失了很多文件,并且它们现在不存在于功能分支中。

  1. 为什么会出现这种情况?
  2. 获取这些文件的最佳方式是什么?我正在考虑手动添加它们。

以下是文件丢失时存储库的描述:

964495c是文件丢失的地方,它是远程分支与本地分支的合并。 d1c457a 是从主开发分支到功能分支的合并。

当我对这两个分支进行比较时,我看到丢失的文件已被删除,但它们从未设置为删除。这不是我的合并,所以我不确定这是否是用户错误,但我需要找出将这些文件包含在我的功能分支中的最佳方法......


第 1 部分的答案

我这里没有足够的信息来告诉你什么did发生......但这里是如何查看发生了什么should发生(或已经发生),在git merge ...。从上图我们可以看出964495c是一个合并,如果它的父提交是一个合并d1c457a(黄点和线)。我们看不到它的另一个父提交——另一个父提交位于紫色线的另一端。 (我想,一根线是分支dev另一个是分支feature.)

[Edit:根据评论,第一个父级是29a7b67(在分支上feature),第二个是d1c457a(在分支上dev正如预期的那样)。]

第一件事git merge所做的就是找到“合并基础”。因此,在 shell 命令窗口中找到两个父 ID:

$ git rev-parse 964495c^1
29a7b67...
$ git rev-parse 964495c^2
d1c457a...

(I'm partly guessing here, based on colors, that d1c457a is the second-parent, i.e., the thing being merged-in, rather than the thing merged-into—not that it matters too much, the merge result should be the same either way). [Edit: confirmed]

Now, using the two commit IDs produced above, find the merge-base. For simplicity I'll assume the first command produced 1234567... Per comment, this is 8967ae7...

$ git merge-base 29a7b67 d1c457a
8967ae7...

You now have three commit IDs. Let's re-do the above with shell variables, just so that I don't have to guess at the commit-IDs any more since the symbolic names might help:

$ id_into=$(git rev-parse 964495c^1)
$ id_from=$(git rev-parse 964495c^2)
$ id_base=$(git merge-base $id_into $id_from)

Now shell variables $id_base, $id_from, and $id_into hold the commit ID of the merge-base, the tip of the branch being merged-from,1 and the ID of the commit just before 964495c itself (the original tip of branch feature when the merge was being done).

使用这些,我们可以看到什么git merge被要求合并,通过做两个git diff是。 (接下来的部分假设 Unix/Linux/Mac shell 重定向。)

$ git diff -M50% $id_base $id_into > /tmp/existing_changes
$ git diff -M50% $id_base $id_from > /tmp/new_changes

第一个差异找出“这个分支上发生了什么,即feature自从另一个分支dev与它不同”。第二个差异发现“另一个分支上发生了什么dev因为它偏离了这个分支,即feature".

The merge命令然后尝试将这两者结合起来。无论在哪里dev有任何变化:

  • 如果更改是添加新文件,则添加新文件(除非feature还添加了它:那么我们可能会发生冲突,需要手动解决)
  • 如果更改是重命名文件,则重命名该文件(再次除非feature已经有了)
  • 如果更改是删除文件,则删除该文件
  • 如果更改是从文件中添加或删除某些行,请在此处执行此操作(除非feature已经有,在这种情况下,忽略更改;或者如果我们找不到具有相同内容的确切行,那么我们就会遇到冲突 - 这种冲突情况包括文件被删除的情况feature).

我已将以下情况加粗git merge should删除一个文件。如果合并自分支 (dev)自合并基础以来删除了该文件,git merge会悄悄地从合并结果中删除该文件。


现在,话虽如此,如果进行合并的人使用--no-commit,或者如果存在冲突,合并会在尽其所能后停止,并且无论谁进行合并都有机会进行合并额外的变化。在合并冲突的情况下,这当然是进行合并的人员必须解决冲突的地方。但是,进行合并的人可以使用--no-commit即使没有冲突也能到达这里。无论如何,此时,进行合并的人可以删除文件、添加文件和修改文件。当他或她(好吧,让我们用“他们”:-))...当他们完成时,他们git commit结果,并做出了承诺964495c....


1At least, it's what was the tip of dev at the time: dev might have grown a bit since then, just as feature has in fact grown since then.

第 2 部分的答案

不一定有单一的最佳方法来找回丢失的文件,但很容易从特定提交中签出文件。这里明显要使用的是29a7b67 (aka $id_from上面,尖端feature当谁进行合并时,就进行了合并):

$ git checkout 29a7b67 -- path/to/file

(列出多个文件,或一个或多个目录,以从该提交 ID 中获取更多文件或目录中的每个文件。)这会将文件放入工作树中and索引,截至它们在该提交 ID 处所处的状态,以便下一个git commit会将它们包含在该状态中。

(您当然可以编辑它们并git add如果需要的话可以对结果进行更改。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Git 合并删除文件 的相关文章

随机推荐