Git是否可以跟踪单个函数从一个文件到另一个文件的移动?如何跟踪?

yquaqz18  于 2022-11-20  发布在  Git
关注(0)|答案(5)|浏览(133)

我曾多次遇到这样的说法:如果你将一个函数从一个文件移动到另一个文件,Git可以跟踪它。例如,这条记录说:“Linus说,如果你将一个函数从一个文件移动到另一个文件,Git会告诉你这个函数在移动过程中的历史。”
但是我对Git的一些幕后设计有一点了解,我不明白这怎么可能。所以我想知道...这是一个正确的说法吗?如果是的话,这怎么可能?
我的理解是,Git将每个文件的内容存储为一个Blob,每个Blob都有一个全局唯一的标识,该标识来自其内容和大小的SHA哈希。然后,Git将文件夹表示为树。任何文件名信息都属于树,而不是Blob,因此,例如,文件重命名显示为对树的更改,而不是对Blob的更改。
因此,如果我有一个名为“foo”的文件,里面有20个函数,还有一个名为“bar”的文件,里面有5个函数,我把其中一个函数从foo移到了bar(分别得到19和6),Git怎么能检测到我把这个函数从一个文件移到了另一个文件呢?
据我所知,这将导致2个新的blob存在(一个用于修改后的foo,另一个用于修改后的bar)。我意识到可以计算diff来显示函数从一个文件移动到另一个文件。但我不明白函数的历史如何可能与bar而不是foo相关联(无论如何,不会自动)。
如果Git真的要查看单个文件的 * 内部 *,并为每个函数计算一个 *blob *(这将是疯狂的/不可行的,因为你必须知道如何解析任何可能的语言),那么我可以看到这是如何可能的。
那么......这句话到底对不对?如果是对的,那么我的理解中到底缺少了什么?

6rqinv9w

6rqinv9w1#

此功能通过git blame -C <file>提供。
-C选项会驱使git尝试在被审核文件中的文本块添加或删除与在同一个变更集中被修改的文件之间找到匹配项。额外的-C -C-C -C -C会扩展搜索范围。
在使用git blame -C的测试存储库中尝试,您将看到刚刚移动的代码块源自它所属的原始文件。
git help blame手册页:
在整个文件重命名中,会自动跟随行的原点(当前没有关闭重命名跟随的选项)。要跟随从一个文件移动到另一个文件的行,或跟随从另一个文件复制和粘贴的行等,请参阅-C-M选项。

2o7dmzc5

2o7dmzc52#

Git 2.15, git diff now supports开始,使用--color-moved选项检测移动的行。它适用于跨文件移动。
很明显,它适用于彩色终端输出。据我所知,没有选项以纯文本补丁格式指示移动,但这是有意义的。
对于默认行为,请尝试

git diff --color-moved

该命令还接受选项,当前选项为nodefaultplainzebradimmed_zebra(使用git help diff可获取最新选项及其说明)。例如:

git diff --color-moved=zebra

至于 * 如何 * 完成,您可以从this email exchange by the author of the functionality中获得一些理解。

ig9co6j1

ig9co6j13#

git gui blame(+ filename)提供了一点这个功能。它显示了文件行的注解,每一行都指出了它的创建时间和最后一次修改的时间。对于跨文件的代码移动,它将原始文件的提交显示为创建,将添加到当前文件的提交显示为最后一次修改。试试看吧。
我真正想要的是给予git log作为一个参数,除了文件路径之外,还有一个行号范围,然后它会显示这个代码块的历史。如果文档是正确的,没有这样的选项。是的,从Linus的声明中,我也认为这样的命令应该是现成的。

kokeuurv

kokeuurv4#

git实际上并不跟踪重命名。重命名只是一个删除和添加操作,仅此而已。任何显示重命名的工具都可以根据历史信息来重建它们。
因此,跟踪函数重命名是一件简单的事情,即在每次提交之后分析所有文件的差异。现有的重命名跟踪已经处理“模糊”重命名,其中对文件进行一些改变以及重命名它;这需要查看文件的内容。2查找函数的重命名也是一个简单的扩展。
我不知道基本的git工具是否真的做到了这一点--它们试图做到语言中立,而函数识别则不是语言中立的。

sqyvllje

sqyvllje5#

git diff将显示某些行从foo中消失并在bar中重新出现。如果在同一次提交中这些文件中没有其他更改,则更改将很容易被发现。
一个智能的git客户端将能够向您展示行是如何从一个文件移动到另一个文件的。一个语言感知的IDE将能够将这种变化与一个特定的函数相对应。
当一个文件被重命名时,也会发生类似的事情。它只是在一个名称下消失,在另一个名称下重新出现,但任何合理的工具都能够注意到它,并表示为重命名。

相关问题