处理重命名:svn与git与mercurial

每个VCS如何处理重命名?

我发现了很多矛盾的信息,说明git跟踪LOC(代码行)而不是文件,重命名因此对它没有任何意义。

  • Git根本不跟踪重命名,但使用启发式在合并等过程中重新发现它们。
  • Mercurial跟踪重命名(logging原始版本和原始文件)并在合并期间使用该信息。 所以你必须明确告诉hg有关hg mv重命名,或者使用hg addremove --similarity进行自动发现。 有一些关于在合并期间添加启发式的讨论。
  • Svn跟踪重命名,但我不知道它合并期间处理它们有多好(从来没有真正testing过)。

混帐

Git不同之处在于它不会重命名跟踪 ,这意味着它不需要通过使用SCM命令来重命名(或运行自动检测脚本以在提交之前标记重命名)而被告知重命名,并且不保存这样的信息在存储库中,但它会重命名检测 。 这意味着它可以在合并时使用基于文件名和文件内容相似性的启发式algorithm来查找重命名,当通过-M选项(或使用diff.renamesconfiguration选项configuration)请求diff时。

这种方法的优点如下:

  • 重命名不需要明确标记(或检测):重命名可以来自补丁,或可以通过文件pipe理器或graphics界面
  • 相似性检测algorithm可以改进,并且在提交时不会像提交时检测到重命名以标记它们那样被冻结,并且将该信息保存在存储库中; 如果它们没有被冻结在历史中,更容易处理重命名检测错误
  • 它遵循Git哲学是重要的内容; 看看git blame (和像git gui blame这样的graphics前端)可以跟随跨越文件​​边界的代码块的移动,这比通过文件重命名更通用。

请注意,pathspec过滤不适用于重命名检测; 如果你想跟踪重命名文件的历史logging使用“ git log --follow <filename>

在实践中:

Git自动检测重命名。 (顺便说一下,我听说git可以检测到当你将一个函数从一个文件移动到另一个文件时, 我的初始testing似乎表明,情况并非如此。)

使用Mercurial,你必须明确地告诉它关于重命名,或者通过hg mv ,或者hg addremove--similarity选项,或者TortoiseHg的“guess renames”选项,或者某些工具,比如VisualHg会为你重命名。 如果你想在Mercurial中使用Git方法,我已经写了一个扩展来在提交时检测重命名 ,但目前它处于非常实验阶段。

Subversion根本不处理重命名 它logging重命名为一个文件被删除,另一个文件被添加。 这意味着,例如,如果Alice更改文件,Bob将其重命名,则会发生树冲突。 无论您正在进行全面的分支和合并,还是简单地svn update发生这种情况。 重命名跟踪计划在明年的Subversion 1.8中进行。

你听到了,有点。

Git操作文件的内容,而不是文件本身,所以重命名在技术上是没有意义的。 混淆,重命名看起来像文件A消失了,文件B出现与A相同的内容。但git实际上是相当不错,搞清楚什么时候一个文件已经被重命名。

尝试一下:重命名一个文件,然后运行'git rm oldname'和'git add newname'来告诉git执行更改,然后运行'git status'来查看git认为它正在做什么 – 你会看到它告诉你的文件已经被重命名了。 不过,我不确定这意味着什么。 看看“git show”提交,你不会看到任何提及的重命名,只是从一个path删除一堆行,并添加到另一个。

或者,您也可以使用'git mv'命令重命名文件。 它不会改变git如何看待操作,它只是一步一步有效地'mv oldname newname','git rm oldname'和'git add newname'。

有关Mercurial的概述,请参阅Tonfa的答案 。

另一方面,SVN不能检测到重命名,但必须用“svn mv”命令告诉他们。 当被告知时,它会将重命名跟踪为“头等舱”更改,所以稍后查看更改日志时,您会看到更改是重命名。

不过,我不build议select基于这个特性的SVN或者mercurial。 这些工具之间有很大更重要的区别。 我首先决定是否要分布式版本控制系统(git或mercurial)或集中式版本控制系统(svn)。

还有一件尚未提到的git,除了使用启发式来确定重命名是否发生:

如果一个文件甚至是一个完整的目录树被重命名,复制或者移动,并且下面没有任何东西被修改,那么文件或者树实际上被作为同一个对象存储在版本库中,并且不会占用任何额外的空间。

如果您修改它,那么像往常一样将其作为新的对象存储。

我不确定hg和svn,但我怀疑他们的更改列表导向架构意味着他们在这种情况下行为不同。 它对使用没有任何影响,除了它可能会让你有理由避免移动或复制存储库中的巨大树木。

git跟踪内容,而不是文件。 我不确定mercurial,但svn必须明确告诉重命名