合并时的Git行为

合并时的Git行为,git,merge,git-branch,Git,Merge,Git Branch,我有一个项目,有一个源分支——Branch1和两个分支,我从Branch1获得,比如Branch2和Branch3 我删除了Branch2中的一个文件,并要求将其合并到Branch1。它被成功合并 我对Branch3中的一个文件进行了更新,但是在Branch2中删除的文件仍然可以在Branch3中看到 然后我成功地将其合并到Branch1 但我认为Git会合并Branch3的快照,它仍然将文件保存在Branch1上。 但是遗憾的是,没有,在第一次合并请求中删除的文件消失了。 事实上,在Branc

我有一个项目,有一个源分支——Branch1和两个分支,我从Branch1获得,比如Branch2和Branch3

我删除了Branch2中的一个文件,并要求将其合并到Branch1。它被成功合并

我对Branch3中的一个文件进行了更新,但是在Branch2中删除的文件仍然可以在Branch3中看到

然后我成功地将其合并到Branch1

但我认为Git会合并Branch3的快照,它仍然将文件保存在Branch1上。 但是遗憾的是,没有,在第一次合并请求中删除的文件消失了。 事实上,在Branch3到Branch1的合并请求期间,git甚至没有在GitLab中将该文件作为diff告诉我

我的问题是,我认为Git总是会复制Branch3的整个快照并将其合并到Branch1


为什么没有发生这种情况?

为了让这更具体,让我们调用您在分支2上删除的文件
foo.txt
。当您将分支2合并到分支1中时,该文件现在也会在分支1上删除。由于分支3不修改此文件,因此即使在合并分支3后,它仍会在分支1上被删除

考虑这一点的最佳方式是合并将更改从一个分支复制到另一个分支。合并时,它不会复制整个快照。不过,这仍然是一个小小的波动。为了获得git如何工作的更准确的心智模型,理解提交是什么很重要。基本上,提交是一组更改以及一些附加元数据,如时间戳、作者姓名等。提供了非常有用的深入描述

然后,分支是一系列提交。签出分支时,git通过在该分支上应用提交中的所有更改来创建其跟踪的所有文件的本地副本。合并也是如此:
git merge branch1
将把branch1中但不在当前分支中的所有更改应用于本地文件

现在,更容易理解以下命令中发生的情况:

git checkout branch1
git merge branch3

由于分支3不会更改在分支1上删除的文件,git将其保持原样。Git将只应用分支3中尚未属于分支1的更改。

欢迎使用堆栈溢出。我想我从你的口头描述中理解了你的问题。但是,您可以通过使用特定的文件名(即使它们是虚构的)使其更加清晰。特别是,我不清楚“我删除Branch2中的文件”和“我更新Branch3中的文件”是指不同的文件还是指同一个文件。为这两个文件使用名称将使您的意思更加清楚。更好的是,在整个过程中显示实际的git命令。@matt是的,这也是。特别是因为短语“对Branch3中的文件进行更新”完全没有意义。你是说你拉了?编辑?什么?在很多方面这都不重要,但我认为最好不要声称提交是一种改变。这实际上是一个快照。这一点在这里更为重要,因为当Git进行合并时,它将直接比较合并基础和两个分支提示以获得变更集,而不是将所有中间变更集相加。结果在困难的重命名情况下有所不同…@torek当你说“这实际上是一个快照”时,快照是什么?我的理解是,提交只记录更改,而不是整个项目的快照。这不是一种正确的查看方式吗?它是运行
git commit
时索引中所有文件的快照。这些文件是压缩的,但不是增量。每次签出都使用已签出的快照填充索引。使用
git add
将一个文件从工作树复制到索引中,压缩并覆盖索引中的文件,或者创建一个新文件(如果是新文件名),然后
git rm
从索引中删除该文件(以及过程中的工作树)。因此,索引总是随时可用,这使得
git commit
速度更快。对于每个文件的每个版本,存储库中都有一个blob对象(文件内容,去掉文件名)。这些blob对象最终被打包到“打包文件”中,这些文件使用增量压缩,但在对象抽象不可见的级别上。这意味着提交和树对象也可以得到增量压缩。在更高的级别上,Git只是通过其哈希ID请求一个对象;如果它在一个包文件中,deltified,Git必须先取消deltified。@torek所以如果我理解正确,delta压缩只存储提交和其父级之间的更改,但是git的实现方式是直接构造工作目录,而不是像我在这里的回答中所暗示的那样,在每个提交的基础上重放每个提交。是这样吗?