77

有好几次,我遇到过这样的说法,如果你将一个函数从一个文件移动到另一个文件,Git 可以跟踪它。例如,这个条目说,“Linus 说如果你将一个函数从一个文件移动到另一个文件,Git 会告诉你这个移动过程中单个函数的历史。”

但是我对 Git 的一些底层设计有一点了解,我不明白这是怎么可能的。所以我想知道......这是一个正确的说法吗?如果是这样,这怎么可能?

我的理解是,Git 将每个文件的内容存储为一个 Blob,每个 Blob 都有一个全局唯一标识,该标识来自其内容和大小的 SHA 哈希值。然后 Git 将文件夹表示为树。任何文件名信息都属于树,而不属于 Blob,因此文件重命名例如显示为对树的更改,而不是对 Blob。

因此,如果我有一个名为“foo”的文件,其中包含 20 个函数,以及一个名为“bar”的文件,其中包含 5 个函数,然后我将其中一个函数从 foo 移动到 bar(分别导致 19 和 6), Git 如何检测到我将该函数从一个文件移动到另一个文件?

据我了解,这将导致存在 2 个新 blob(一个用于修改后的 foo,一个用于修改后的 bar)。我意识到可以计算出一个差异来表明该函数已从一个文件移动到另一个文件。但是我看不到有关该函数的历史记录如何可能与 bar 而不是 foo 相关联(无论如何都不会自动关联)。

如果 Git 要实际查看单个文件的内部,并为每个函数计算一个 blob(这将是疯狂的/不可行的,因为您必须知道如何解析任何可能的语言),那么我可以看到这是如何可能的。

所以……这个说法正确与否?如果它是正确的,那么我的理解中缺少什么?

4

5 回答 5

35

此功能是通过提供的git blame -C <file>

-C选项驱使 git 尝试在正在审查的文件中添加或删除文本块与在相同变更集中修改的文件之间找到匹配项。附加-C -C-C -C -C扩展搜索。

在测试存储库中尝试一下,git blame -C您会发现刚刚移动的代码块源自它所属的原始文件。

git help blame手册页:

整个文件重命名时会自动跟随行的起源(目前没有关闭重命名跟随的选项)。要跟踪从一个文件移动到另一个文件的行,或跟踪从另一个文件复制和粘贴的行等,请参阅-C-M选项。

于 2012-05-19T11:53:13.237 回答
20

Git 2.15 开始,git diff现在支持使用选项检测移动的行--color-moved。它适用于跨文件移动。

显然,它适用于彩色终端输出。据我所知,没有选择以纯文本补丁格式指示移动,但这是有道理的。

对于默认行为,请尝试

git diff --color-moved

该命令还接受选项,当前为nodefaultplain和(用于获取最新选项及其描述)zebra。例如:dimmed_zebragit help diff

git diff --color-moved=zebra

至于它是如何完成的,你可以从这个功能作者的电子邮件交流中获得一些理解。

于 2017-11-09T02:39:00.840 回答
8

git gui blame(+ 文件名)中包含一些此功能。它显示文件行的注释,每行都指示它的创建时间和上次更改时间。对于跨文件的代码移动,它将原始文件的提交显示为创建,并将其添加到当前文件的提交显示为last change。试试看。

我真正想要的是在git log文件路径之外提供一个行号范围作为一些参数,然后它将显示此代码块的历史记录。如果文档正确,则没有这样的选项。是的,从 Linus 的声明中,我也认为这样的命令应该很容易获得。

于 2011-02-06T12:48:31.227 回答
5

git 实际上根本不跟踪重命名。重命名只是删除和添加,仅此而已。任何显示重命名的工具都会从这些历史信息中重建它们。

因此,跟踪函数重命名只是事后分析每次提交中所有文件的差异的简单问题。没有什么特别不可能的。现有的重命名跟踪已经处理了“模糊”重命名,其中对文件进行了一些更改以及重命名;这需要查看文件的内容。查找函数重命名也是一个简单的扩展。

然而,我不知道基本的 git 工具是否真的这样做了——它们试图保持语言中立,而功能识别在很大程度上不是语言中立的。

于 2011-02-05T17:53:02.523 回答
2

那里git diff会告诉你某些行从 中消失foo并重新出现在bar. 如果在同一次提交中这些文件没有其他更改,那么更改将很容易被发现。

一个聪明的git客户将能够向您展示行如何从一个文件移动到另一个文件。具有语言感知能力的 IDE 将能够将此更改与特定功能相对应。

当文件被重命名时,会发生非常相似的事情。它只是以一个名称消失并以另一个名称重新出现,但任何合理的工具都能够注意到它并表示为重命名。

于 2011-02-05T17:48:40.810 回答