Git合并未合并所有文件

9

我在使用git时遇到了很大的困难。

我有一个分支A和一个分支B。我想要将分支A合并到分支B中。我目前在分支B上,并使用了以下命令:

git merge A

现在,当我运行git status时,我发现我领先了两次提交,并且当我查看在git merge期间更改的文件时,我注意到只有两个文件被更改。然而,至少有十几个文件在分支A中被更改,但在git merge中没有被选中。

为什么git merge只合并了这两个文件,而显然还有其他需要被合并的文件呢?


如果您将更改提交到B分支,则合并将带来这些提交,因此文件不会出现在git状态中,只有提交记录。 - Jamie - Fenrir Digital Ltd
@EvilGeniusJamie 哦天啊,那我怎么知道哪些文件被更改了?我更关心文件而不是提交记录。 - Robin
我会建议查看 git diff-tree 的文档,但是... git 的文档 >.< 哈哈。不过可以看看这个答案 https://dev59.com/PHRC5IYBdhLWcg3wD8xV - Jamie - Fenrir Digital Ltd
@Robin git diff --name-only branchA branchB 请执行以上命令以比较分支A和分支B之间的差异,并返回文件名列表。 - Ramiz Wachtler
1个回答

12

比较两个分支尖端提交是错误的,因为这不是git merge所做的事情。

要查看每个人更改的文件,必须首先找到最近共享AB分支的提交:

             o--o   <-- branch-B
            /
...--o--o--*
            \
             o--o--o   <-- branch-A

这里每个回合o代表着人们随时间添加的提交记录。

我在这里标注了一个叫做公共提交的符号*,它就是Git称之为两个分支的合并基础。当你处于其中一个分支的末端(例如B)并运行git merge A命令时,Git会自动找到此提交。

然后Git将进行比较,不是BA的差异,也不是AB的差异,而是:

git diff hash-of-* hash-of-tip-of-B    # what did *we* change?

并且:

git diff hash-of-* hash-of-tip-of-A    # what did *they* change?
git merge的目标是定位并提取提交记录*,将来自两个分支的所有更改应用于当前分支(B),并将其作为一个新的合并提交进行提交,其中包含两个父提交,以使其成为合并提交,这样Git下一次就知道要使用什么作为合并基础。
如果您想查看提交记录*的哈希ID,可以运行git merge-base
git merge-base --all A B
你可以运行git diff命令,使用合并基础的哈希ID,并将名称A用于选择分支A的末尾,以查看它们所做的更改。你可以运行第二个独立的git diff,再次使用相同的合并基础哈希ID,并将名称B用于选择分支B的末尾,以查看你所做的更改(你可能还记得自己所做的更改,但查看Git是否同意你的记忆是个好主意,因为Git将使用它发现的内容,而不是你的记忆!)。
有一个简写方式可以为你运行git merge-base命令,它只与git diff命令一起使用。
git diff A...B   # note the three dots

将会比较AB的合并基础与由B标识的提交,以找出所更改的内容。后续操作为:

git diff B...A   # note the three dots again

将会比较BA1的合并基础与由A标识的提交,以查找它们所更改的内容。

(您可以添加选项,如--name-status--name-onlygit diff来影响git diff显示其计算/查找到的更改。请注意,每当涉及重命名时,合并使用等效于git diff -M50以查找重命名。现代Git自2.9版起默认启用git diff中的重命名检测。)


1"合并基础"是一种对称图形操作,因此"A和B的合并基础"在定义上等于"B和A的合并基础"。


10
这并未解决如何将两个分支合并所有文件的问题,只是告诉我有时Git是一个复杂且不直观的混乱工具。 - Ian Smith
@IanSmith:git merge将从合并基地合并,如所述。如果您想从其他地方合并而不是从合并基地,请勿使用git merge。(如果要特定地取三个文件并将它们组合起来,请考虑使用git merge-file,它需要三个输入文件而不是三个输入提交。) - torek
2
假设你要将分支A(主线)还原到它的第一个提交,并且你想将分支B(新主线)的所有内容作为下一个新提交带入分支A。常识告诉我们应该首先尝试使用git merge,但这并不是正确的工具?在这种情况下,什么是正确的工具? - Ian Smith
如果你的意思是做了类似于:git checkout master; git merge --ff-only $(git commit-tree -p HEAD -m urk first-commit-hash^{tree}),以便 master 的树与根提交的树匹配,那么“合并”图中其他提交的结果就不太清楚了。但如果你有计划,可以使用 git commit-tree 创建任意图形,然后运行 git merge 在生成的提交上,知道 git merge 的工作原理;生成的可能是你想要的文件集。 - torek
请注意,在上述情况下,git merge 不会执行任何操作。将 Git 视为一个图形操作工具,并附带有大量文件更新工作:请参见 Think Like (a) Git - torek
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接