Git:合并文件的合并结果子集

时间:2018-05-21 21:21:41

标签: git git-merge

假设fileA上有一个master(说它由1000行组成)

我们在feature_branch,其中fileA的长度为1050行。

然后如何成为可能,进入master并执行

git merge feature_branch

fileA最终会有(再次)1000行?

合并消息显示没有冲突,并通知我

  

自动合并fileA

更新:重要的是:

在使用包含特定文件的新虚拟项目进行测试时,

master / 1000行和

开始

feature_branch / 1050行合并到其中,

以1050行结束。

我想这是一个关于主要项目历史的问题呢?

1 个答案:

答案 0 :(得分:5)

TL; DR

这可能完全正常。例如,基本版本也可能有1050行,其中一个更改是删除 50行。结合"删除50行"与"改变其他东西,或根本不做任何改变"结果"删除50行"作为对该文件的最终更改。

合并前需要了解的内容

关于在Git中合并,有几点要记住。首先是Git使用merge作为动词,合并,这意味着组合变化,而Git也使用merge作为形容词或名词,合并提交或简单地合并,它指的是至少有两个提交的提交。

另一个是git merge并不总是实际合并。它可以做一些它叫做快进的东西。在这种情况下,Git根本不会执行动词形式 - 此处没有合并 - 并且不会进行合并提交。所以请确保你的合并是一个真正的合并,我在下面描述,而不是其中一个快速非合并。

还要记住Git存储快照:每次提交都是每个源文件的完整副本。这会影响动词形式合并的工作方式。

"合并"并不意味着"复制"

Merge-as-a-verb是从一些共同点组合变化的行为。考虑到这一点,想想两个做出两个不同变化的人:Alice修复第12行,其中单词"拼写错误"错误拼写,并且Bob修复第20行,其中句子有错误的单词。爱丽丝提交了她的拼写修复,鲍勃提交了错误的单词修复。

当Alice去合并Bob的修复程序时,反之亦然,Git 一定不能带走其他修复程序。因此,将这两个更改合并到文件README.txt必须将Alice的版本与合并基础版本进行比较,然后将Bob的版本与相同合并基础版本。无论Alice做出什么改变,都会进入变更集:" Alice变更的内容。"无论Bob做出什么改变,都会进入一个单独的变更集:鲍勃改变了什么。

Git然后合并两个变更集,将两个更改集应用于基本文件,以获得最终结果。如果Alice和Bob在不同的行上进行了更改 - 就像在这个例子中一样--Git只需要进行两组更改。如果他们更改了相同的行,Git将查看他们是否对这些行进行了相同的更改,如果是,请获取该更改的一个副本。否则(他们改变了相同的行,但以不同的方式)Git声明合并冲突,让来修复混乱。

当合并结果令您惊讶时,请查看您的假设

要做的第一件事是确保你有一个真正的合并。如果是这样,接下来要弄清楚公共基础版本是什么。您可以使用git merge-base命令执行此操作:

git merge-base --all a1fc931 4056ca3
例如,如果你正在合并的两个提交哈希是a1fc9314056ca3。要查找提交哈希值,您可以查看git log --graph --oneline;或者,如果合并完成,您可以使用特殊的Git语法来处理您刚刚合并的父级:

git merge-base --all HEAD^1 HEAD^2

如果合并已因合并冲突而停止,您可以通过以下方式找到合并基础:

git merge-base --all HEAD MERGE_HEAD

因为MERGE_HEAD将记录其他提交的哈希值。

找到合并基础 - 这将是一个很难看的哈希ID - 你现在可以生成Git看到的两个变更集:

git diff --find-renames <base> <left>
git diff --find-renames <base> <right>

<base>这里是git merge-base --all找到的合并基础哈希ID。 (如果发现不止一个,你会遇到更困难的特殊情况;运气好的话,它只打印一个哈希ID。)<left>部分是HEAD^1或{ {1}},取决于合并是否完成:它是您开始合并时的提交。 HEAD部分是另一个提交,可以是<right>HEAD^2

两个MERGE_HEAD的输出是你改变了什么(在左边)和他们改变了什么(在右边)。 Git正在组合这些更改,或者将它们组合在一起,以产生失败或成功的合并。

关于合并基础和快进

的更多单词(和图表)

在Git中查找合并库的行为包括扫描提交图 - 或根据需要尽可能多地查找最低共同祖先两个提交被合并。如果我们用左边的早期提交绘制图形,然后在右边提交,如下所示:

git diff

其中每轮 o--o--L <-- yourbranch (HEAD) / ...--o--* \ o--o--R <-- otherbranch 代表一个提交,那么 merge base 是过去两个分支连接的第一个提交:commit o,在此案件。因此,Git会将提交*与提交*进行比较,并将L与提交*进行比较,以确定您更改的内容以及更改内容。

当分支序列看起来更像这样时,就会发生快进:

R

这里,合并基础提交您当前的(HEAD)提交。如果Git要将提交...--o--* <-- yourbranch (HEAD) \ o--o--R <-- otherbranch 与提交*进行比较,那会发生什么变化?

在这种情况下,Git不必进行任何实际的合并。它可以直接检查提交*,因为组合&#34;没有改变&#34;使用&#34; R*&#34;之间的任何变化;只是让你再次提交R。因此Git默认执行此操作,导致:

R

您只需获取每个文件的版本。

你可以强制Git进行真正的合并,并进行真正的合并提交,从而产生这样的结果:

...--o--o
         \
          o--o--R   <-- yourbranch (HEAD), otherbranch

其中...--o--*---------M <-- yourbranch (HEAD) \ / o--o--R <-- otherbranch 是合并提交(合并为形容词)。但是,存在于commit M中的快照将与提交M中的快照完全匹配。 Git结合了你的&#34;完全没有变化&#34;通过更改,将这些更改应用于基础R,并构建与*匹配的新提交。