Git如何跟踪文件之间移动的源代码?

32

显然,当您将一个函数从一个源代码文件移动到另一个文件时,git修订记录(针对新文件)可以向您展示该代码片段最初来自哪里(例如,请参阅本教程中的“查看历史记录”一节)。

这是如何工作的?

2个回答

47

它不追踪它们。这就是它的美妙之处。

Git只记录整个项目树的快照:在提交之前,所有文件看起来都是什么样子,在提交之后又变成了什么样子。我们如何从这里到那里,Git并不关心。

这使得可以在提交后编写智能工具,以从该提交中提取信息。例如,Git中的重命名检测是通过将所有删除的文件与所有新文件进行比较,并比较成对相似性度量来完成的。如果相似性度量大于x,则被视为重命名;如果在yxy<x)之间,则被视为重命名+编辑;如果低于y,则被视为独立存在。酷的是,您作为“提交考古学家”可以在事实之后指定xy应该是什么。如果提交仅记录“此文件是该文件的重命名”,这将不起作用。

检测移动内容的方法类似:将每个文件切成片段,计算所有片段之间的相似性度量,然后可以推断出在这里删除的该片段和在那里添加的非常相似的该片段实际上是从这里移至那里的同一片段。

但是,正如tonfa在他的回答中提到的,这非常昂贵,所以通常不进行。但是它可以做到,这就是重点。

顺便说一下:这几乎完全与Google Wave、EtherPad、Gobby、SubEthaEdit、ACE and Co.使用的操作转换模型相反。


35
我不太明白“这就是它的美妙之处”的含义。我的理解是,“Git不会存储文件实际发生了什么,因此您可以随时自己猜测!”但这有何美妙之处呢? - Kos
4
我认为它的美妙之处在于意识到跟踪功能不应该成为核心版本控制本身的一部分。通过“外包”这个功能,可以避免许多例如SVN的复杂性和缺点。你可以获得简单和灵活性(SVN工具通常仅限于使用最初记录的跟踪信息,尽管这可能不是代码库实际发生情况的好代表)。 - nikow
2
美妙之处在于git不假定其当前的启发式算法是正确的 - 它只保存数据,让您稍后使用任何想要的启发式算法来解释该数据。这也意味着,如果某些启发式算法计算非常昂贵,可以在共享存储库之外的其他地方完成,而不是在(可能非常繁忙的!)共享存储库上完成。 - pjz
1
@tavnab,Gmane链接已经失效,但是该邮件 还可以通过Web Archive获取 - kdb
无论美丽与否(我认为它相当不错),理解"git只是快照整个文件树"是非常基础的。它彻底改变了我的思维模式,现在很多事情都变得更加清晰明了。如果你错误地认为git记录和追踪的是"变化",那么很多事情将永远无法理解。它所做的只是快照文件树并记住历史图谱(整个文件树的)。基于此,它事后通过算法幻想(使用任何你想要的算法)可能发生的变化。但这只是一个猜测。它对变化一无所知。 - undefined
显示剩余5条评论

3

这只是一种启发式的方法。它比较文件之间的距离,并尝试查找匹配的代码块。但是,只有在将代码复制或移动到新文件时才会实现此启发式方法(否则,检查每对文件将太耗费时间)。


仅在同一提交中返回已翻译的文本? - Thilo
是的,它会在同一次提交中寻找匹配的文件。 - tonfa
3
请参阅 git diff 手册中关于 -M-C 选项的文档,以获取更详细的说明。 - Jakub Narębski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接