第 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
如果需要的话可以对结果进行更改。)