对于软件开发项目,管理源代码的重要性只略低于编写代码的重要性。UNIX 和Linux系统提供许多种版本控制系统 (VCS) 包,每个包采用略有不同的方法解决这个问题。本文主要讨论 Mercurial 源代码管理系统(常常简称为 hg)。Mercurial 提供一个强大、现代且轻量的源代码控制解决方案,让开发人员可以轻松地更改和调试软件项目,同时维护一个稳定的中心源代码存储库,所有项目成员都可以依赖这个存储库。
UNIX 和 Linux 系统上的源代码管理
识别和跟踪多位开发人员所做的更改并把它们合并在最新的单一代码库中,这样就能够实现协作性的多开发人员项目。VCS 软件也称为修订控制系统 (RCS) 或源代码管理 (SCM) 系统,它们让多个用户可以提交对相同文件或项目的更改,而且保证一个开发人员的更改不会意外地覆盖另一个开发人员的修改。
Linux® 和 UNIX® 系统上有许多 VCS 软件,从 RCS 和 Concurrent Versions System (CVS) 等老式系统直到 Arch、Bazaar、Git、Subversion 和 Mercurial 等现代系统。与 Git 一样,Mercurial 最初是作为替代商业源代码管理系统 BitKeeper 的开放源码系统出现的,BitKeeper 过去用于维护和管理 Linux 内核的源代码。在此之后,Mercurial 发展成为流行的 VCS 系统,许多开放源码和商业项目都使用它。使用 Mercurial 的项目包括 Mozilla、IcedTea 和 MoinMoin wiki。
VCS 系统一般把每个可以进行更改和跟踪的源代码集合称为存储库。开发人员如何与存储库交互是传统 VCS 系统(比如 CVS 和 Subversion,称为集中式 VCS 系统)与更灵活的 VCS 系统(比如 Mercurial 和 Git,称为分布式 VCS 系统)之间的关键差异。开发人员使用客户机/服务器模型与集中式 VCS 系统交互,对本地源代码拷贝的更改只能推回到中心存储库中。开发人员使用对等模型与分布式 VCS 系统交互,中心存储库的任何拷贝本身都是一个存储库,可以向它们提交更改,其他任何拷贝可以共享其中的更改。分布式 VCS 系统实际上没有中心主存储库的概念,但是差不多总是通过策略定义一个主存储库,所以有一个存储库负责构建、测试和维护软件的主版本。
为什么要使用 Mercurial?
Mercurial 是一个小型但强大的分布式 VCS 系统,它很容易掌握,同时仍然提供 VCS 高级用户可能需要(或希望)使用的高级命令。由于 Mercurial 的分布式性质,很容易在本地操作项目、通过本地提交跟踪并管理自己的更改以及在需要时把这些更改推到远程存储库。
在现代的分布式 VCS 系统中,最接近于 Mercurial 的 VCS 系统是 Git。Mercurial 和 Git 之间的一些差异如下:
●多种内置的撤消操作:Mercurial 的 revert、backout 和 rollback 命令可以简便地返回到特定文件的以前版本或以前的已提交更改集。Git 只提供一个内置的 revert 命令,而且语法非常复杂。
●内置的 web 服务器:Mercurial 提供一个简单的集成的 web 服务器,很容易快速地驻留存储库,让其他用户可以从中获取更改。推操作需要忽略安全性或支持 Secure Sockets Layer (SSL) 的更复杂的设置。
●在复制/移动操作期间保存历史:Mercurial 的 copy 和 move 命令都保存完整的历史信息,而 Git 在这两种情况下不保存历史。
●分支:Mercurial 自动地共享所有分支,而 Git 要求每个存储库设置自己的分支(在本地创建它们或者把它们映射到远程存储库中的特定分支)。
●全局和本地标签:Mercurial 支持在存储库之间共享的全局标签,可以在没有分支的情况下方便地共享代码开发中特定点的相关信息。
●Windows 平台上的原生支持:Mercurial 是用 Python 编写的,而 Microsoft® Windows® 系统支持 Python。因此,可以以 Windows 可执行程序的形式使用 Mercurial(见 参考资料)。Windows 上的 Git 比较复杂,可以选用 msysGit、在 Cygwin 下使用标准的 Git 或者使用基于 web 的托管系统或存储库。
●自动的存储库收缩:Git 要求您显式地对存储库进行收缩和垃圾收集,而 Mercurial 自动地执行功能相当的操作。但是,对于相同的代码库,Mercurial 存储库往往比 Git 存储库大。
Mercurial 和 Git 的支持者还希望讨论这两个 VCS 系统的命令集的学习难度、优点和易用性。由于篇幅的限制,这里不讨论这些方面,但是在网上搜索这个主题会找到许多有意思的资料。
创建并使用 Mercurial 存储库
Mercurial 提供两种为项目源代码创建本地存储库的基本方法:显式地创建存储库或者克隆现有的远程存储库:
要想创建本地存储库,应该使用 hg init [REPO-NAME] 命令。如果在执行此命令时提供存储库名称,就会在指定的位置为此存储库创建目录。如果不提供存储库名称,就会把当前的工作目录转换为存储库。在为现有的代码库创建 Mercurial 存储库时,后一种做法很方便。
要想克隆现有的存储库,应该使用 hg clone REPO-NAME [LOCALNAME] 命令。Mercurial 支持使用 Hypertext Transfer Protocol (HTTP) 和 Secure Shell (SSH) 协议访问远程存储库。清单 1 给出一个 hg 命令示例和通过 SSH 克隆存储库时产生的输出。
清单 1. 通过 SSH 克隆 Mercurial 存储库
$ hg clone ssh://codeserver//home/wvh/src/pop3check wvh@codeserver's password: destination directory: pop3check requesting all changes adding changesets adding manifests adding file changes added 1 changesets with 12 changes to 12 files updating to branch default 12 files updated, 0 files merged, 0 files removed, 0 files unresolved remote: 1 changesets found
注意:要想使用 HTTP 协议访问 Mercurial 存储库,那么必须在此存储库中启动 Mercurial 的内部 web 服务器 (hg serve -d),或者使用 Mercurial 的 hgweb.cgi 脚本把 Mercurial 与现有的 web 服务器(比如 Apache)集成起来。在通过 HTTP 克隆存储库时,常常要指定本地存储库的名称。
创建或克隆存储库并让此存储库成为工作目录之后,就可以开始使用其中包含的代码、添加新文件等等。#p#
在 Mercurial 中获取帮助
Mercurial 的主要命令是 hg,它支持与其他 VCS 系统相似的一套子命令。执行不带参数的 hg 命令就可以看到最常用的命令的列表,输出与 清单 2 相似。
清单 2. Mercurial 提供的基本命令
Mercurial Distributed SCM basic commands: add add the specified files on the next commit annotate show changeset information by line for each file clone make a copy of an existing repository commit commit the specified files or all outstanding changes diff diff repository (or selected files) export dump the header and diffs for one or more changesets forget forget the specified files on the next commit init create a new repository in the given directory log show revision history of entire repository or files merge merge working directory with another revision pull pull changes from the specified source push push changes to the specified destination remove remove the specified files on the next commit serve export the repository via HTTP status show changed files in the working directory summary summarize working directory state update update working directory use "hg help" for the full list of commands or "hg -v" for details
这个简短的列表只显示基本的 Mercurial 命令。执行 hg help 命令可以获得完整的列表。
提示:执行 hg help COMMAND 命令,把 COMMAND 替换为任何有效的 Mercurial 命令,就可以获得任何 Mercurial 命令的详细帮助。
检查存储库状态
签入 (check in)更改是任何 VCS 系统中最常见的操作。可以使用 hg status 命令查看对存储库中的文件所有未完成的更改。例如,在创建新文件或修改现有文件之后会看到与 清单 3 相似的输出。
清单 3. Mercurial 的状态输出
$ hg status M Makefile ? hgrc.example
在这里,Makefile 文件是已经修改过的现有文件(由行开头的字母 M 表示),而 hgrc.example 文件是还没有跟踪的新文件(由行开头的问号 ? 表示)。
在存储库中添加文件
要想把 hgrc.example 文件添加到存储库跟踪的文件列表中,应该使用 hg add 命令。作为参数显式地指定一个或多个文件名,就会把这些文件添加到存储库跟踪的文件列表中。如果不指定任何文件,就会把所有新文件添加到存储库中,见 清单 4。
清单 4. 在存储库中添加文件
$ hg add adding hgrc.example
提示:要想自动地添加所有新文件并且把已经删除的所有文件标为永久删除,可以使用 Mercurial 的 hg addremove 命令。
检查存储库的状态,会看到已经添加了新文件(由行开头的字母 A 表示),见 清单 5。
清单 5. 更改之后的存储库状态
$ hg status M Makefile A hgrc.example
提交更改
签入更改是任何 VCS 系统中最常见的操作。更改代码并测试之后,就可以把这些更改提交到本地存储库了。
在第一次提交更改之前
如果这是您的第一个 Mercurial 项目,那么必须提供一些基本信息,让 Mercurial 能够识别提交这些更改的用户。如果不这么做,在尝试提交更改时会看到包含 abort: no username supplied... 的消息,更改不会提交。
添加用户信息的方法是在自己的主目录中创建文件 .hgrc。这个文件是您的个人 Mercurial 配置文件。至少需要在此文件中添加 清单 6所示的基本用户信息。
清单 6. 用户的 .hgrc 文件中必需的信息
[ui] username = Firstname Lastname
把 Firstname 和 Lastname 替换为您的名字和姓氏;把 user@domain.tld 替换为您的电子邮件地址;保存修改后的文件。
在 Linux 和 UNIX 系统上的 /etc/mercurial/hgrc 文件以及 Microsoft Windows 系统上 Mercurial 安装目录中的 Mercurial.ini 文件中,可以设置应用于所有用户的默认 Mercurial 配置值(不应该包含针对特定用户的信息)。
标准的提交过程
创建或检查 ~/.hgrc 文件之后,可以使用 hg commit 命令提交更改,可以指定希望提交的文件;如果不提供参数,就会提交所有未提交的更改,见以下示例:
$ hg commit Makefile hgrc.example committed changeset 1:3d7faeb12722
如示例输出所示,Mercurial 把与一次提交相关联的所有更改称为更改集。
当提交更改时,Mercurial 启动默认编辑器,让您能够添加提交消息。要想避免启动默认编辑器,可以在命令行上使用 -m "Message.." 选项指定提交消息。要想使用另一种编辑器,可以在 ~/.hgrc 文件的 [ui] 部分中添加一个 editor 条目,在 editor 关键字后面加上希望使用的编辑器的名称和相关联的命令行选项。例如,我通过添加条目使用非窗口模式的 emacs 作为默认编辑器,我的 ~/.hgrc 文件如 清单 7 所示。
清单 7. 用户的 .hgrc 文件中的进一步定制
[ui] username = William von Hagen editor = emacs -nw
提示:要想让 Mercurial 提供尽可能多的活动信息,可以在 Mercurial 配置文件的 [ui] 部分中添加 verbose = True 条目。
把更改推到远程存储库
如果使用一个远程存储库的克隆,在把更改提交到本地存储库之后,可能希望把这些更改推到远程存储库。这要使用 Mercurial 的 hg push 命令,见 清单 8。
清单 8. 通过 SSH 推更改
$ hg push wvh@codeserver's password: pushing to ssh://codeserver//home/wvh/src/pop3check searching for changes 1 changesets found remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 2 changes to 2 files
从远程存储库获取更改
如果您使用一个远程存储库的克隆,而其他用户也使用这个存储库,您可能希望获取他们已经完成并推到此存储库的更改。这要使用 Mercurial 的 hg pull 命令,见 清单 9。
清单 9. 通过 SSH 获取更改
$ hg pull wvh@codeserver's password: pulling from ssh://codeserver//home/wvh/src/pop3check searching for changes adding changesets adding manifests adding file changes added 1 changesets with 0 changes to 0 files (run 'hg update' to get a working copy) remote: 1 changesets found
正如这个命令的输出所示,这个命令只获取远程更改的相关信息 — 必须运行 hg update 命令显示本地存储库中的相关更改。这个命令检查更新存储库的方式,见 清单 10。
清单 10. 更新自己的存储库以显示更改
$ hg update 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
在 Mercurial 中撤消更改
Mercurial 提供下面的内置命令,它们可以轻松地撤消已提交的更改:
hg backout CHANGESET:撤消特定的更改集并创建撤消此更改集的更改集。除非在执行此命令时指定 --merge 选项,否则必须把这个更改集合并到自己的当前修订中,以便推到远程存储库。
hg revert:如果指定一个或多个文件的名称,就返回到它们的以前版本;如果指定 --all 命令行选项,就返回到所有文件的以前版本。
hg rollback:撤消最后一个 Mercurial 事务,通常是 commit、对远程存储库的 pull 或 push。只能撤消一个事务。
结束语
Mercurial 和其他分布式源代码管理系统是未来的潮流。Mercurial 是开放源码软件,有针对 Linux、UNIX、Microsoft Windows 和 Mac OS® X 预先编译的 Mercurial 版本。本文主要讨论了如何使用 Mercurial 执行一些常见的 VCS 任务,说明了使用 Mercurial 是多么容易。Mercurial 还提供许多更高级的命令和配置选项,帮助您管理源代码和定制与 Mercurial 的交互。
【编辑推荐】