我可以组合文件并保留行历史记录

时间:2014-07-27 13:45:32

标签: git

我需要将两个文件合并为一个。人们可以简单地复制和粘贴。

但是我想知道git是否提供了任何机制,以便合并的文件将保留两个文件的行历史记录?因此,当git blame您仍然可以看到两个文件的历史记录时。

2 个答案:

答案 0 :(得分:2)

简短的回答是:“尝试git blame -C -C -C。如果还没有完成这项工作,那就不行。”

答案很长,如果你修改git blame本身,你可以追溯性地进行这项工作,即即使对于已经发生这种情况的代码,它也会起作用。但是,这需要一些非常聪明的工作。

git blamegit log --follow处理文件重命名的方式与git diff处理重命名和复制的方式相同,也就是说,通过heuristic。使用git diff,您可以使用一些控制旋钮来设置参数:-B-M-C--find-copies-harder-l 。这些允许您增加并限制git diff在查找复制和移动代码方面的工作量。

使用git blame,您只能获得-C选项,您可以重复此选项。 (你也得到-M,但它与git diff中的含义不同 - 差异化的重命名检测功能就像通过默认的-M选项一样开启。)

什么git diff - 因此git blame,因为它使用相同的内部差异机制,所以将每个提交视为完整的快照。

也就是说,假设您在开发中的当前位置(例如)总共有三个文件,f1f2f3。现在这三个都存在,您可以更改一个(f1),添加更改并提交。新提交仍然具有相同的三个文件:与之前的提交相比,它只有f1的修改版本。

如果您随后删除文件(例如f3)并提交,则新提交有两个文件f1f2。如果您没有修改和git add这两个文件,则它们在此新提交中与先前提交中的相同。如果你做了修改和add - 例如,如果你将所有f3的内容都包含在f2中 - 那么新提交的剩余文件就不同了以前的提交。

git diff以及git blame可以做的是注意到在“之前的提交”中有三个文件,f1f2和{ {1}},在“下一次提交”(或“当前提交”)中,只有两个文件。因此,它可以查看f3f3中是否显示f1的任何行。

如果您执行相反的操作,例如,如果您从f2f1的任何文件中获取一些代码并将其移动到新文件f3中,然后添加并提交这些更改 - 然后f4可以看到git diff之前和之前都不存在,因此它可以查看是否已从其中一个现有文件重命名或复制f4。< / p>

在所有情况下,重命名和复制检测都需要花费大量的工作。 1 因此在f4的情况下,重命名和复制检测通常完全关闭,除非你将git diff配置为diff.renames 2 truecopies;或者如果在命令行中指定copy和/或-M参数。 (Git的差异也提供-C来限制看起来有多难。 3

使用-l,重命名检测更容易,因为它一次只能处理一个文件(使用有效的git blame自动重命名)。仅在检测复制线时出现困难。在这里,-M50% - 给出一次 - 告诉-C查看修改了正在检查的文件的相同提交中已修改(包括删除)的文件。给定两次,git blame将查看在创建文件时在同一提交中修改的文件。给定三次,git blame将查看每次提交中的所有文件。也就是说,即使git blame在您要求f1查看文件git blame的更改的提交中未更改,它也会查找来自f3的副本,但只有你已经给过f1三次。


1 由于git的设计,有一种重命名/复制检测很容易。 与其他文件完全相同的文件在git的存储库中具有相同的“内部名称”,因为存储库对象的“名称”实际上只是对象数据的加密校验和。 Git假设没有两个不同的文件将校验和到相同的值。

理论上可能会出错。机会由"Birthday problem"给出。由于SHA-1是160位散列,因此任意两个文件随机冲突的可能性为2个 159 中的1个,或730个中的1个750 818 665 451 459 101 842 416 358 141 509 827 966 271 488(“短程”系统中约730个quindecillion中的1个。这不是一个大问题;我们更有可能被一个错误的小行星消灭。 : - )

2 确实设置为任何有效的布尔值“true”。请参阅git config的文档。

3 这可以配置为-C。设置为diff.renameLimit表示“无限制”。多年来,默认情况发生了变化;它是100,然后是200,目前设置为400.我认为现有限制对0没有实际影响。

答案 1 :(得分:0)

是的,您可以这样做!假设您有两个文件foobar希望合并到foobar

  1. 创建分支my_branch
  2. 结帐分支my_branch,将foo重命名为foobar,然后提交。
  3. 结帐分支master,将bar重命名为foobar,然后提交。
  4. 现在将my_branch合并为master。您会遇到大冲突。解决它并提交。
  5. 利润!

我现在需要执行此操作,效果很好!

(请注意,@ bperson已经在上面提出了这一建议)