我正在研究一种新的基于编织的数据结构,用于存储版本控制历史记录。这无疑会引起一些宗教之争,争论当它出来的时候是不是正确的做事方式,但这不是我现在的问题。
我的问题是关于应该给出什么样的输出责备。当一行代码被多次添加、删除和合并时,并不总是很清楚应该归咎于哪个版本。值得注意的是,这意味着当一段代码被删除时,它曾经存在的所有记录都消失了,并且没有对删除的指责。每个和我讨论过这个问题的人都说,试图做得更好根本不值得。有时人们会说,被删除的部分后面的那一行,不管它实际上是什么,它的责任都改变了,当部分被删除时,它被修改了。如果这一段是在最后一行,那么最后一行的责备就会被改变,如果文件最终是空的,那么责备就会消失在以太中,因为实际上已经没有地方可以放置责备信息了。由于各种各样的技术原因,我不会使用这个hack,但假设继续使用这个完全没有文档记录但事实上的标准实践将是没有争议的(但请随意激怒我并将其从您的系统中删除)。
继续我的实际问题。通常,在责备每一行时,你会查看它在历史中添加和删除的完整历史,并使用三向合并(或者,在交叉合并的情况下,随机的胡扯),并根据它们之间的关系确定行是否应该在那里基于它的历史,如果它不应该,那么你将其标记为新的当前版本。如果一行代码出现在多个祖先代码中,并有不同的罪责,那么它会任意选择要继承的那个。同样,我认为继续使用这个完全没有文档记录但事实上的标准实践是没有争议的。
我的新系统的不同之处在于,它不是基于对整个历史的复杂计算,对给定行是否应该在当前版本中进行复杂的计算,而是简单地查看直系祖先,如果该行在其中任何一个中,它都会选择一个任意的人来继承责任。我之所以做出这样的改变主要是出于技术上的原因(完全有可能其他的责备实现也在做同样的事情,出于类似的技术原因和缺乏关心),但在思考之后,我实际上更喜欢新的行为,因为它比旧的更直观和可预测。大家怎么想?
我实际上写了一个被指责的实现之一(我相信是Subversion当前的实现,除非有人在过去一两年取代它)。我也帮助了一些其他人。
至少大多数责备的实现不像你描述的那样:
通常在责备每一行时,你会查看它在历史中添加和删除的完整历史,并使用三向合并(或者,在交叉合并的情况下,随机扯淡),并根据这些之间的关系确定该行是否应该基于其历史存在,如果它不应该,那么你将其标记为当前版本的新行。如果一行代码出现在多个祖先代码中,并有不同的罪责,那么它会任意选择要继承的那个。同样,我认为继续使用这个完全没有文档记录但事实上的标准实践是没有争议的。
实际上,大多数责备都比这简单得多,并且根本不需要尝试使用这些关系,但它们只是以某种任意顺序遍历父节点,使用简单的增量结构(通常是相同的内部结构,无论它们在将其转换为文本输出之前使用什么不同的算法)来查看块是否发生了变化,如果发生了变化,则归咎于它,并将该行标记为已完成。
例如,Mercurial只是首先进行迭代深度搜索,直到所有行都被指责。它没有考虑到这种关系是否使它不可能责怪正确的人。
Git确实做了一些更复杂的事情,但仍然不像你描述的那样。
Subversion做了Mercurial做的事情,但是历史图表非常简单,所以更容易。
反过来,你所建议的,实际上是他们所有人真正做的:
选择一个任意的祖先,沿着这条路径直到兔子洞完成,如果它没有让你责怪所有的行,任意选择下一个祖先,继续直到所有的责任被分配。
就个人而言,我更喜欢你的简化选项。
原因:责备并不常用
所以我不认为浪费大量的时间去做一个全面的实现是有意义的。
这是真的。指责很大程度上被证明是那些"彩虹尽头的一罐金子"的特征之一。从我们这些站在地上的人看来,这真的很酷,梦想着有一天我们只要点击一个文件,就能看到谁写了哪行代码。但现在它被广泛应用,我们大多数人已经意识到它实际上并不是很有帮助。在stackoverflow上检查blame
标签上的活动。
仅在最近几个月里,我就遇到了几十个"值得责备"的场景,在大多数情况下,我都试图先责备别人,结果发现这样做要么很麻烦,要么完全没有帮助。相反,我通过对相关文件进行简单的过滤更改日志来找到所需的信息。在某些情况下,如果我坚持不懈的话,我也可以使用Blame找到这些信息,但这将花费更长的时间。
主要问题是代码格式的变化。几乎所有事情的罪魁祸首都被列为……我!为什么?因为我负责修复换行和制表符,重新排序函数顺序,将函数拆分为单独的实用程序模块,修复注释错别字,以及改进或简化代码流程。如果不是我,其他人也在路上的某个地方做了空白或块移动。为了对任何可以追溯到我不需要责备就能记住的事情进行有意义的责备,我不得不回滚修改并重新责备。然后再次责备。一次又一次。
因此,为了使责备在大多数幸运的情况下实际上是一个有用的节省时间的方法,责备必须能够启启性地通过换行符,空格和理想情况下阻止复制/移动更改。这听起来像是一个非常高的要求,特别是在为单个文件搜索变更日志时,大多数情况下,它不会产生太多差异,您可以相当快速地手动筛选。(值得注意的例外可能是,设计糟糕的源代码树,其中90%的代码都塞在一两个巨大的文件中……但是,在如今的协作编码环境中,谁还会这么做呢?)。
结论:给它一个责备的基本实现,因为有些人喜欢在功能列表上看到"它可以责备!"然后转移到重要的事情上。享受吧!
行合并算法比开发人员还笨。如果他们不同意,那只是表明合并是错误的,而不是表明一个决策点。因此,简化后的逻辑实际上应该更正确。