所有版本控制系统都必须解决相同的基本问题:系统如何允许用户共享信息,但防止他们意外地互相干扰?用户很容易意外覆盖存储库中彼此的更改。
考虑以下情景:假设我们有两位同事,Harry 和 Sally。他们都决定同时编辑同一个存储库文件。如果 Harry 先将他的更改保存到存储库,那么(稍后)Sally 可能会意外地用她自己的新版本文件覆盖它们。虽然 Harry 的文件版本不会永远丢失(因为系统会记住每次更改),但 Harry 所做的任何更改 不会 出现在 Sally 的较新版本文件中,因为她一开始就没看到 Harry 的更改。Harry 的工作仍然有效地丢失了 - 或者至少在文件的最新版本中丢失了 - 而且很可能是意外丢失的。这绝对是我们想要避免的情况!
许多版本控制系统使用 锁定-修改-解锁 模型来解决这个问题,这是一个非常简单的解决方案。在这样的系统中,存储库一次只允许一个人更改文件。首先,Harry 必须 锁定 文件,然后才能开始对其进行更改。锁定文件很像从图书馆借书;如果 Harry 锁定了文件,那么 Sally 就无法对其进行任何更改。如果她尝试锁定文件,存储库将拒绝该请求。她所能做的就是读取文件,并等待 Harry 完成他的更改并释放他的锁定。Harry 解锁文件后,他的回合结束,现在 Sally 可以通过锁定和编辑来轮到她了。
锁定-修改-解锁 模型的问题在于它有点限制性,并且经常成为用户的障碍
锁定可能会导致管理问题。 有时 Harry 会锁定一个文件,然后就忘记了。与此同时,由于 Sally 仍在等待编辑该文件,她的手被束缚住了。然后 Harry 去度假了。现在 Sally 必须让管理员释放 Harry 的锁定。这种情况最终导致了很多不必要的延迟和时间浪费。
锁定可能会导致不必要的串行化。 如果 Harry 正在编辑文本文件的开头,而 Sally 只是想编辑同一文件的结尾呢?这些更改根本不重叠。他们可以轻松地同时编辑文件,并且不会造成太大的危害,假设更改被正确地合并在一起。在这种情况下,他们没有必要轮流。
锁定可能会产生一种虚假的安全感。 假设 Harry 锁定并编辑文件 A,而 Sally 同时锁定并编辑文件 B。但是假设 A 和 B 相互依赖,并且对每个文件所做的更改在语义上不兼容。突然,A 和 B 不再一起工作了。锁定系统无力阻止这个问题 - 但它却以某种方式提供了一种虚假的安全感。Harry 和 Sally 很容易想象,通过锁定文件,每个人都开始了一项安全、隔离的任务,从而阻止他们尽早讨论他们不兼容的更改。
Subversion、CVS 和其他版本控制系统使用 复制-修改-合并 模型作为锁定的替代方案。在这个模型中,每个用户的客户端读取存储库并创建文件或项目的个人 工作副本 。然后用户并行工作,修改他们的私有副本。最后,私有副本被合并在一起成为一个新的最终版本。版本控制系统通常协助合并,但最终由人负责使其正确发生。
这是一个例子。假设 Harry 和 Sally 各自创建了从存储库复制的同一项目的工作副本。他们并发工作,并在他们的副本中对同一个文件 A
进行更改。Sally 首先将她的更改保存到存储库。当 Harry 稍后尝试保存他的更改时,存储库会通知他,他的文件 A 已 过期。换句话说,存储库中的文件 A 自他上次复制以来已发生更改。因此,Harry 要求他的客户端将存储库中的任何新更改 合并 到他的文件 A 工作副本中。Sally 的更改很可能与他自己的更改不重叠;因此,一旦他整合了两组更改,他就将他的工作副本保存回存储库。
但是,如果 Sally 的更改 确实 与 Harry 的更改重叠怎么办?那又怎样呢?这种情况称为 冲突,通常不是什么大问题。当 Harry 要求他的客户端将最新的存储库更改合并到他的工作副本中时,他的文件 A 副本会以某种方式标记为处于冲突状态:他将能够看到两组冲突的更改,并在它们之间手动选择。请注意,软件无法自动解决冲突;只有人类才能够理解并做出必要的明智选择。一旦 Harry 手动解决了重叠的更改(可能通过与 Sally 讨论冲突!),他就可以安全地将合并后的文件保存回存储库。
复制-修改-合并 模型听起来可能有点混乱,但实际上,它运行得非常顺利。用户可以并行工作,永远不必互相等待。当他们在同一个文件上工作时,结果表明他们的大部分并发更改根本不重叠;冲突很少发生。并且解决冲突所需的时间远远少于锁定系统浪费的时间。
归根结底,一切都归结为一个关键因素:用户沟通。当用户沟通不畅时,语法和语义冲突都会增加。没有任何系统可以强迫用户进行完美的沟通,也没有任何系统可以检测语义冲突。因此,不要被锁定系统将在某种程度上防止冲突的虚假承诺所迷惑;在实践中,锁定似乎比其他任何东西都更抑制生产力。
有一种常见的情况是锁定-修改-解锁 模型效果更好,那就是当你拥有不可合并的文件时。例如,如果你的存储库包含一些图形图像,并且两个人同时更改了图像,那么就无法将这些更改合并在一起。Harry 或 Sally 其中一人将丢失他们的更改。