利用版本控制
版本控制对于任何软件项目都是必须的,同样对于 Drupal 社区也不例外。版本控制追踪 Drupal 中的每个文件的所有的修改。它保存了每个版本的历史信息以及作者。你可以明确的得到一个,关于谁修改了在什么时间以及为什么修改的报告。版本控制也可以简 化向公众发布一个新版本的流程。Drupal 社区使用经过锤炼的可靠的 CVS 软件来维护它的版本历史。
版本控制的好处不仅仅适用于管理 Drupal 工程。你也可以利用 Drupal 的 CVS 来帮助维护你的基于 Drupal 的工程并且能极大的提高你的维护成本。首先,你需要改变一下你安装 Drupal 的方式。
安装带有 CVS 的 Drupal
当你从 drupal.org 的下载页面下载了 Drupal 的压缩包时,代码的这一副本完全没有了版本信息,而版本信息可以用来通知你关于你的代码的当前状态。
使用 CVS 的开发者可以快速的找到关于版本问题和应用更新的答案,而其他的开发者仍然需要下载新的版本。
注意:两种下载 Drupal 的方式的唯一看得见的区别是,使用 CVS 检出的版本包含了一个名为“CVS”的额外的文件夹,Drupal 中的所有目录里面都包含一个这样的文件夹,用来存放 CVS 信息。Drupal 的 .htaccess 文件包含了一组规则,如果你使用的是 Apache 的话,这些规则可用来自动屏蔽掉这些文件夹(一些 CVS 客户端比如 TortoiseCVS 能够自动隐藏 CVS 文件夹)。
可能会有人告诉你 CVS 版本的 Drupal 用起来并不安全,而且使用 CVS 获取的最新代码也不稳定。这是一个常见的误解,也是对两个概念的混淆。这些人在这里提到的是一个工程的 HEAD 版本,在这一 Drupal 版本中(或者使用 CVS 的其他工程),正在测试新的特性以准本发布下一个版本。而 CVS 可用来同时维护一个软件的 HEAD 版本和所有的稳定版本。
使用带有 CVS 的 Drupal
那么使用 Drupal 的这个奇特的 CVS 检出版本能够带给你哪些好处呢?
你可以对 Drupal 内核应用安全更新,在官方的安全通知发布以前你就可以进行了。我们不是已经提到了更新是件很容易的事情么?不需要下载 Drupal 完整的最新版本,你只需要简单的运行一个简洁的 CVS 命令就可以了。
能够维护对 Drupal 代码的定制化修改。修改 Drupal 的内核是最不应该做的事情,但是如果你必须修改它的话,那么修改时要用 CVS。即便是你修改了核心文件,CVS 也将聪明的帮你更新代码,这样在更新流程中你就不会在不经意间将你定制的修改覆盖掉了。
你也可以使用 CVS 来发现其他开发者对 Drupal 核心文件所做的修改。如果你的 Drupal 工作拷贝与 Drupal 服务器上干净的代码相比,存在任何不同的话,你可使用一个简单的命令,为这些不同生成一个逐行的列表。
使用 CVS:安装一个 CVS 客户端
在命令行中运行下面的命令来测试是否安装了 CVS 客户端:
$ cvs
如果你收到了一个“Command not found(命令不存在)”的错误,你可能就需要安装一个 CVS 客户端。Windows 用户可以看一下 TortoiseCVS(http://tortoisecvs.sourceforge.net/)。而 Mac 用户可参看这篇文章 http://developer.apple.com/internet/opensource/cvsoverview.html。Linux 用户,你应该自己知道做什么。
如果运行了这个 cvs 命令以后,你看到输出了下面的 CVS 文档,那么说明你已经安装了 CVS 客户端!
Usage: cvs [cvs-options] command [command-options-and-arguments]
从 CVS 检出 Drupal
我们将如何在命令行中使用 CVS。现在有许多图形化的 CVS 客户端,学会了这些基本的指令以后,你应该很容易的操纵这些基于图形化的 CVS 客户端。
用 CVS 行话来说,你将需要从集中的 CVS 资源库中检出一个 Drupal 的工作拷贝。这可能有点唠叨,但是我们想为你多准备几个新的术语。使用下面的命令就能从 CVS 服务器上获取 Drupal5:
cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout –d
~/www/drupal5 -r DRUPAL-5 drupal
让我们来分解这个命令。cvs 执行一个 CVS 客户端;也就是说它在你的计算机上运行一个名为 cvs 的程序:
cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout –d
~/www/drupal5 -r DRUPAL-5 drupal
cvs 中的选项 –d 代表着“目录(directory)”,它用来声明 CVS 资源库的位置:
cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout –d
~/www/drupal5 -r DRUPAL-5 drupal
一个资源库,用 CVS 的话来说,就是一个使用 CVS 维护的所有文件的文件树所在的位置。现在,如果资源库位于同一台计算机上的话,那么 -d 选项可以简洁成这样 cvs -d /usr/local/myrepository。然而 Drupal 的资源库位于远方的服务器上,所以我们需要生命更多的连接参数。让我们更详细的分析一下这个命令。
-d 选项的每一个参数使用冒号(:)进行分割。pserver 代表着“passwordauthenticated server(密码验证服务器)”,它也是用来连接到 Drupal 资源库的连接方法。然而,CVS 也可以连接到其他协议,比如 SSH。
接着声明了用户名和密码。对于 Drupal CVS 资源库来说两者都是:anonymous。接着符号(@)指出要连接的主机:cvs.drupal.org。最后,我们需要声明在远方的主机上资源库所在的位置:/cvs/drupal。
现在所有的参数已经全了,现在我们可以使用它来执行实际的 cvs 命令了,在这里 checkout 命令用来从资源库中取出一个 Drupal 工作拷贝:
cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout –d
~/www/drupal5 -r DRUPAL-5 drupal
不要将这里的 -d 与 cvs 命令部分全局选项的 -d 混淆了:
cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout –d
~/www/drupal5 -r DRUPAL-5 drupal
这个 -d 用来,将资源库的一个工作拷贝放到你计算机的根目录下面的 www 目录下的名为 drupal5 的目录里。这是一个可选的参数,如果没有这个参数,那么就使用资源库中原有的名字来复制工作拷贝。所以,此时,它将创建一个名为 drupal 的文件夹来存放你的来自于资源库的工作拷贝,因为资源库的名字就叫 drupal。
-r 参数代表着“版本(revision)”。一般来说,它应该是一个标签或者分支。我们将在接下来讨论什么是标签和分支(tags and branches)。在前面的命令中,我们请求名为 DRUPAL-5 的版本。
cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout –d
~/www/drupal5 -r DRUPAL-5 drupal
不幸的是,在 CVS 中,没有一个简单的方式来得到关于所有的标签或者分支的列表(所以你应该知道要请求的版本)。最简单的做法是从 Drupal 资源库中检出一个版本并运行以下命令:
cvs status -v CHANGELOG.txt
(或者将 CHANGELOG.txt 替换为其它的存在的文件)。这将列出所有用到该文件的标签和分支,这将很好的为你给出一个当前可用的分支和标签。
最后,drupal 要检出的资源库的名字。
cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout –d
~/www/drupal5 -r DRUPAL-5 drupal
注意:当你通过验证登录到一个 CVS 服务器以后,你将不需要再次验证了,因为在你的根目录下将创建一个名为 .cvspass 的文件用来存储登录信息。而接下来的针对这个资源库的 CVS 命令就不再需要这个全局的 -d 参数了。
标签和分支
当一个新的 Drupal 版本发布时,社区将在 CVS 中创建一个分支,它将是当前 HEAD 代码基础的一个重要的复制。这将允许在原始的 HEAD 代码上继续开发新特性,而同时允许社区来完善一个新的版本。例如,Drupal 5 就是这样创建的。实际规范的分支名有 DRUPAL-4-6-0、DRUPAL-4-7-0 和 DRUPAL-5(注意,Drupal5 的命名规范改变了;删除了第3个参数)(译者注:现在有了 DRUPAL-6)。
标签不是代码的复制;实际上,它们是一个特定分支某一时间的一个快照。在 Drupal 世界中,标签是用来标记 beta、bug-fix 和稳定版的。我们使用它来得到更细的版本比如 Drupal 5.1 和 5.2。规范的标签名有 DRUPAL-4-7-1、DRUPAL-4-7-2 和 DRUPAL-5-1(注意,在这里 Drupal5 的命名规范也改变了)。有时,如果将标签和分支比作树中的一部分会更好理解,HEAD 看做树干,分支看做树支,而标签可看作是树叶,如图21-1所示。
图21-1. 一个 CVS 树,其中分支为代码自己的直系,而叶子为该直系的快照。树枝代表着 CVS 分支,树叶代表着 CVS 标签
使用 CVS 更新代码
如果你想为你的站点更新到最新的 Drupal 代码上,甚至更新到下一个闪光的新版本上,你可以使用 update 命令来完成这些工作。首先测试一下 update 命令将产生哪些改变,运行下面的命令:
cvs –n update –dP
这将为你展示哪些将被修改,而实际上并未修改。要运行实际的更新操作,使用下面的命令:
cvs update –dP
这将使得你的 Drupal 工作拷贝与你正在使用的分支的最新修改保持同步。CVS 通过查看存储在 CVS 文件夹里的 CVS 元数据来获取你所使用的分支,所以你不需要每次都声明它。当资源库中存在的目录在你的工作拷贝中不存在时,-d 选项奖为你创建相应得目录。-P 将清除掉所有它们不需要的目录。
注意:在运行任何可能修改你的文件的 CVS 命令以前,一定要先备份你的数据。另一种最佳实践是,在将这些修改放到已上线的站点以前,先在一个实验站点进行 CVS 更新并解决任何潜在的文件冲突,之后再转移到线上站点。
更新到一个不同的 Drupal 版本上,仅需要修改一下 CVS update 命令就可以了。我们假定你现在用的是 Drupal 4.7。再提醒一次,在运行下面的命令以前,一定要保证你位于 Drupal 的根目录下。
更新已存在的分支,Drupal 4.7。在下面的命令中你实际上不需要声明 DRUPAL-4-7(因为 cvs 将知道你的当前分支),但是罗嗦一点也有好处,它能让你确保所做的修改就是你想要的:
cvs update -dP -r DRUPAL-4-7
警告:如果你正在更新到一个新的 Drupal 版本上,你应该首先禁用掉所有的非核心模块和主题,然后在运行 cvs 更新命令来更新 Drupal 核心。
接着,将核心代码更新到 Drupal 5:
cvs update -dP -r DRUPAL-5
对于其它的部分你仍然需要使用原有的更新流程,比如更新第3方模块和主题,以及通过访问 update.php 更新数据库,但是现在你不需要下载 Drupal 核心的新的版本并覆盖你的核心文件了。
追踪 Drupal 代码修改
想检查拟开发小组中的成员中是否有人修改核心文件?想为对核心文件所做的任何修改生成一个报告?CVS 的 diff 命令生成一个用户可读的逐行的关于代码不同之处的输出,也就是关于更新了的和修改了的部分。下面的例子使用 cvs diff –up 运行 diff 命令所得的输出:
Index: system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.402
diff -u -r1.402 system.module
— system.module 21 Mar 2007 20:55:35 -0000 1.402
+++ system.module 27 Mar 2007 19:56:18 -0000
@@ -1505,7 +1505,7 @@ function theme_system_modules($form) {
$modules = $form['validation_modules']['#value'];
foreach ($modules as $module) {
if (!isset($module->info['package'])) {
- $module->info['package'] = ‘Uncategorized’;
+ $module->info['package'] = ‘Other’;
}
$packages[$module->info['package']][$module->name] = $module->info;
}
以单个加号(+)开头的行是添加进来的,而以减号(-)开头的行是被删除了的。上面的文本提示我们有人将模块的启用/禁用页面的“Uncategorized”分类改成了了“Other”。
-u 选项意味着,Drupal 使用了统一的 diffs。这里也是用 -p 选项;这将在修改的总结段落之后输出函数的名字。当阅读这个报告时,它能帮你快速的找到代码所在的函数位置,因为并不是所有的 Drupal 开发者都能够记住该函数出现的行数:
@@ -1505,7 +1505,7 @@ function theme_system_modules($form) {
解决 CVS 冲突
如果你修改了 Drupal 的核心代码,那么当你更新 CVS 时就有产生冲突的风险。运行完 cvs 更新命令以后,将会使用一个“C”来标出带有冲突的文件,由于这些冲突的存在,你的站点也将无法继续运行(由 CVS 插入的标记冲突的文本不是合法的 PHP)。CVS 试图合并文件的新版本和旧版本,但它没有成功的完成合并,现在需要人工干预以手工的检查该文件。发生冲突时,包含冲突的文件就像下面的这样:
<<<<<<< (filename)
your custom changes here
=======
the new changes that from the repository
>>>>>>> (latest revision number in the repository)
你需要删除你不想要的,并通过删除通途指示字符来清理代码。
干净的修改核心代码
你应该尽可能的做到永不修改核心代码。但是有时候,你可能必须修改。如果你需要修改,确保能有一种方式让你精确的追踪你所做的修改。让我们看一个简 单的例子,我们将编辑 edit sites/default/settings.php。在132行,你将看到下面一行代码:
ini_set(’session.cookie_lifetime’, 2000000);
这个值控制着 cookies 的生存时间(单位为秒)。让我们假定我们数据库中的 sessions 表膨胀的太快了,所以我们需要减少这些会话的生命周期。我们可以直接修改这个值,但是如果修改了这个值,那么在接下来的 CVS 更新中我们将得到一个冲突并需要手工的解决该问题。
一个干净的解决方案是将我们想要修改的那行代码注释掉,复制该行代码并将其放在文件中原来代码的下面,然后再修改该值:
/* 原始值 -通过修改来减少cookie的生命周期
ini_set(’session.cookie_lifetime’, 2000000);
*/
ini_set(’session.cookie_lifetime’, 1000000); // 我们添加了该行。
由于原始的代码没有被修改,所以运行 CVS 就不会在此处产生一个冲突了。
获得一个 Drupal 的 CVS 帐号
Drupal 有两个 CVS 资源库。其中一个是 Drupal 核心资源库,只有很少的经过挑选的一小部分开发者才具有提交权限;另一个是第3方的资源库,用来存放位于 drupal.org 上的第3方的模块,翻译,主题,以及一些文档和为开发者存储代码片段的沙箱文件夹。如果你有一个模块、主题、或者翻译,你想把它贡献给社区的话,你需要申 请一个 CVS 帐号,从而能够访问 Drupal CVS 的第3方资源库,以将你的代码贡献给社区。关于申请的更所细节,参看 http://drupal.org/cvs-account。关于提交和分支化你贡献的模块的优秀文档,位于 Drupal 站点的 http://drupal.org/handbook/cvs/quickstart。
还有许多其它的方式为 Drupal 做出贡献,比如编写文档,参与论坛;更多方式可参看 http://drupal.org/node/22286。
创建和应用补丁
如果你想修理 bug,或者项测试一下其他人的 bug 修理情况,或者由于这个或者那个原因需要修改核心代码,那么此时你需要创建或者应用一个补丁。一个补丁就一个人和计算机都可读的文本文件,它展示了针对 Drupal 核心资源库所做修改的逐行报告。补丁有 diff 程序生成,你已经在前面的“追踪 Drupal 代码修改”部分里的例子中看到了一个例子。
创建一个补丁
下面是一个补丁的例子,它用来清理 includes/common.inc 中 t() 函数的文档:
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.591
diff -u -r1.591 common.inc
— includes/common.inc 28 Mar 2007 07:03:33 -0000 1.591
+++ includes/common.inc 28 Mar 2007 18:43:18 -0000
@@ -639,7 +639,7 @@
*
* Special variables called “placeholders” are used to signal dynamic
* information in a string, which should not be translated. Placeholders
- * can also be used for text that that may change from time to time
+ * can also be used for text that may change from time to time
* (such as link paths) to be changed without requiring updates to translations.
*
* For example:
当修改产生以后,开发者在 Drupal 根路径下运行以下命令:
cvs diff -up > common.inc.patch
这个命令得到 cvs diff 的输出并将其放到名为 common.inc.patch 的新文件中。接着开发者访问 drupal.org,并在这里报告 bug:http://drupal.org/node/100232。
应用一个补丁
补丁是由 cvs diff 或者 diff 命令的输出所创建的文件。在你创建或者下载了一个补丁以后,导航到 Drupal 的根目录并运行以下命令:
patch -p0 < path_to_patchfile/file.patch
如果你应用一个补丁时遇到了问题,可以在 http://drupal.org/node/60116 寻找相关帮助。
提示:有时,你可能想为你的已上线的站点应用一个补丁,来提高速度或者添加新的功能。做这件事的最佳实践是,创建一个补丁文件夹,用来存放应用了的 补丁。如果你还没有做这件事,你可以对文件运行“cvs diff –up”命令从而重新创建补丁。在同一个文件夹下,你还需要创建一个文本文件来说明应用每个补丁的原因。
为了工程管理混合使用 SVN 和 CVS
Drupal 的核心代码是使用了 CVS 的,然而你工程的其它部分可能完全没有使用版本控制或者可能使用了一个不同的版本控制系统。
通常的实践是,使用另一个不冲突的版本控制系统比如 Subversion(SVN),来将整个工程(包括 Drupal 和它的 CVS 元数据)存放在它自己的资源库中。它的想法是,你首先对 Drupal 核心进行 CVS 更新操作(从 cvs.drupal.org 获取更新),接着你切换到 SVN,使用 SVN 提交命令提交这些修改(这将它们放进你的 SVN 资源库中)。你可以使用这个 SVN 资源库存放任何定制的模块、主题、图片、甚至你的工程的数据库 schema。
注意:更多关于 Subversion 的信息可参看 http://subversion.tigris.org。
