重命名文件与拉请求压缩合并



根据我所学到的,git可以在一次提交中提交重命名/移动时处理文件重命名/移动,在另一次提交时进行修改。

但是,当你挤压合并你的公关部门时,这是如何运作的呢?

  1. 在功能分支中:重命名文件并提交
  2. 在功能分支中:修改文件并提交
  3. 创建PR
  4. 挤压将其合并为master

与此同时,其他人在自己的功能分支中修改了相同的文件。

当他们将master合并到功能分支中时会发生什么?据我所知,重命名和文件修改在master中是在同一个提交中进行的(由于压缩合并(,对吧?那git会怎么处理呢?

根据我所学到的,git可以在一次提交中提交重命名/移动并在另一次提交时进行修改时处理文件重命名/移动。

嗯,是的,但也不是。

这里的关键是Git不存储更改。Git存储快照。换句话说,每个提交都有源代码的完整副本。如果重命名一堆文件,不做其他更改,并创建新快照,则旧快照的内容在旧名称下,而新快照的内容与相同,但在一组新的名称下

如果重命名并修改文件,则旧快照的旧名称下有旧内容,而新快照的新名称下有新内容。

Git对git log --followgit diff --find-renames所做的是拍摄两个快照——比如说"在"一个有趣的事件之前和之后,在这种情况下,有趣的事件是重命名——并且比较它们。在内部,提交的文件存储为<名称,散列ID>对(或者更准确地说,<模式、名称、哈希ID>三元组(:

$ git ls-tree -r HEAD
[snippage]
100644 blob 41b718c29e1b9fc2981d7d14a3d25e69c31a3030    version.c
100644 blob 7c62e80577154d79bec050424945eb500d262a0f    version.h
100644 blob 069ee94a4d79422ea659a7ebe3923662f0626afa    versioncmp.c
100644 blob bb010f7a2b3c1090bc9c62f613cede7bbda86e97    walker.c
[snippage]

这里的blob实际上是mode的一部分的文本表示(100644始终是blob对象(,因此这些行中的每一行都是读取条目的结果,该条目包含此名称和哈希ID配对。

每个文件内容的哈希ID仅基于文件数据,而不是文件的名称。例如,无论文件名为walker.c还是funny.name,只要内容相同,哈希ID也将相同。

因此,给定左侧和右侧快照(前后(,如果哈希ID匹配,则内容也匹配。这使得git diff --find-renames非常快速地找到重命名:我们只需排列所有匹配的哈希ID,左侧的名称就会重命名为右侧的名称。

如果文件被轻微地修改,这种快速重命名检测技巧就不起作用。现在Git必须实际提取所有左侧文件和所有右侧文件,并比较。与快速"查看哈希ID"的技巧不同,这实际上非常困难(要配对的文件数量为O(n2((。Git将首先尽最大努力在不检查内容的情况下将所有左侧和右侧文件配对,这样"可能重命名"的文件列表就尽可能小,然后只查看那些尚未配对的文件。

因此,Git可以处理这两种情况——只要内容没有发生太大的变化,这样相似性检测器就可以消耗大量的CPU时间来通过相似性索引匹配文件——但如果git diff区分两次提交的事件只是一个重命名事件,则进行匹配重命名查找所需的计算能力要小得多。这意味着所有的散列ID都匹配,而快速匹配代码完成了全部工作。

但当你压缩合并你的公关分支时,这是如何工作的?

没有。

挤压合并是工具。在适当的时候使用它们。当挤压合并不合适时,请使用其他工具。

(记住,压缩合并意味着运行git merge,但随后将结果提交为普通提交,而不是合并提交。从命令行来看,git merge --squash每次都像包含了--no-commit选项一样,所以你必须自己运行git commit命令。GitHub点击"压缩并合并"按钮不使用命令行命令,所以它有点不同,但您得到的最后一组提交与您在命令行上完成所有这些操作时相同。(

最新更新