Git能否真正跟踪单个函数从1个文件到另一个文件的移动?如果是这样,怎么样?

Cha*_*ers 66 git git-diff git-log

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

但我对Git的一些引擎盖设计有一点了解,我不知道这是怎么回事.所以我想知道......这是正确的陈述吗?如果是这样,这怎么可能?

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

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

根据我的理解,这将导致2个新的blob存在(一个用于修改的foo,一个用于修改的条).我意识到可以计算diff以显示函数从一个文件移动到另一个文件.但是我没有看到关于函数的历史如何可能与bar而不是foo相关联(反正不是自动的).

如果Git的是真正看里面单个的文件,并计算每个函数BLOB(这将是疯狂的/不可行的,因为你必须知道如何解析任何可能的语言),那么我可以看到这是可能的.

所以...声明是否正确?如果它是正确的,那么我理解中缺少什么?

小智 28

此功能通过git blame -C提供

-C选项驱动git尝试查找正在审阅的文件中添加或删除文本块与在相同更改集中修改的文件之间的匹配.附加-CC或-CCC扩展搜索范围.输入git help blame作为手册页.

尝试使用git blame -C进行测试回购,你会看到你刚刚移动的代码块来自它所属的原始文件.

  • `-CC` 和 `-CCC` 似乎不起作用......在 `git version 2.15.0.rc0` 上,我需要多次单独传递隔离的 `-C` 开关以使其记录影响。文档 _kinda_ 至少隐含地表明了这一点。然而,这个答案和其他评论表明这在过去有效。嗯。 (2认同)

vas*_*vas 14

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

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

对于默认行为,请尝试

git diff --color-moved
Run Code Online (Sandbox Code Playgroud)

该命令还需要选择,目前是no,default,plain,zebradimmed_zebra(使用git help diff以获得最新的选项及其说明).例如:

git diff --color-moved=zebra
Run Code Online (Sandbox Code Playgroud)

至于如何完成,您可以通过该功能的作者该电子邮件交换中收集一些理解.

  • @EugenKonkov是的,使用`git config`来设置`diff.colorMoved`. (2认同)

bdo*_*lan 5

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

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

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


Paŭ*_*ann 5

这个功能有点像git gui blame(+ filename).它显示文件行的注释,每个注释表示文件的创建时间和最后更改时间.对于跨文件的代码移动,它显示原始文件的提交作为创建,以及将其作为最后一次更改添加到当前文件的提交.试试吧.

我真正想要的是git log作为一些参数给出文件路径之外的行号范围,然后它将显示该代码块的历史.如果文件是正确的,那就没有这样的选择.是的,根据Linus的陈述,我也认为这样的命令应该随时可用.

  • 我刚刚第一次看到gui责备.尼斯.我开始认为也许这就是Linus的意思.并不是Git在内部存储信息,说明函数从一个文件移动到另一个文件,但是,根据Git*存储的信息,你可以*确定*函数移动了(就像git gui blame那样,或者通过差异像我在问题中提到过).如果是这样,这意味着我原来的理解是正确的,它是关于提交,树和Blob,而Git从不查看文件.但这足以让您通过分析检测功能移动.也许. (3认同)