Git真的能跟踪单个函数从一个文件到另一个文件的移动吗?如果是,怎么做?

Git真的能跟踪单个函数从一个文件到另一个文件的移动吗?如果是,怎么做?,git,git-diff,git-log,Git,Git Diff,Git Log,我曾多次遇到这样一种说法,即如果将单个函数从一个文件移动到另一个文件,Git可以跟踪它。例如,他说,“Linus说如果你将一个函数从一个文件移动到另一个文件,Git会告诉你这个函数在移动过程中的历史记录。” 但我对Git的一些引擎盖下设计有一点了解,我不知道这是怎么可能的。所以我想知道。。。这是正确的说法吗?如果是这样,这怎么可能呢 我的理解是Git将每个文件的内容存储为一个Blob,每个Blob都有一个全局唯一的标识,该标识源于其内容和大小的SHA散列。然后Git将文件夹表示为树。任何文件名信

我曾多次遇到这样一种说法,即如果将单个函数从一个文件移动到另一个文件,Git可以跟踪它。例如,他说,“Linus说如果你将一个函数从一个文件移动到另一个文件,Git会告诉你这个函数在移动过程中的历史记录。”

但我对Git的一些引擎盖下设计有一点了解,我不知道这是怎么可能的。所以我想知道。。。这是正确的说法吗?如果是这样,这怎么可能呢

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

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

据我所知,这将导致两个新的blob存在(一个用于修改的foo,一个用于修改的bar)。我意识到可以计算一个diff来显示函数从一个文件移动到另一个文件。但我不知道函数的历史如何可能与bar而不是foo关联(无论如何,不是自动关联)

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


所以。。。这句话对不对?如果它是正确的,那么我的理解中还缺少什么?

有一个
git diff
将向您显示某些行从
foo
中消失,并在
栏中重新出现。如果在同一次提交中这些文件中没有其他更改,那么很容易发现更改

智能的
git
客户端将能够向您展示行是如何从一个文件移动到另一个文件的。有语言意识的IDE将能够将这种变化与特定的函数对应起来


重命名文件时,也会发生类似的情况。它只是在一个名称下消失,在另一个名称下重新出现,但任何合理的工具都能够注意到它并将其表示为重命名。

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

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


不过,我不知道基本git工具是否真的做到了这一点——它们试图做到语言中立,而函数标识也不是语言中立的。

这一功能的一部分在
git gui中(+filename)。它显示文件行的注释,每行都指示文件创建的时间和上次更改的时间。对于跨文件的代码移动,它将原始文件的提交显示为创建,并将添加到当前文件的提交显示为上次更改。试试看


我真正想要的是将
git log
作为一个参数附加到一个文件路径的行号范围,然后它将显示这个代码块的历史记录。如果文档是正确的,就没有这样的选项。是的,从Linus的陈述中,我也认为这样的命令应该是现成的。

这个功能是通过
git-C
提供的

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

您可以尝试使用
git-C
进行测试repo,您将看到刚才移动的代码块来自它所属的原始文件

从手册页面:

在整个文件重命名过程中,行的原点将自动跟随(目前没有关闭以下重命名的选项)。要跟随从一个文件移动到另一个文件的行,或跟随从另一个文件复制和粘贴的行等,请参阅
-C
-M
选项

使用
--color moved
选项检测移动的行时。它适用于跨文件移动

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

对于默认行为,请尝试

git diff --color-moved
该命令还接受选项,当前有
no
default
plain
zebra
dimmed\u zebra
(使用
git help diff
获取最新选项及其说明)。例如:

git diff --color-moved=zebra

至于它是如何完成的,您可以从中获得一些理解。

我指的不是“函数重命名”。相反,我想问的是将一个文件文本的子集从该文件移到另一个文件的情况。你是对的,但你的评论不清楚,开头几句话会暗示(我)你误解了Q,请编辑它或做些什么。在主题上,git使用(system?)diff,这就是它在这方面的全部能力,它可以“跟踪”函数重命名,但它在i方面并不特别聪明