分布式版本控制入门(图解)

传统版本控制帮助你备份、跟踪和同步文件。分布式版本控制使得分享更改变得容易。做得好,你可以获得两全其美的效果:简单的合并和集中式发布。

分布式?常规版本控制有什么问题?

无——阅读 版本控制可视化指南 如果你想快速复习。当然, 有些人 会嘲笑你使用一个“古老”的系统。但在我这里,你仍然没问题:使用 任意 版本控制系统(VCS)是项目向前迈出的积极一步。

集中式 VCS 起源于20世纪70年代,当时程序员使用瘦客户端,并崇拜“大型机”(big iron)(你怎么能 喜欢一台当时胃口很大的机器 8位等于1字节?).

集中式很简单,以及你会首先发明的东西:一个每个人都可以签入和签出的单一地点。就像图书馆,你可以在书上涂鸦。

这种模型适用于备份、撤销和同步,但对于合并和分支(branching)人们所做的更改并不理想。随着项目增长,您希望将功能拆分为块,独立开发和测试,并逐步将更改合并到主线。实际上,分支很繁琐,因此新功能可能以巨大的签入形式出现,使得更改难以管理,一旦出错难以理清。

当然,在集中式系统中合并总是“可能”的,但不容易:你经常需要自己跟踪合并以避免重复相同的更改。分布式系统使分支和合并变得轻松,因为它们依赖于此。

请给我几张图

其他教程有大量具体的文本命令;这里是一个 可视化 概览。为刷新记忆,开发者在典型的 VCS:

centralized version control

每个人同步并检入主干:Sue添加汤,Joe添加汁,Eve添加蛋。

Sue的更改必须先进入主干,其他人才能看到。是的,理论上Sue 可以 可以创建一个新分支让别人尝试她的更改,但在常规的 VCS。

分布式版本控制系统(DVCS)

在分布式模型中,每个开发者都有自己的仓库(repo)。Sue的更改存在于她的本地仓库中,她可以与Joe或Eve共享:

distributed version control example

但这是否会成为一个没有指挥者的马戏团?不会。如果需要,每个人都可以将更改推送到一个公共仓库,这与上面的集中式模型惊人地相似。这个弗兰肯仓库包含了Sue、Joe和Eve的更改。

我希望分布式版本控制有另一个名字,例如“独立”、“联邦”或“点对点”。术语“分布式”让人联想到分布式计算,其中工作被分割到一组机器中(比如用 SETI@home 或进行 蛋白质折叠).

一个 DVCS 不像Seti@home:每个节点完全独立,共享是可选的(在Seti中你必须回传结果)。

五分钟掌握关键概念

这是基础知识;还有一份 关于补丁理论的介绍,如果你感兴趣的话。

核心概念

  • 集中式版本控制侧重于 同步、跟踪和备份文件。
  • 分布式版本控制侧重于 分享变更;每个变更都有一个 全局唯一标识符或唯一ID.
  • 记录/下载应用 变更与变更是分开的步骤(在集中式系统中,它们是同时发生的)。
  • 分布式系统没有强制结构。您可以创建“集中管理”的位置,或让所有人保持对等关系。

新术语

  • 推送:向另一个仓库发送变更(可能需要权限)
  • 拉取:从仓库获取变更

主要优势

  • 每个人都有一个本地沙盒。 您可以在本地机器上进行变更和回滚。不再有巨大的提交;您的增量历史记录在您的仓库中。
  • 它可以离线工作。 您只需要在线即可共享变更。否则,您可以愉快地留在本地机器上,提交和撤销,无论“服务器”是否宕机,或者您是否在飞机上。
  • 它很快。 差异、提交和回滚都在本地完成。无需借助不稳定的网络或服务器来请求一年前的旧版本。
  • 它很好地处理变更。 分布式版本控制系统是 构建 围绕着共享变更。每个变更都有一个GUID,便于追踪。
  • 分支和合并很简单。 由于每个开发者“都有自己的分支”,每次共享的变更都像是逆向集成。但GUID使得自动合并变更和避免重复变得容易。
  • 更少的管理。 分布式 VCS系统很容易运行;无需安装“始终运行”的服务器软件。另外, DVCS它可能不需要你“添加”新用户;你只需选择哪些 URL可以从中拉取(pull)的仓库。这可以避免大型项目中的政治麻烦。

主要缺点

  • 你仍然需要备份。 有些人声称你的“备份”就是拥有你变更的其他机器。我不这么认为——如果他们并没有全部接受呢?如果他们离线了而你有新的变更呢?对于一个 DVCS, 你仍然希望有一台机器可以推送(push)变更到上面以防万一。(在Subversion中,你通常指定一台机器来存储主仓库;对于一个 DVCS).
  • 并没有真正的“最新版本”如果没有中心位置,你不会立刻知道应该找Sue、Joe还是Eve获取最新版本。同样,中心位置有助于明确最新的“稳定”发布版本是什么。
  • 没有真正的修订号。 每个仓库都有自己的修订编号,取决于变更。相反,人们会引用变更编号: 打扰一下,你有fa33e7b这个变更吗? (记住,标识符是一个丑陋的GUID)。值得庆幸的是,你可以用有意义的名称来标记发布版本。

Mercurial 快速入门

Mercurial 是一个快速、简单的 DVCS. 它的昵称是 hg,就像元素汞(Mercury)一样。

cd project
hg init                                (create repo here)
hg add list.txt                        (start tracking file)
hg commit -m "Added file"              (check file into local repo)
hg log                                 (see history; notice guid)

changeset:   0:55bbcb7a4c24
user:        Kalid@kazad-laptop
date:        Sun Oct 14 21:36:18 2007 -0400
summary:     Added file

[edit file]
hg revert list.txt                 (revert to previous version)

hg tag v1.0                        (tag this version)
[edit file]
hg update -C v1.0                  ("update" to the older tagged version; -C forces overwrite of local copy)

一旦 Mercurial 初始化了一个目录,它看起来像这样:

distributed version control repo layout

你拥有:

  • 工作副本你当前正在编辑的文件。
  • 仓库一个目录(Mercurial中的.hg),包含所有补丁和元数据(注释、GUID、日期等)。没有中心服务器,所以数据留在你身边。

在我们的分布式示例中,Sue、Joe 和 Eve 拥有各自的仓库,具有独立的修订历史。

理解更新与合并

在学习关于 DVCS. 首先,更新分为几个步骤:

  • 获取 将变更放入仓库(推送或拉取)
  • 应用 将变更应用到文件(更新或合并)
  • 保存 新版本(提交)

其次,根据变更情况,你可以选择更新或合并:

  • 更新 在不存在歧义时发生。例如,我拉取一个只有你一直在编辑的文件的变更。该文件直接跳到最新修订版,因为没有重叠的变更。
  • 合并 在存在冲突变更时是必要的。如果我们都编辑了同一个文件,最终会得到两个“分支”(即平行宇宙)。一个世界有我的变更,另一个世界有你的变更。在这种情况下,我们(可能)希望将这些变更合并到一个单一的宇宙中。

我仍在思考在 DVCS:

distributed version control merge changes

在这种情况下,需要进行合并,因为 (+Soup) 和 (+Juice) 是对共同父级(只有“Milk”的列表)的修改。Joe 合并文件后,Sue 可以执行常规的“拉取并更新”以从 Joe 那里获取合并后的文件。她不需要自己再合并一次。

在 Mercurial 中,你可以运行:

hg incoming ../another-dir  (see pending changes)
hg pull ../another-dir      (download changes)

hg update                   (actually apply changes...)
hg merge                    (... or merge if needed)

hg commit                   (check in merged file; unite branches)

是的,“拉取-合并-提交”循环很长。幸运的是,Mercurial 提供了将多个命令合并为一个的快捷方式。尽管看起来复杂,但比在 Subversion 中手动处理合并要容易得多。

大多数合并是自动的。 当冲突出现时,通常能快速解决。Mercurial 会跟踪每个变更的父子关系(我们合并的列表有两个父级),以及每个分支的“头”或最新变更。合并前我们有两个头;之后只有一个。

组织分布式项目

以下是一种组织分布式项目的方式:

distributed version control push pull model

Sue、Joe 和 Eve 将变更提交到一个公共分支。他们可以互相交换补丁以进行简单的“同伴构建”: 嘿伙计,你能试试这些补丁吗?在推送到实验分支之前,我需要看看它是否可行。

之后,维护者可以审查并将变更从实验分支拉取到稳定分支,稳定分支包含最新版本。分布式 VCS 有助于隔离变更,同时仍然提供集中式系统的“单一来源”。开发模型有很多种,从“仅拉取”(维护者决定接收什么,用于 Linux 开发)到“共享推送”(类似于集中式系统)。分布式 VCS 为你提供 灵活性 关于项目如何维护。

实践与辛辣嘲讽助你完美

我是 DVCS 新手,但对我目前所学感到满意。我喜欢 SVN, 但看看合并变得多么容易是“有趣”的。我的建议是从Subversion开始,掌握团队协作,然后尝试分布式模型。通过适当的布局, DVCS 可以做到集中式系统能做的一切,并且附带轻松合并的好处。

在线资源

名言:

  • “有多少人做过分支并合并它?有多少人觉得这个体验愉快?”
  • “当你要做合并时,你会提前计划一周,然后腾出一天时间来执行。”
  • “有些人有5、10、15个分支”。一个是实验分支,一个是维护分支,等等。
  • “CVS — 你不提交。你在不提交的情况下做更改。你只有通过庞大的测试套件后才提交。人们会做只有一行的改动,知道它不会 可能 造成破坏。”

所以祝你好运,并小心那些圣战。欢迎在下方分享任何技巧或建议。

本系列其他文章

  1. 版本控制可视化指南
  2. 分布式版本控制入门(图解)
  3. 学习 Git 时的顿悟时刻

加入 45 万月度读者

喜欢这篇文章?还有更多内容能帮你建立持久、直观的数学理解。加入通讯以获取额外内容和最新更新。