使用 Arch 进行版本控制:维护和高级使用
Arch 是新一代版本控制系统的一部分,与旧的并发版本系统 (CVS) 及其类似系统相比,它提供了重要的架构优势。作为一个去中心化的版本控制系统,Arch 允许远程用户参与大型开发工作,而无需获得特殊的访问权限。Arch 还提供了强大的跨归档操作,鼓励第三方贡献者的参与。
本系列的前一篇文章 [LJ,2004 年 11 月] 演示了 Arch 的基本操作,例如检出代码和从远程归档创建分支。本文将介绍如何还原归档中的更改、如何将您的私有归档发布到公共镜像,以及当您忘记创建新分支时,如何将更改的副本从一个归档移动到另一个归档。
Arch 程序名为 tla。程序名 arch 被 POSIX 标准占用,该标准要求 /bin/arch 报告系统信息。运行以下命令可以找到大量信息tla help。如果您需要弄清楚特定命令(例如 commit)的参数,运行以下命令会有所帮助tla commit -H,以查看 tla commit 命令可以执行的操作。
任何版本控制系统最直接的好处之一是能够撤销一个或一组更改。每个人都会时不时犯错,因此您的工具提供优雅恢复的手段非常重要。
将检出的树返回到没有本地更改的状态的最快方法是运行tla undo。这将创建一个名为 ,,undo-1/ 的目录,其中包含所有已做的更改。如果您愿意,您可以简单地tla redo以重新应用这些更改。例如
$ tla register-archive http://www.lnx-bbc.org/arch $ tla get \ lnx-bbc-devel@zork.net--gar/lnx-bbc--stable bbc $ cd bbc/ $ echo "BIG MISTAKE" > robots.txt $ echo "#smaller change" >> Makefile $ tla undo $ tla redo
Thetla undo命令在需要暂时搁置某项工作以进行某种快速更改的“稍后考虑”时刻最有用。Arch 在执行更新或星形合并等操作时,会在内部使用 undo 和 redo 命令。
如果错误仅限于单个文件,则无需撤销整个变更集。Arch 允许您还原对单个文件所做的更改,方法是生成一个统一差异,表示该文件自上次提交以来的更改。然后,可以将此差异以反向模式馈送到 patch 程序中,这将导致更改从文件中取消修补。
$ tla file-diffs robots.txt | patch -R
如果文件被意外删除,则需要执行touch robots.txt然后再执行此命令。如果没有文件(即使是空文件),Arch 也无法从中生成文件差异。但是,当处理完整的变更集时,Arch 会更加智能。
Arch 相对于其前身 CVS 的一大优势在于,它允许创建和操作变更集。变更集是单个tla commit调用期间记录的所有编辑、重命名、添加和删除的文件以及日志条目的完整集合。
有时会提交不应提交的变更集,或者需要在实现更永久的方法之前撤销某种临时方法。在这些情况下,通过反向重放来还原变更集
$ tla replay --reverse \ jrh@zork.net--projects/foo--bar--1.0--patch-4 $ tla sync-tree \ jrh@zork.net--projects/foo--bar--1.0--patch-4
第一个命令还原 foo 树的 bar 分支的 1.0 版本中的第四个变更集,即使它不是最新的修订版。这也具有撤销该变更集的日志条目的附加效果,因此您可以使用tla sync-tree命令将提交日志恢复到应有的状态。
patch-4 变更集仍然存储在 jrh@zork.net—projects 归档中,并且该树仍然可以以该状态检出。只有代码的当前工作副本受到了上述命令的影响。当上述用户运行tla commit时,将添加一个新的变更集,其中包含 patch-4 的逆向操作。
Thetla replay命令可以用于比简单的undo更强大的操作。Arch 最引人注目的功能之一是能够从远程归档中挑选特定的变更集,而无需应用您不需要的更改。
考虑一下由 Bob 维护的项目 foo。Bob 保留了项目的稳定分支 (foo--stable) 和实验性分支 (foo--experimental)。所有发布都从稳定分支生成——foo--stable--2.4.2 是最新的。实验性分支是提供一些官方位置的冒险新功能的地方。
Alice 计划处理一些实验性代码,因此她从 Bob 的实验性分支中标记出来,以便在自己的空间中工作
$ tla my-id "Alice B. Hacker <abh@zork.net>" $ tla make-archive -l abh@zork.net--work \ sftp://abh@zork.net/home/abh/public_html/arch $ tla archive-setup foo--hackery--0.0 $ tla register-archive http://entar.net/~bob/fooarch $ tla tag \ bob@entar.net--code/foo--experimental--0.0 \ abh@zork.net--work/foo--hackery--1.0
在处理她的实验性功能的过程中,Alice 发现了一个 Bob 一定忽略的错误。修复很简单,所以她用tla undo搁置了她当前的工作,并检入了修复
$ tla undo $ vi buggy_file.c another_buggy_file.c $ tla commit M buggy_file.c M another_buggy_file.c * committed abh@zork.net--work/foo--hackery--1.0--patch-9 $ tla redo
Alice 很快完成了她的更改,并告诉 Bob 她的归档位置。Bob 认为她的代码可以接受用于实验性分支,并将其星形合并进来
$ tla get bob@entar.net--code/foo--experimental--0.0 $ cd foo--experimental--0.0/ $ tla register-archive http://zork.net/~abh/arch/ $ tla star-merge \ abh@zork.net--work/foo--hackery--1.0
在阅读 Alice 的变更日志时,Bob 意识到她修复的错误也存在于稳定分支中。因为他不想从她的 hackery 分支中获取所有实验性代码,所以 Bob 只挑选了包含错误修复的变更集
$ tla get bob@entar.net--code/foo--stable--2.4.2 $ cd foo--stable--2.4.2/ $ tla replay \ abh@zork.net--work/foo--hackery--1.0--patch-9
Alice 和 Bob 能够协同工作,尽管两位开发人员都没有共享对单个系统的访问权限。两位开发人员都没有设置任何类型的专用服务器;他们能够使用标准的库存协议,例如 HTTP、SSH 和 SFTP。Alice 的归档可以从 Internet 上的 Web 目录访问,就像 Bob 的官方归档一样,这具有优势。
Arch 为 Alice 和 Bob 提供了工具,让他们可以使用 Apache 和 OpenSSH 等不太复杂的东西来操作他们两个独立的归档以及它们之间的差异。
通过互联网发送如此多的代码总是让自由软件开发人员至少有点紧张,即使只是在他们的脑海深处。当前的同行评审系统似乎已经快速有效地解决了恶意代码提交的问题,但如果能够毫无疑问地识别每个变更集的作者,这将有所帮助。
Arch 允许开发人员以加密方式签署他们的变更集,从而可以通过信任网络验证提交者的身份。虽然这不能最终证明相关开发人员的意图,但它提高了伪造提交的门槛。
要在 Arch 中使用加密签名,您首先必须生成一个 GnuPG 密钥。
$ gpg --gen-key
不幸的是,已签名归档在功能上与未签名归档略有不同。这使得有必要为已签名提交保留单独的归档。运行tla make-archive带有 -s 开关会创建一个能够存储 GnuPG 签名的归档
$ tla make-archive -ls jrh@zork.net--signed \ ~/SIGNED-ARCHIVE $ tla my-default-archive jrh@zork.net--signed
最后,必须创建一些配置文件,以便 Arch 签署变更集并验证签名。首先,tla 发行版中包含的 awk 脚本 gpg-check.awk 必须安装在运行 Arch 的系统上的某个位置。Debian tla 软件包默认将其安装到 /usr/bin/tla-gpg-check。为了让 Arch 验证签名,文件 ~/.arch-params/signing/=default.check 应包含一行,内容为
$ mkdir ~/.arch-params/signing/ $ echo \ 'tla-gpg-check gpg_command="gpg --verify-files -"'\ > ~/.arch-params/signing/\=default.check
如果您希望根据需要从公共密钥服务器自动下载密钥,您可以添加如下参数--keyserver pgp.mit.edu --keyserver-options auto-key-retrieve到 gpg_command。这会导致 Arch 从 pgp.mit.edu 下载所需的密钥,并在 get 或 update 操作期间根据这些密钥验证归档中的签名。
为了让 Arch 自动签署您提交到使用 -s 选项创建的归档的变更集,~/.arch-params/signing/=default 文件必须是如下所示的单行,替换为您创建密钥时使用的地址
$ echo \ 'gpg --default-key "<jrh@zork.net>" --clearsign' \ > ~/.arch-params/signing/\=default
在上面的挑选更改示例中,Alice B. Hacker 为她的个人归档使用了 Web 可访问目录。这很方便,但对于断开连接的使用来说,这构成了一个问题。如果 Alice 想在长时间的飞机飞行或火车旅行中使用她的笔记本电脑工作怎么办?她要么必须使用tla changes生成变更集 tarball,要么在她连接到网络时,从她的笔记本电脑手动逐个星形合并她的各种分支到她的 Web 空间归档。幸运的是,Arch 允许创建只是其他归档的镜像的归档
$ tla make-archive -ls --mirror-from \ jrh@zork.net--signed \ sftp://jrh@zork.net/public_html/arch/
在此 make-archive 实例中,J. Random Hacker 正在 Internet 服务器上的他的 public_html 目录中创建一个归档。创建镜像归档后,它会在 tla 归档列表中显示为jrh@zork.net--signed-MIRROR。现在可以使用单个命令将数据推送到其中
$ tla archive-mirror jrh@zork.net--signed
除了将本地归档数据复制到远程系统的推送镜像之外,Arch 还允许创建远程归档本地副本的拉取镜像
$ tla make-archive -ls --mirror \ lnx-bbc-devel@zork.net--gar \ /var/tmp/gar-cache $ tla archive-mirror lnx-bbc-devel@zork.net--gar
当断开连接操作时,这可能很方便,此时本地分支可能不足以满足需求。拉取镜像允许在脱机时对远程归档的数据进行只读访问。
jrh@zork.net—signed-MIRROR 归档的一个缺点是它本身就是一个单独的已签名归档。这意味着 J. Random Hacker 必须在将每个变更集从原始归档复制到镜像时对其进行签名。
在某些情况下,这是期望的效果。例如,发布经理亲自为进入公共镜像的每个变更集担保。但是,在大多数情况下,重要的是只需将现有签名与变更集一起复制即可。这可以通过在tla archive-mirror运行的系统上创建一个特殊文件来实现
$ echo jrh@zork.net--signed > \ ~/.arch-params/signing/jrh@zork.net--signed-MIRROR
镜像非常有用,但本质上是只读的。可以提交到镜像的唯一方法是通过原始归档,通过tla archive-mirror.
考虑 Alice 的笔记本电脑镜像情况。当坐在 Amtrak 的海岸星光号的观景车厢中时,她拿出笔记本电脑并执行tla get以从 abh@zork.net--work 的本地镜像中获取一些代码。在威拉米特河谷的某个地方,她找到了灵感并完成了一个非常有用的 hack。
任何提交她的更改的尝试都会收到消息尝试直接写入镜像,这意味着提交失败。简单的解决方案是等到她到达互联网接入点,然后使用 undo 和 redo 命令
$ tla undo ,changes-to-mirror $ cd ~/real-project/ $ tla redo ~/mirror-checkout/,changes-to-mirror/ $ tla commit
如果您的更改不足以需要多个变更集,则此方法效果很好。对于较长时间的断开连接会话,您需要创建一个新的本地分支。
在太平洋海岸之旅结束后,Alice 乘坐 Zephyr 号火车前往芝加哥。这是一次更长的旅程,她发现自己在 foo--stable--2.4.2 代码的 bob@entar.net--code 的本地镜像中工作。工作几个小时后,她决定将她的更改移动到一个新分支。
首先,她在笔记本电脑上创建一个新的归档和分支
$ tla make-archive -l abh@zork.net--laptop ~/arch $ tla my-default-archive abh@zork.net--laptop $ tla archive-setup foo--laptop-hacks--1.0
接下来,她从镜像分支中标记出到她的新归档。她运行tla logsshell 反引号中的命令,这样她就不必记住她当时正在处理哪个补丁级别和版本
$ tla tag `tla logs -r -f | head -n 1` \ foo--laptop-hacks--1.0
最后,Alice 强制检出的副本相信它是她的新 laptop-hacks 分支中的第一个修订版
$ tla sync-tree foo--laptop-hacks--1.0--base-0 $ tla set-tree-version foo--laptop-hacks--1.0
此时,她已将检出的副本从只读镜像转移到笔记本电脑上托管的读写归档。
在长时间的断开连接会话之前设置镜像很像为旅行打包行李:您总是会忘记您真正需要的一样东西。如果您发现您的某些关键代码的检出副本来自 HTTP 归档,那么将笔记本电脑插入山间小屋的电源插座中会令人沮丧。
幸运的是,即使您无法访问旧的只读归档,您也可以使用一些相同的技术将检出的副本移动到新分支。
Alice 在芝加哥的一家网吧检出了一个名为 bar 的项目的副本。在返回加利福尼亚的旅程中,她决定处理该代码。又经过一个小时的惊人努力,她再次决定是时候创建自己的分支来工作了。
由于原始归档无法访问,因此无法标记分支。幸运的是,检出的树中存在大部分变更日志和历史信息,因此 Alice 暂时使用tla undo撤销了她的更改,然后强制检出的副本进入她的新分支
$ tla archive-setup bar--train-ride--1.0 $ tla set-tree-version bar--train-ride--1.0 $ tla add-log-version bar--train-ride--1.0 $ tla import
完成此操作后,Alice 运行tla redo然后tla commit。现在她在芝加哥抓取的修订版是 bar--train-ride--1.0--base-0,而她的更改是 bar--train-ride--1.0--patch-1。
虽然这种方法并不完美,但仍然可以毫无问题地与原始分支进行星形合并。如果 Alice 发现她在 bar 项目上的工作更加复杂,她很可能会与上游归档合并,并在再次找到互联网访问时创建一个适当的分支。
Nick Moffitt 是居住在旧金山湾区的 Linux 专业人士。他是 GNU/Linux 的 LNX-BBC 可启动名片发行版的构建工程师,也是 GAR 构建系统的作者。在不进行黑客攻击时,他研究城市公共交通的历史。