Git fast-import流的合并语义是什么?

9

我编写并维护了一个名为reposurgeon的开源工具,它可以编辑版本控制存储库历史记录,并可用于在版本控制系统之间移动项目历史记录。最近,我提供了完整的支持,以便读取Subversion转储文件和repos。但是,reposurgeon目前还做不好一件事情,那就是将通过复制完成的Subversion分支合并转换为git风格的DAG合并。

为了正确处理这部分内容,我需要更好地理解git快速导入流中合并提交的语义。我的问题是关于合并提交后哪个版本的内容应该可见。

当然,与合并提交相关的文件修改会使其内容在此处可见。我的问题是关于未被该提交触及的路径。

  1. 如果某个路径仅在合并祖先的一个提交链中具有内容,则我认为该内容应该是可见的。这是否正确?

  2. 如果某个路径在合并祖先的多个提交链中都有内容,哪个版本将可见?

  3. 如果某些路径上的文件被删除,有什么规则可以预测何时会在合并修订中删除它们?

1个回答

8

如果我理解你的问题正确的话,你想知道在将提交内容流式传输到 Git 时,fast-import 允许你采用哪些快捷方式。

从阅读 git/fast-import.c 和手册页面得出结论,fast-import 会从 "from" 命令中提供的树初始化新提交的树。当使用 "filemodify" 和其他命令来构建最终要提交的新树时,会从该状态开始。

在遇到 "merge" 命令时,fast-import 命令似乎并不会改变树的结构;如果您想要包含来自除第一个之外的父级的更改,则需要明确指定要引入的文件。但是,您可以使用标记或对象哈希为 "filemodify" 命令中的其他分支文件命名。


编辑:噢,我们来深入了解 Git 模型。

在 Git 中,提交指向一个树,该树代表被跟踪目录层次结构的完整内容,以该提交时的状态为准。提交不携带与其父提交之间的差异有关的任何信息;理论上,您可以通过比较这些树来重建差异。

合并提交仅由其具有两个或多个父提交的事实来区分于非合并提交。它仍然具有单个树,记录了从执行合并操作得到的版本中的确切内容,但不记录其作者如何将这些父提交组合成合并版本的任何信息。Git "porcelain" 命令(例如 git loggit diff)会通过魔法来重建有用的描述信息。

从概念上讲,要创建一个新的提交对象,您需要描述路径与文件内容之间的完整映射,该映射将放入该提交中。(为了使这个过程更高效和简单,需要进行大量的技巧性处理。)

git fast-import 命令为常见情况提供了一种快捷方式:通常,您正在导出的版本控制系统可以告诉您此提交是从同一分支上最近的提交中以某种差异形式形成的。在这种情况下,您可以有效地将差异编码到 fast-import 的流格式中,以便更简单和更快速地导入。

但是请记住,这只是从头开始重构整个树的快捷方式。


2
在快速导入中,它只是将第二个(或第三个、第四个等等)父提交添加到您当前构建的提交对象中。 - Jamey Sharp
@ESR 它携带着信息“这个分支(实际上是该分支末尾的提交)已经合并到这里”,这样你就可以在历史记录中看到它,而且即使你稍后删除了分支引用,分支上的提交仍然可以被引用。 - hobbs
3
一个合并提交与其他提交一样,只是具有多个父提交;与其他提交一样,它引用了一个表示提交后仓库文件状态的树形结构;在合并的情况下,这个树形结构包含了来自于所有父提交的任意自动或手动合并结果。对于 fast-import,你可以使用 filemodify (M) 命令提供这些信息。如果你使用 from + merge,那么你可以相对于 from 祖先指定更改;如果你使用 merge + merge,那么你需要从空树开始,同时提供所有文件的状态。 - hobbs
1
我现在要写一个适用于git快速导入页面的补丁。这需要进行文档记录,以便其他人不会像我一样走错路。 - ESR
@ESR 谢谢。我认为Jamey应该得到赞扬,因为他和我几乎同时想出了正确答案(并将其放入答案而不是评论中); 如果你发现他漏掉了什么,请让他知道,这样他就可以获得你的勾选标记。 - hobbs
显示剩余4条评论

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