46

这些 VCS 如何处理重命名?

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

4

6 回答 6

43
  • Git 根本不跟踪重命名,而是在合并等过程中使用启发式方法重新发现它们。
  • Mercurial 轨道重命名(原始版本和原始文件被记录)并在合并期间使用该信息。所以你必须明确告诉 hg 关于重命名hg mv,或者hg addremove --similarity用于自动发现。也有一些关于在合并期间添加启发式的讨论。
  • Svn 跟踪重命名,但我不知道它在合并期间处理它们的效果如何(从未实际测试过)。
于 2009-10-08T13:21:27.483 回答
23

吉特

Git 的不同之处在于它不进行重命名跟踪,这意味着它不需要通过使用 SCM 命令进行重命名(或在提交前运行自动检测脚本来标记重命名)来告知重命名,并且不保存存储库中的此类信息,但它确实重命名了 detection。这意味着它使用基于文件名和文件内容相似性的启发式算法来查找重命名,无论是在合并期间,还是在通过-M选项请求(或使用diff.renames配置选项配置)时用于差异。

这种方法的优点如下:

  • 重命名不需要明确标记(或检测):重命名可以来自补丁,或者可以通过文件管理器或图形界面完成
  • 相似性检测算法可以改进,不会像在提交前检测重命名以标记它们的情况那样在提交时冻结,并将此信息保存在存储库中;如果重命名检测错误没有被冻结在历史记录中,也更容易处理
  • 它遵循 Git 哲学,内容才是最重要的;看看git blame(以及它的图形前端,如“git gui blame”)如何跟踪代码块跨文件边界的移动,这比文件的整体重命名更通用。
  • 相同的机制负责在合并期间处理重命名;使用重命名检测意味着它可以针对合并最终基于的 3 个提交完成,并且无需仔细跟踪历史记录,注意每次重命名 - 或文件规范名称的非分布式概念

请注意,路径规范过滤不适用于重命名检测;如果您想跨重命名跟踪文件的历史记录,请使用“ git log --follow <filename>

于 2009-10-09T09:06:06.003 回答
10

在实践中:

Git 会自动检测重命名。(顺便说一句,我听说 git 可以检测到您何时将函数从一个文件移动到另一个文件。但我最初的测试似乎表明情况并非如此。)

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

Subversion 根本不处理重命名它将重命名记录为一个文件被删除和另一个文件被添加。这意味着,例如,如果 Alice 更改了一个文件,而 Bob 重命名了它,就会发生树冲突。无论您是在进行全面的分支和合并还是只是简单地svn update进行. Subversion 1.8 计划在明年某个时候推出重命名跟踪。

于 2010-06-26T07:25:30.600 回答
6

你没听错,有点。

Git 对文件的内容进行操作,而不是文件本身,因此重命名在技术上对它来说毫无意义。对 git 来说,重命名看起来就像文件 A 消失了,而文件 B 出现的内容与 A 相同。但 git 实际上非常擅长确定文件何时真正被重命名。

试试看:重命名一个文件,然后运行 ​​'git rm oldname' 和 'git add newname' 告诉 git 暂存更改,然后运行 ​​'git status' 看看 git 认为它在做什么 - 你会看到它告诉你的文件已被重命名。不过,我不确定这意味着什么。查看带有“git show”的提交,您不会看到任何提及重命名的内容,只是从一个路径中删除了一堆行并添加到另一个路径。

或者,您也可以使用“git mv”命令重命名文件。它不会改变 git 对操作的看法,它只是一步有效地执行 'mv oldname newname'、'git rm oldname' 和 'git add newname'。

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

另一方面,SVN 无法检测重命名,但必须使用“svn mv”命令告知重命名。但是,当被告知时,它会将重命名跟踪为“第一类”更改,因此稍后查看更改日志时,您会看到更改是重命名。

不过,我不建议基于此功能选择 SVN 而不是 git 或 mercurial。这些工具之间存在更大和更重要的差异。我首先要决定您是想要分布式版本控制系统(git 或 mercurial)还是集中式版本控制系统(svn)。

于 2009-10-08T13:20:58.607 回答
3

除了使用启发式方法来确定是否发生了重命名之外,还有一件关于 git 尚未提及的事情:

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

如果您修改它,那么它会像往常一样存储为一个新对象。

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

于 2009-10-10T08:10:19.530 回答
0

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

于 2009-10-08T13:05:29.183 回答