﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-Joinclass Inc-文章分类-配置管理</title><link>http://www.cnitblog.com/tilan/category/4238.html</link><description>软件开发 软件配置 项目管理 软件工程</description><language>zh-cn</language><lastBuildDate>Tue, 27 Sep 2011 08:53:19 GMT</lastBuildDate><pubDate>Tue, 27 Sep 2011 08:53:19 GMT</pubDate><ttl>60</ttl><item><title>基于Trac的项目管理系统构建(Windows篇)</title><link>http://www.cnitblog.com/tilan/articles/23747.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Thu, 08 Mar 2007 05:43:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/23747.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/23747.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/23747.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/23747.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/23747.html</trackback:ping><description><![CDATA[<p>这里我们要构建一个基于Trac的项目管理系统。代码管理使用subversion，项目管理使用Trac。所需要的软件包如下：</p>
		<ul class="list1" style="PADDING-LEFT: 16px; MARGIN-LEFT: 16px">
				<li>
						<a href="http://trac.edgewall.org/wiki/TracDownload" rel="nofollow">Trac 0.10</a>，Trac程序 
</li>
				<li>
						<a href="http://httpd.apache.org/download.cgi" rel="nofollow">Apache 2.0.59</a>，Web服务器 
</li>
				<li>
						<a href="http://subversion.tigris.org/project_packages.html" rel="nofollow">subversion 1.4.3</a>，代码版本管理工具 
</li>
				<li>
						<a href="http://www.python.org/" rel="nofollow">Python 2.4.4</a>，Python解释器 
</li>
				<li>
						<a href="http://httpd.apache.org/modules/python-download.cgi" rel="nofollow">mod_python</a>，Python的Apache模块 
</li>
				<li>
						<a href="http://www.clearsilver.net/downloads/" rel="nofollow">ClearSilver 0.9.4</a>，Python的模版工具 
</li>
				<li>
						<a href="http://www.egenix.com/files/python/mxDateTime.html" rel="nofollow">mxDateTime 2.0.3</a>，Python必须库文件 
</li>
				<li>
						<a href="http://www.postgresql.org/" rel="nofollow">PostgreSQL 8.2.3</a>，数据库服务器 
</li>
				<li>
						<a href="http://pypgsql.sourceforge.net/" rel="nofollow">pyPgSQL 2.5.1</a>，Python访问PostgreSQL数据库的模块 </li>
		</ul>
		<p>很遗憾subversion现在仍然不支持最新的Apache 2.2系列，因此我们只能使用Apache 2.0系列。而pyPgSQL 2.5.1版和ClearSilver 0.9.4不支持Python 2.5，因此只能用 Python 2.4。</p>
		<p>另外，虽然Trac支持SQLite，但SQLite支持的SQL语法有限，实际应用中会有诸多不便，因此我们选择了PostgreSQL作为后台数据库。</p>
		<!-- end Pukiwiki generated code-->
		<a id="more-351">
		</a>
		<!-- begin Pukiwiki generated code-->
		<h2 id="content_8_0">安装错误时怎么办？</h2>
		<p>如果你安装过程中发现某些地方不正常，记住按照下面的方法来纠正：</p>
		<ol class="list1" style="PADDING-LEFT: 16px; MARGIN-LEFT: 16px">
				<li>查看错误信息，看是否能找到提示 
</li>
				<li>检查有无忘了装的软件 
</li>
				<li>检查httpd.conf是否有误 
</li>
				<li>修改之后记得重新启动Apache </li>
		</ol>
		<h2 id="content_8_1">安装Apache和subversion</h2>
		<p>在<a href="http://httpd.apache.org/download.cgi" rel="nofollow">Apache官方网站</a>上下载2.0.59版的msi安装包，执行即可。为方便起见，建议将Apache安装到根目录下，例如 D:\Apache。安装时的一些细节可以参考<a href="http://tech.inspiremedia.org/archives/92.html" rel="nofollow">这篇文章</a>。安装完毕后用浏览器访问 <a href="http://localhost/" rel="nofollow">http://localhost/</a> ，如能看到Apache的起始页面即安装成功。</p>
		<p>从<a href="http://subversion.tigris.org/project_packages.html" rel="nofollow">subversion</a>上下载zip包解压缩即可，目前最新版本为svn-win32-1.4.3.zip。假设解压到 D:\svn下。</p>
		<p>然后将subversion与Apache集成在一起（也可参考<a href="http://tech.inspiremedia.org/archives/70.html" rel="nofollow">这篇文章</a>）。将 D:\svn\bin 下的以下文件复制到 D:\Apache\modules 目录下：</p>
		<ul class="list1" style="PADDING-LEFT: 16px; MARGIN-LEFT: 16px">
				<li>mod_authz_svn.so 
</li>
				<li>mod_dav_svn.so </li>
		</ul>
		<p>将 D:\svn\bin 下的以下文件复制到 D:\Apache\bin 目录下：</p>
		<ul class="list1" style="PADDING-LEFT: 16px; MARGIN-LEFT: 16px">
				<li>libdb44.dll 
</li>
				<li>intl3_svn.dll </li>
		</ul>
		<p>然后建立代码仓库目录 D:\repos。</p>
		<p>然后修改 D:\Apache\Apache2\conf\httpd.conf，查找下面这一行，去掉前面的 # 号。</p>
		<pre> LoadModule dav_module modules/mod_dav.so</pre>
		<p>然后在其附近添加以下这一行：</p>
		<pre> LoadModule dav_svn_module modules/mod_dav_svn.so</pre>
		<p>之后在 httpd.conf 的末尾添加以下内容：</p>
		<pre> &lt;Location /repos&gt;
     DAV svn
     SVNParentPath D:/repos
 &lt;/Location&gt;</pre>
		<p>然后重新启动Apache。之后试着访问一个不存在的页面，如 <a href="http://localhost/abc" rel="nofollow">http://localhost/abc</a>，你会看到<strong>Not Found</strong>页面下方的内容如下：</p>
		<pre> Apache/2.0.59 (Win32) SVN/1.4.3 DAV/2 Server at localhost Port 80</pre>
		<p>如果这里显示了 SVN/1.4.3 则说明安装成功。</p>
		<h2 id="content_8_2">安装Python、mod_python和SVN binding</h2>
		<p>从<a href="http://www.python.org/" rel="nofollow">Python官方网站</a>下载Python 2.5的msi安装包进行安装，假设安装到D:\Python25目录下。</p>
		<p>从<a href="http://httpd.apache.org/modules/python-download.cgi" rel="nofollow">mod_python的下载页面</a> 上下载mod_python 3.3.0b的Win32版(mod_python-3.3.0b.win32-py2.4-Apache2.0.exe)。安装时它会问你Apache的安装位置，输入 D:\Apache\Apache2 即可。</p>
		<p>最后打开 D:\Apache\Apache2\conf\httpd.conf，查找 LoadModule，加入下面这一行：</p>
		<pre> LoadModule python_module modules/mod_python.so</pre>
		<p>然后重新启动Apache。之后试着访问一个不存在的页面，如 <a href="http://localhost/abc" rel="nofollow">http://localhost/abc</a>，你会看到<strong>Not Found</strong>页面下方的内容如下：</p>
		<pre> Apache/2.0.59 (Win32) SVN/1.4.3 mod_python/3.3.0b Python/2.4.4 DAV/2 Server at localhost Port 80</pre>
		<p>如果这里显示了 mod_python/3.3.0b Python/2.4.4 则说明安装成功。</p>
		<p>最后要安装subversion binding使Python支持subversion。到<a href="http://subversion.tigris.org/project_packages.html" rel="nofollow">刚才下载subversion的地方</a> 下载 svn-win32-1.4.3_py2.4.exe 文件并安装。</p>
		<h2 id="content_8_3">安装PostgreSQL和pyPgSQL</h2>
		<p>到<a href="http://www.postgresql.org/" rel="nofollow">PostgreSQL官方主页</a>下载最新版8.2.3(postgresql-8.2.3-1.zip)并安装。</p>
		<p>为了让Python支持PostgreSQL，我们还需要安装pyPgSQL模块。到<a href="http://pypgsql.sourceforge.net/" rel="nofollow">pyPgSQL主页</a>下载2.5.1版并安装。</p>
		<p>安装结束之后，需要将 bin 目录下的以下文件复制到 D:\Python24\Lib\site-packages\pyPgSQL\libpq 下。</p>
		<ul class="list1" style="PADDING-LEFT: 16px; MARGIN-LEFT: 16px">
				<li>libpq.dll 
</li>
				<li>comerr32.dll 
</li>
				<li>libeay32.dll 
</li>
				<li>libintl-2.dll 
</li>
				<li>libiconv-2.dll 
</li>
				<li>krb5_32.dll 
</li>
				<li>ssleay32.dll </li>
		</ul>
		<h2 id="content_8_4">安装ClearSilver和mxDateTime</h2>
		<p>在<a href="http://www.clearsilver.net/downloads/" rel="nofollow">ClearSilver的下载页面</a>选择0.9.4的py2.4版下载 (win32/clearsilver-0.9.14.win32-py2.4.exe)并安装。</p>
		<p>
				<a href="http://trac.edgewall.org/wiki/TracInstall" rel="nofollow">Trac官方文档</a>中虽然没有说明mxDateTime，但是建立项目时Trac会报错，要求你安装mxDateTime库。从<a href="http://www.egenix.com/files/python/mxDateTime.html" rel="nofollow">mxDateTime主页</a>下载并安装。</p>
		<h2 id="content_8_5">安装Trac</h2>
		<p>最后终于轮到主角Trac出场了。在<a href="http://trac.edgewall.org/wiki/TracDownload" rel="nofollow">Trac下载页面</a>上下载 Trac安装程序(trac-0.10.3.win32.exe)并安装。</p>
		<p>然后建立项目目录 D:\projects。</p>
		<p>然后打开 D:\Apache\Apache2\conf\httpd.conf，在最末尾添加以下内容：</p>
		<pre> &lt;Location /projects&gt;
     SetHandler mod_python
     PythonHandler trac.web.modpython_frontend 
     PythonOption TracEnvParentDir D:/projects
     PythonOption TracUriRoot /projects
 &lt;/Location&gt;</pre>
		<p>然后重新启动Apache，访问 <a href="http://localhost/projects/" rel="nofollow">http://localhost/projects/</a>，你会看到<strong>Available Projects</strong>字样，则说明安装成功。至此安装全部完毕。</p>
		<h2 id="content_8_6">建立项目</h2>
		<p>下面我们要建立一个实际开发中使用的项目。我们为这个项目命名为 hello。</p>
		<p>首先要建立一个代码仓库。打开命令行，输入以下命令：</p>
		<pre> D:
 cd D:\repos
 md hello
 cd hello
 D:\svn\bin\svnadmin create .</pre>
		<p>然后打开浏览器，访问 <a href="http://localhost/repos/hello/" rel="nofollow">http://localhost/repos/hello/</a> 。如果你上面的设置都正确，你将会看到下面的内容：</p>
		<pre> Revision 0: /
 ----------------------------------------------
 Powered by Subversion version 1.4.3 (r23084).</pre>
		<p>即说明代码仓库建立成功，而 <a href="http://localhost/repos/hello/" rel="nofollow">http://localhost/repos/hello/</a> 就是代码仓库的 URL。</p>
		<p>然后建立数据库。从开始菜单中启动PostgreSQL的 pg Admin III工具，新建一个数据库 hello，注意将字符编码设置为UTF8。</p>
		<p>然后建立Trac项目。打开命令行，输入以下命令：</p>
		<pre> D:
 cd D:\projects
 D:\Python24\python.exe D:\Python24\Scripts\trac-admin hello initenv</pre>
		<p>trac-admin 为Trac的管理工具，hello为项目名，initenv命令指示Trac新建一个项目。然后按照下面的内容输入：</p>
		<pre> Project Name [My Project]&gt; Hello World
 Database connection string [sqlite:db/trac.db]&gt; postgres://&lt;username&gt;:&lt;password&gt;@localhost/hello
 Repository type [svn]&gt; svn
 Path to repository [/path/to/repos]&gt; D:/repos/hello
 Templates directory [D:\Python24\share\trac\templates]&gt;</pre>
		<p>数据库连接那一行，&lt;username&gt;和&lt;password&gt;分别为安装PostgreSQL时设置的用户名和密码。如果创建失败，则需要删除 D:\projects\hello 之后再重试。</p>
		<p>最后打开浏览器，访问 <a href="http://localhost/projects/hello" rel="nofollow">http://localhost/projects/hello</a> 即可看到Trac的界面了。</p>
		<h2 id="content_8_7">设置HTTP认证</h2>
		<p>在Trac界面右上方有个Login菜单，通过这个菜单登录之后，创建bug或者做其他修改时就不用每次都输入用户名。不过这个菜单需要单独配置才能正常工作。</p>
		<p>首先我们要生成密码文件。打开命令行，输入以下命令：</p>
		<pre> D:
 cd D:\projects
 D:\Apache\Apache2\bin -c .htpasswd admin
 Automatically using MD5 format.
 New password: *****
 Re-type new password: *****
 Adding password for user admin</pre>
		<p>即可生成密码文件 .htpasswd。以后向该密码文件里追加用户只需这样即可。</p>
		<pre> D:\Apache\Apache2\bin .htpasswd user</pre>
		<p>然后编辑 httpd.conf，在最末尾加入以下内容：</p>
		<pre> &lt;LocationMatch "/projects/[^/]+/login"&gt;
     AuthType Basic
     AuthName "Trac"
     AuthUserFile D:/projects/trac.htpasswd
     Require valid-user
 &lt;/LocationMatch&gt;</pre>
		<p>然后重新启动Apache</p>
		<script type="text/javascript">
				<!--
google_ad_client = "pub-3874079075380071";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
//2007-03-19: 3G-move, 三星, 摩托罗拉, 索爱, 诺基亚
google_ad_channel = "1730597762+1709572468+0778807001+6838187825+8377398382";
//-->
		</script>
		<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
		</script><img src ="http://www.cnitblog.com/tilan/aggbug/23747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-03-08 13:43 <a href="http://www.cnitblog.com/tilan/articles/23747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>每日构建采用软件的评估报告</title><link>http://www.cnitblog.com/tilan/articles/21912.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Tue, 16 Jan 2007 03:21:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21912.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21912.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21912.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21912.html</trackback:ping><description><![CDATA[<h1 align="left">
				<font size="5">一、目的：</font>
		</h1>
		<div>选择一个符合本公司软件开发实际需求的每日构建软件，并有一定前瞻性。</div>
		<h2>二、评估项目</h2>
		<div>             1、基本功能 ：</div>
		<div>                     （1）、能调用多种版本控制软件取得代码。</div>
		<div>                     （2）、对代码进行编译，并自动管理版本号。</div>
		<div>                     （3）、对编译结果能及时并且自动反馈，编译时的任何错误都能被追踪。</div>
		<div>                     （4）、可以调用测试软件进行测试。</div>
		<div>                     （5）、构建成功完成后能作出软件“快照”，可直接供测试和发布。</div>
		<div>                     （6）、是否支持多语言编译。</div>
		<div>                     （7）、可灵活定义构建流程。</div>
		<div>              2、易用性：</div>
		<div>                            界面是否简单易用。</div>
		<div>              3、后期维护和扩展性：</div>
		<div>                     （1）、每日构建流程的创建是否简便</div>
		<div>                     （2）、项目进行中对每日构建的流程的变更是否简便。</div>
		<div>                     （3）、其他功能的支持，比如集成文件复制，删除，属性更改；压缩、ftp文件传输等。</div>
		<div>                     </div>
		<div>              4、软件费用：</div>
		<div>                     每日构建软件自身成本，以及使用和维护时产生的费用成本。</div>
		<div> </div>
		<h3>
				<font size="5">三、评估对象</font>
		</h3>
		<div>              由于时间等方面的原因，只对两个每日构建软件进行评估。</div>
		<div>       分别是FinalBuilder2和开源软件Want。</div>
		<h3>
				<font size="5">四、评估方法</font>
		</h3>
		<div>       从实际开发流程出发，从VSS取代码，进行编译和发布</div>
		<h3>
				<font size="5">五、评估结果</font>
		</h3>
		<div>       </div>
		<div>   1、针对评估项目：</div>
		<table cellspacing="0" cellpadding="0" width="569" border="0">
				<tbody>
						<tr>
								<td nowrap="" width="53">
										<div align="left">　</div>
								</td>
								<td nowrap="" width="144">
										<div align="left">　</div>
								</td>
								<td nowrap="" width="180">
										<div align="center">
												<b>FinalBuilder2</b>
										</div>
								</td>
								<td nowrap="" width="192">
										<div align="center">
												<b>Want</b>
										</div>
								</td>
								<td width="0" height="28">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="7">
										<div align="center">
												<b>基本功能</b>
										</div>
								</td>
								<td nowrap="" width="144">
										<div>支持多种版本控制软件</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">VSS、CVS、QVCS等多种，没有的可以扩充</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">不直接支持，可以改代码</div>
								</td>
								<td width="0" height="23">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>编译代码，生成版本号</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">支持</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">支持</div>
								</td>
								<td width="0" height="24">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>及时自动反馈编译结果</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">可以通过日志、e-mail等多种方式反馈</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">日志和界面</div>
								</td>
								<td width="0" height="27">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>支持测试软件</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">支持AQTIME，可以用命令行扩充</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">支持DUNIT单元测试，其余的要改代码或调用</div>
								</td>
								<td width="0" height="24">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>构建成功完成可直接供测试和发布</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">可以通过文件复制、ftp等方式直接发布</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">不直接支持，可以改代码</div>
								</td>
								<td width="0" height="30">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>支持多语言编译。</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">支持DELPHI、JAVA、.NET等</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">只支持DELPHI，但可以改代码</div>
								</td>
								<td width="0" height="23">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>灵活定义构建流程</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">可以，并可以对构建程序编写脚本事件</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">不太方便</div>
								</td>
								<td width="0" height="25">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="2">
										<div align="center">
												<b>易用性</b>
										</div>
								</td>
								<td nowrap="" width="144" rowspan="2">
										<div>界面是否简单易用</div>
								</td>
								<td nowrap="" width="180" rowspan="2">
										<div>是，完全GUI界面，也支持命令行</div>
								</td>
								<td nowrap="" width="192" rowspan="2">
										<div align="left">不太方便，控制台程序，配置时需编写XML文件</div>
								</td>
								<td width="0" height="21">
								</td>
						</tr>
						<tr>
								<td width="0" height="21">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="3">
										<div align="center">
												<b>后期维护和扩展性</b>
										</div>
								</td>
								<td nowrap="" width="144">
										<div>快速创建构建流程</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">是</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">需花时间熟悉，编写XML文件</div>
								</td>
								<td width="0" height="26">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div align="left">快速变更构建的流程</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">是</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">需花时间熟悉，修改XML文件</div>
								</td>
								<td width="0" height="25">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>其他功能的支持，比如集成文件复制，删除，属性更改；压缩、ftp文件传输等。</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">是</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">支持压缩等，但大部分要动代码</div>
								</td>
								<td width="0" height="49">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="2">
										<div align="center">
												<b>软件费用：</b>
										</div>
								</td>
								<td nowrap="" width="144" rowspan="2">
										<div align="left">费用</div>
								</td>
								<td nowrap="" width="180" rowspan="2">
										<div align="left">EUR:300,后期费用少</div>
								</td>
								<td nowrap="" width="192" rowspan="2">
										<div align="left">免费，后期费用多</div>
								</td>
								<td width="0" height="21">
								</td>
						</tr>
						<tr>
								<td width="0" height="21">
								</td>
						</tr>
				</tbody>
		</table>
		<div> </div>
		<div>2、总体描述：</div>
		<div> （1）、二者在测试时都发现小BUG，由于WANT是开源软件，迅速解决问题，但FB2有新闻组支持，第二天也得到反馈。</div>
		<div>                          在SOURCEFORGE上，对WANT的BUG提交最迟是去年10月，要么是很成熟，要么是人气不足了。后者可能性更大。</div>
		<div>（2）、WANT的架构是比较灵活的，比如对多语言编译的扩充，从代码上看，是可以在其架构上进行。</div>
		<div>              而FB2的扩充只能是通过调用批文件等或版本升级来进行，但它已经提供了大多数主流语言的编译。</div>
		<div>（3）、在构建流程的配置上，WANT是通过手写XML文件配置，虽然有它附带辅助工具DOF2WANT来自动从DOF文件生成xml，但实际情况是生成的文件并不能直接或少许改动后使用，还是有比较大的工作量。单个WANT程序只能编译一个工程文件，如果是群组，必须依次调用，日后组织困难。</div>
		<div>FB2是通过图形界面配置，直观易用，流程的顺序和是否使用通过鼠标控制就可以配置，并可以方便的把多个流程组合并顺序使用。</div>
		<div>（4）、FB2还提供了一些其他功能：构建过程中人机交换功能、注册表的读写、检测磁盘剩余空间、创建虚拟驱动器，调用InstallShield，对INTERNET的访问、运行脚本（支持四种脚本语言）等功能。</div>
		<div>（5）、从每日构建的理论来说，WANT更像是每日编译，虽然它比直接写编译批文件功能强大一些。FB2相对来说是比较完善的，它的流程化更加清晰，更人性化。</div>
		<div>WANT的优势在于开源，可以不断进行完善来达到FB2的功能和便利优势，但所需人工费用很大。</div>
		<div>因此，从性价比上看，FB2对一个想通过实施每日构建来提高软件质量和管理质量的公司来说，应该是个比较好的选择。</div><img src ="http://www.cnitblog.com/tilan/aggbug/21912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-16 11:21 <a href="http://www.cnitblog.com/tilan/articles/21912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 在ant中使用cvs功能自动完成每日构建</title><link>http://www.cnitblog.com/tilan/articles/21907.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Tue, 16 Jan 2007 02:58:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21907.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21907.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21907.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21907.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21907.html</trackback:ping><description><![CDATA[<p>实现的主要功能是：自动从cvs中check out模块，然后编译，把编译后的class打成jar，再commit到cvs服务器的指定位置。 <br />build.xml <br /></p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<div class="dp-highlighter">
						<div class="bar">
						</div>
						<ol class="dp-xml">
								<li class="alt">
										<span>
												<span class="tag">&lt;?</span>
												<span class="tag-name">xml</span>
												<span> </span>
												<span class="attribute">version</span>
												<span>=</span>
												<span class="attribute-value">"1.0"</span>
												<span class="tag">?&gt;</span>
												<span>  </span>
										</span>
								</li>
								<li class="">
										<span>
										</span>
										<span class="tag">&lt;</span>
										<span class="tag-name">project</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"gnt Auto build"</span>
										<span> </span>
										<span class="attribute">basedir</span>
										<span>=</span>
										<span class="attribute-value">"."</span>
										<span> </span>
										<span class="attribute">default</span>
										<span>=</span>
										<span class="attribute-value">"build"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- The CVSROOT value --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"cvsroot"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">":pserver:dhf:@192.168.0.200:D:/cvs_repository_z"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"cvs.password"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">""</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>     </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.dir"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"${basedir}/ywzcpt"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.module.name"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.dir"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"${basedir}/zfyw"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.module.name"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"zfyw"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"external.dir"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"${basedir}/external"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"external.module.name"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"external"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"cvs-op"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"co "</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- Initializing --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"init"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">tstamp</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>            </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">format</span>
										<span> </span>
										<span class="attribute">property</span>
										<span>=</span>
										<span class="attribute-value">"today"</span>
										<span> </span>
										<span class="attribute">pattern</span>
										<span>=</span>
										<span class="attribute-value">"yyyy-MM-dd hh:mm:ss"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">tstamp</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"${today}"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"prepare"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"init"</span>
										<span> </span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvspass</span>
										<span> </span>
										<span class="attribute">cvsroot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">password</span>
										<span>=</span>
										<span class="attribute-value">"${cvs.password}"</span>
										<span> </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"prepare"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvs</span>
										<span> </span>
										<span class="attribute">cvsRoot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">package</span>
										<span>=</span>
										<span class="attribute-value">"${external.module.name}"</span>
										<span>    </span>
								</li>
								<li class="">
										<span>             </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="comments">&lt;!-- Retrieve the ywzcpt module --&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-check-out"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">delete</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span class="tag">/&gt;</span>
										<span>    </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvs</span>
										<span> </span>
										<span class="attribute">cvsRoot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">package</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span>    </span>
								</li>
								<li class="alt">
										<span>             </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-check-out"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">delete</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span class="tag">/&gt;</span>
										<span>    </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvs</span>
										<span> </span>
										<span class="attribute">cvsRoot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">package</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span>    </span>
								</li>
								<li class="alt">
										<span>             </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- cvs checkout --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-check-out"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-check-out"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- build XSP framework --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"build"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|     Start Building GNT for compilation      |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-build"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|      End Building GNT for compilation       |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-build"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|    Start Building ywzcpt for compilation    |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span> </span>
										<span class="attribute">output</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.log"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.add"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"add ./build/log/*.log ./build/*.jar ./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.commit"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>="commit -m '${today}' ./build/log/*.log ./build/*.jar    </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"commit-build"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+     End Building ywzcpt for compilation     |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-build"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-check-out, ywzcpt-build"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|    Start Building ywzcpt for compilation    |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span> </span>
										<span class="attribute">output</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.log"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.add"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"add ./build/log/*.log ./build/*.jar ./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.commit"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>="commit -m '${today}' ./build/log/*.log ./build/*.jar    </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"commit-build"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+     End Building ywzcpt for compilation     |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"clean"</span>
										<span> </span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">delete</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span class="tag">/&gt;</span>
										<span>    </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>     </span>
								</li>
								<li class="alt">
										<span>
										</span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">project</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
						</ol>
				</div>
		</div>
		<script><![CDATA[ender_code();]]&gt;</script>
		<br />ywzcpt/build.xml片断： <br /><div class="code_title">代码</div><div class="code_div"><div class="dp-highlighter"><div class="bar"></div><ol class="dp-xml"><li class="alt"><span><span>主要实现commit功能   </span></span></li><li class=""><span></span><span class="tag">&lt;</span><span class="tag-name">target</span><span> </span><span class="attribute">name</span><span>=</span><span class="attribute-value">"commit-build"</span><span class="tag">&gt;</span><span>  </span></li><li class="alt"><span>    </span><span class="tag">&lt;</span><span class="tag-name">cvs</span><span> </span><span class="attribute">cvsRoot</span><span>=</span><span class="attribute-value">"${cvsroot}"</span><span> </span><span class="attribute">passfile</span><span>=</span><span class="attribute-value">"${root.dir}/ant-cvs.cvspass"</span><span>  </span></li><li class=""><span>         </span><span class="attribute">command</span><span>=</span><span class="attribute-value">"${ywzcpt.add}"</span><span class="tag">/&gt;</span><span>  </span></li><li class="alt"><span>    </span><span class="tag">&lt;</span><span class="tag-name">cvs</span><span> </span><span class="attribute">cvsRoot</span><span>=</span><span class="attribute-value">"${cvsroot}"</span><span> </span><span class="attribute">passfile</span><span>=</span><span class="attribute-value">"${root.dir}/ant-cvs.cvspass"</span><span>  </span></li><li class=""><span>         </span><span class="attribute">command</span><span>=</span><span class="attribute-value">"${ywzcpt.commit}"</span><span class="tag">/&gt;</span><span>  </span></li><li class="alt"><span></span><span class="tag">&lt;/</span><span class="tag-name">target</span><span class="tag">&gt;</span><span>  </span></li></ol></div></div><script><![CDATA[ender_code();]]&gt;</script><br />最后，在win2k中制定一个计划任务，就可以了。


<script type="text/javascript"><!--
google_ad_client = "pub-3874079075380071";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
//2007-03-19: 3G-move, 三星, 摩托罗拉, 索爱, 诺基亚
google_ad_channel = "1730597762+1709572468+0778807001+6838187825+8377398382";
//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script><img src ="http://www.cnitblog.com/tilan/aggbug/21907.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-16 10:58 <a href="http://www.cnitblog.com/tilan/articles/21907.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux 的版本控制-------关于体系结构、模型和示例的概述</title><link>http://www.cnitblog.com/tilan/articles/21894.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 15 Jan 2007 15:10:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21894.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21894.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21894.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21894.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21894.html</trackback:ping><description><![CDATA[<p>2006 年 11 月 06 日</p>
		<blockquote>版本控制系统或资源管理系统是现代软件开发的一个重要方面。不使用版本控制系统就如同超速驾驶一辆汽车：很刺激，也可能会更快抵达目的地，但事故却在所难免。本文概述了软件配置管理（SCM）系统及其优势，内容涵盖 CVS、Subversion、Arch 和 Git。本文还讨论了最常见的 SCM 体系结构。本文在最后给出了新出现的一些方法及这些方法与先前方法的区别。 </blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>
				<a name="N1004B">
						<span class="atitle">什么是软件配置管理？</span>
				</a>
		</p>
		<p>在学校学习的重要工具中，通常<i>不会</i> 包含 SCM。软件（或资源）控制，正如其名字所暗示的那样，是一种工具和一种相关的过程，而这种过程被用于维护源代码及其演进。SCM 提供的主要功能如下：</p>
		<ul>
				<li>在存储库（repository）中维护一个文件。 
</li>
				<li>在存储库中维护文件的修订。 
</li>
				<li>检测源更改冲突并为多个开发人员的环境提供合并。 
</li>
				<li>跟踪变更的发起方。 
</li>
				<li>为了实现一致、可重复的构建提供文件（相关修订）的配置管理。 </li>
		</ul>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" width="100%" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N1006C">
																				<b>SCM 的适用性</b>
																		</a>
																		<br />
																		<i>资源控制</i> 主要是指源代码和相关文件的控制，而<i>资源管理</i> 则可应用于任何类型的资源。包含超文本标记语言（HTML）和二进制图像文件、一般文本文档或其他任何文件的 Web 站点是 SCM 系统进行修订控制的对象。 </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>所以，SCM 允许您控制存储库中的一组文件并跟踪这些文件的修订。其他开发人员更改了存储库中的这些文件后，SCM 会标识出这些变更与您所做的变更之间存在的冲突，然后自动将其合并或通知您存在冲突。这个功能非常重要，因为它允许多个开发人员修改同一组文件。SCM 还能跟踪出谁做了何种变更。SCM 还允许您将文件按逻辑划分为相关的文件组，比如组成软件图像或可执行文件的源文件。 </p>
		<p>
				<a name="N1007B">
						<span class="atitle">SCM 的术语</span>
				</a>
		</p>
		<p>在深入研究 SCM 体系结构的类型和细节之前，先要熟悉一下术语的含义。<i>存储库</i> 是文件存储和管理的中心位置（有时又被称为<i>树</i>）。从存储库中取出文件放到本地系统的工作文件夹的过程被称作<i>签出</i>。如果变更了本地文件而又想同步变更存储库，就需要执行<i>更新</i>。如果要将变更后的文件签入到存储库，就需执行<i>提交</i>。如果所变更的文件先前已经被变更并已由别人提交，则会发生<i>合并</i>，表明两组变更集将会被合并在一起。若由于变更冲突的原因不能合并时，则必已发生了<i>冲突</i>。在此情况下，提交被拒绝，并要求开发人员手工合并变更。当提交了变更之后，就会创建此文件的一个新的<i>修订</i>。</p>
		<p>一个或多个开发人员可以对主树（存储库的当前头）或位于主树旁的单个的<i>分支</i>进行操作。这就让开发人员可以操作分支而不会影响到主树。当分支稳定后，再将分支与主树进行合并。</p>
		<p>要标记源树演进过程中的重要阶段，可以对一组文件修订应用<i>标签</i>。这会将这组文件组合成一个有用的集合（有时会用作针对于惟一构建的文件的一个发布）。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-vercon/index.html#main">
																				<b>
																						<font color="#5c81a7">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100A8">
						<span class="atitle">体系结构</span>
				</a>
		</p>
		<p>各种 SCM 间有许多的差异，其中有两种最基本的区别很值得研究：</p>
		<ul>
				<li>集中式存储库与分布式存储库 
</li>
				<li>变更集模型与快照模型 </li>
		</ul>
		<p>
				<a name="N100BA">
						<span class="smalltitle">
								<strong>
										<font face="Arial">集中式存储库与分布式存储库</font>
								</strong>
						</span>
				</a>
		</p>
		<p>现代 SCM 体系结构的最为重要的差异之一是存储库是集中式的还是分布式（分散的）。当前最为常见的体系结构是集中式存储库。这个<i>星型</i> 体系结构由中心的源存储库和工作于这个存储库的多个开发人员组成（参见图 1）。开发人员从中心存储库签出源代码到本地的沙箱内，进行变更后，将它提交回中心存储库。其他开发人员就可以再访问这些变更。</p>
		<br />
		<a name="figure1">
				<b>图 1. 在集中式体系结构中，所有开发人员都通过同一个中心存储库进行工作</b>
		</a>
		<br />
		<img height="199" alt="集中式的 SCM 体系结构" src="http://www.ibm.com/developerworks/cn/linux/l-vercon/figure1.gif" width="457" />
		<br />
		<p>中心存储库也可以创建分支，允许多个开发人员协作于针对位于存储库（但必须在 <i>mainline</i> 或 <i>tip</i> 之外）的资源的一组变更。</p>
		<p>分布式体系结构则允许开发人员为其变更创建其自己本地的存储库。本地开发人员的存储库与原始的存储库（已被分布）很相似。主要的区别是：在集中化的方式中，变更是在沙箱内完成的，而在分布式方法中则允许开发人员工作于分离的存储库。开发人员进行变更、提交变更到其本地的存储库，之后，在不影响主干的前提下，与其他开发人员的变更合并。这样，本地开发人员就使得变更集对上线（upline）开发人员可用（参见图 2）。</p>
		<br />
		<a name="figure2">
				<b>图 2. 在分散体系结构中，开发人员通过其各自的存储库员同步工作</b>
		</a>
		<br />
		<img height="679" alt="分散的 SCM 体系结构" src="http://www.ibm.com/developerworks/cn/linux/l-vercon/figure2.gif" width="566" />
		<br />
		<p>分散体系结构很有意思，因为它允许不同的开发人员在对等网络内同步工作。当工作准备好（最好是稳定）后，开发人员可以分发变更集（或修补）以使他人也可以使用这些特性。这是当今许多开源系统的模型，包括 Linux® 内核。</p>
		<p>
				<a name="N100F6">
						<span class="smalltitle">
								<strong>
										<font face="Arial">变更集模型与快照模型</font>
								</strong>
						</span>
				</a>
		</p>
		<p>早先的和现代的 SCM 的体系结构的另一个有趣的区别是 delta 变更的存储方式。它们理论上是相同的，且产生的结果也相同，但在修订的存储方式上二者却大不相同。</p>
		<p>在快照模型中，整个存储库的每个修订（带优化以减少树的大小）的全部文件都被存储。而在变更集模型中，只有 delta 被存储于修订之间，这样就创建了一个精简的存储库（参见图 3）。 </p>
		<br />
		<a name="figure3">
				<b>图 3. 快照模型和变更集模型各有所长</b>
		</a>
		<br />
		<img height="302" alt="快照模型与变更集模型的对比" src="http://www.ibm.com/developerworks/cn/linux/l-vercon/figure3.gif" width="353" />
		<br />
		<p>从图 3 可以看出，模型不同但结果却相同。在快照模型中，可以快速获得修订，但需要更多的空间来存储它们。而变更集模型需要的空间少，但需要更多时间来获得某个修订，原因是 delta 必须应用于基本修订。在本文后面的部分将介绍如何建立优化来最小化必须要应用的 delta 的数量。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-vercon/index.html#main">
																				<b>
																						<font color="#5c81a7">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10114">
						<span class="atitle">示例 SCM</span>
				</a>
		</p>
		<p>让我们来看一下按体系结构（集中或分布）划分的一些 SCM。您很快就会看到，其中一些 SCM 支持两种模型。</p>
		<p>
				<a name="N1011D">
						<span class="smalltitle">
								<strong>
										<font face="Arial">CVS</font>
								</strong>
						</span>
				</a>
		</p>
		<p>并发版本系统（Concurrent Versions System，CVS）是当今最为常用的 SCM。它是一种集中式的解决方案，采用了快照模型，开发人员使用集中式的存储库来进行软件的协作开发。CVS 十分常见而且是 Linux 发布版的一部分。其简单和方便的语法（对大多数人而言）使其迅速成为了多个或单个开发人员 SCM 的一种理想选择。</p>
		<p>清单 1 给出了一组 CVS 命令示例和简短的相关描述。要获得关于 CVS 的更多信息，请参阅 <a href="http://www.ibm.com/developerworks/cn/linux/l-vercon/index.html#resources"><font color="#5c81a7">参考资料</font></a> 部分。</p>
		<br />
		<a name="listing1">
				<b>清单 1. CVS 命令示例</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"># Create a new repository
<span class="boldcode"><strong>cvs -d /home/user/new_repository init</strong></span>

# Connect to the central repository
<span class="boldcode"><strong>export CVSROOT=:pserver:user@example.com:/cvs_root</strong></span>

# Check out a sandbox for module project from the central repository
<span class="boldcode"><strong>cvs checkout project</strong></span>

# Update a local sandbox from the central repository
<span class="boldcode"><strong>cvs update</strong></span>

# Check in changes from the local sandbox to the central repository
<span class="boldcode"><strong>cvs commit</strong></span>

# Add new files to the local sandbox (need to be committed)
<span class="boldcode"><strong>cvs add &lt;file/subdirectory&gt;</strong></span>

# Show changes made in the local sandbox
<span class="boldcode"><strong>cvs diff</strong></span></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>对于喜欢用指向-单击方式操作的用户，CVS 提供了许多开源的图形化前端以供使用，包括 WinCVS 和 TortoiseCVS（集成了 Microsoft® Windows Explorer）。</p>
		<p>尽管 CVS 被广泛采用，但它仍然有一些不足之处。CVS 不允许重命名文件，而且对一些特殊文件（如 symlink）的支持不是很好。变更可以按文件跟踪，而非按变更本身，这点十分讨厌。合并有时也会出现问题（CVS 内部会为此使用 diff3）。</p>
		<p>然而，CVS 总体而言还是很有用的，能够实现其需要实现的任务，而且所有主流的平台都支持 CVS。如果喜欢用 CVS 而又想回避其缺点，则可以考虑使用 Subversion。</p>
		<p>
				<a name="N10155">
						<span class="smalltitle">
								<strong>
										<font face="Arial">Subversion</font>
								</strong>
						</span>
				</a>
		</p>
		<p>Subversion（SVN）是为了替代 CVS 而设计的，消除了 CVS 原有的问题和缺点。与 CVS 一样，Subversion 也是一种集中化的解决方案，采用的是快照模型。它的命令也模仿了 CVS 的，但增加了一些对诸如删除文件、重命名文件或恢复为原始文件等的处理功能。</p>
		<p>Subversion 还允许远程访问，可以采用很多协议，比如超文本传输协议 (HTTP)、安全 HTTP或定制的 SVN 协议，此协议还支持通过 Secure Shell (SSH)的隧道技术。</p>
		<p>清单 2 给出了 Subversion 所支持的一些命令及 CVS 中所没有的一些扩展。要获得关于 Subversion 的更多信息，请参阅 <a href="http://www.ibm.com/developerworks/cn/linux/l-vercon/index.html#resources"><font color="#5c81a7">参考资料</font></a> 部分。很明显，Subversion 的命令集和 CVS 的很相似，这使它极受 CVS 用户的欢迎。</p>
		<br />
		<a name="listing2">
				<b>清单 2. Subversion 的命令示例</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"># Create a new repository
<span class="boldcode"><strong>svnadmin create /home/user/new_repository</strong></span>

# Check out a sandbox from the central repository
<span class="boldcode"><strong>svn checkout file:///server/svn/existing_repository new_repository</strong></span>

# Update a local sandbox from the central repository
<span class="boldcode"><strong>svn update</strong></span>

# Check in changes from the local sandbox to the central repository
<span class="boldcode"><strong>svn commit</strong></span>

# Add new files to the local sandbox (need to be committed)
<span class="boldcode"><strong>svn add &lt;file/subdirectory&gt;</strong></span>

# Show changes made in the local sandbox
<span class="boldcode"><strong>svn diff</strong></span>

# Rename a file in the local sandbox (requires commit to the repository)
<span class="boldcode"><strong>svn rename &lt;old_file&gt; &lt;new_file&gt;</strong></span>

# Remove files (also removed from repository, requires commit)
<span class="boldcode"><strong>svn delete &lt;file/subdirectory&gt;</strong></span></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>与 CVS 一样，Subversion 集成了一些图形化的前端如 ViewCVS 和 TortoiseSVN。另外也有一些工具可以把 CVS 存储库转化为 Subversion（例如 cvs2svn.py），但这些工具并不能处理复杂版本的分支和标记。和许多开源项目一样，随着时间的推移，这种情况会有所改变。Subversion 还集成了 TortoiseMerge 作为一个单独的查看器和修补程序。</p>
		<p>Subversion 解决了许多让 CVS 用户困扰的问题，比如特殊文件的版本化和自动的提交和签出。如果您喜欢用 CVS 和集中式存储库的方式，那么 Subversion 就是您所需的 SCM。</p>
		<p>现在让我们先放下对集中方式的讨论，看看被人们视为 SCM 未来的协作式分散存储库。</p>
		<p>
				<a name="N10191">
						<span class="smalltitle">
								<strong>
										<font face="Arial">Arch</font>
								</strong>
						</span>
				</a>
		</p>
		<p>Arch 是分散 SCM 的规范，它提供许多不同的实现，包括 ArX、Bazaar、GNU arch 和 Larch。Arch 不仅可以作为一种分散 SCM 运作，如 <a href="http://www.ibm.com/developerworks/cn/linux/l-vercon/figure2.gif"><font color="#5c81a7">图 2</font></a> 所示，还可使用变更集模型（参见 <a href="http://www.ibm.com/developerworks/cn/linux/l-vercon/figure3.gif"><font color="#5c81a7">图 3</font></a>）。Arch SCM 是开源开发的一种很流行的方法，因为开发人员可在单独的存储库上进行开发，同时又能够控制全部资源。这是因为分布式存储库就是具有修订控制的实际存储库。可以在本地存储库利用变更创建一个修补来供上游的开发人员使用。这就是分散模型的真正的强势所在。</p>
		<p>与 Subversion 相似，Arch 解决了 CVS 中所存在的许多问题，包括元数据的变更，例如修订文件许可、处理文件删除和重命名以及自动的签入（将签入组在一起而非作为单独的文件）。</p>
		<p>清单 3 中显示了 Arch SCM 中的一些常见命令，还给出了 GNU arch，因为它是由 Arch 的设计者 Tom Lord 开发的。GNU arch 提供了 SCM 应有的一些基本功能，包括 Subversion 中的一些新特性。</p>
		<br />
		<a name="listing3">
				<b>清单 3. GNU arch (tla) 的命令示例</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"># Register a public archive
<span class="boldcode"><strong>tla register-archive http://www.mtjones.com/arch</strong></span>

# Check out a local repository from the upstream repository
<span class="boldcode"><strong>tla get project@mtjones.com--dev/project--stable myproject</strong></span>

# Update from the local repository
<span class="boldcode"><strong>tla update</strong></span>

# Check in changes to the local repository
<span class="boldcode"><strong>tla commit</strong></span>

# Add new files to the local repository (need to be committed)
<span class="boldcode"><strong>tla add &lt;file&gt;</strong></span>

# Show changes made in the local repository (patch format)
<span class="boldcode"><strong>tla what-changed</strong></span>

# Rename a file in the local repository (requires commit to the repository)
<span class="boldcode"><strong>tla mv &lt;old_file&gt; &lt;new_file&gt;</strong></span>

# Remove files (also removed from repository, requires commit)
<span class="boldcode"><strong>tla rm &lt;file&gt;</strong></span></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Arch 还允许用 <code>star-merge</code> 合并来自上游存储库的变更。为了最小化必须应用到基本修订的修补的数量（根据变更集模型）， <code>cacherev</code> 命令将会在存储库中创建基本修订的一个新的快照。 </p>创建基本修订的一个新快照 
<p>Arch 的优势之一是虽然它是为分散操作所设计的，但也可以用于集中存储库范例。</p><p><code>tla</code> 用户对其不满之处是它太过复杂。其他的 Arch 实现，例如 <code>baz</code> 则非常简单。如果 <code>tla</code> 不能满足要求，可以尝试使用后者。</p><p>现在让我们来看一下最后一个分散式的 SCM，它由 Linux 内核的维护者 Linus Torvalds 本人编写。</p><p><a name="N101E7"><span class="smalltitle"><strong><font face="Arial">Git</font></strong></span></a></p><p>Git SCM 由 Linus Torvalds 开发，用来替代 Bitkeeper SCM（参阅 <a href="http://www.ibm.com/developerworks/cn/linux/l-vercon/index.html#resources"><font color="#5c81a7">参考资料</font></a> 部分）。 它非常简单，是一种分散式的基于变更集的 SCM 且用作 Linux 内核的 SCM。它使用文件组模型而非跟踪单个的文件。使用 SHA1 压缩并混编变更集以验证其完整性（参见清单 4）。 </p><br /><a name="listing4"><b>清单 4. Git 的命令示例</b></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode"># Get a Git repository (first time)
git clone \
  rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git \
  linux-2.6

rsync -a \
  --progress rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/ \
  .git/

# Update a Git repository from the defined upstream Git repository
<span class="boldcode"><strong>git pull rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git</strong></span>

# Checkout from the Git repository into the local working repository
<span class="boldcode"><strong>git checkout</strong></span>

# Update from the local Git repositor3
<span class="boldcode"><strong>git-update-cache</strong></span>

# Commit changes to the local Git repository
<span class="boldcode"><strong>git commit</strong></span>

# Add new files to the local repository
<span class="boldcode"><strong>git-update-cache --add &lt;file&gt;</strong></span>

# Show changes made to the local working directory
<span class="boldcode"><strong>git diff</strong></span>

# Remove files (requires commit)
<span class="boldcode"><strong>git-update-cache --remove &lt;file&gt;</strong></span></pre></td></tr></tbody></table><br /><p>Git SCM 在其自己的 Git 存储库内是自托管的，这意味着您必须引导 Git 来将其安装到本机。Git 的命令集与您到目前为止看到的那些命令十分类似，而且相对简单。</p><p>您可能会问：“为什么不使用现有的 SCM 中的一种呢？” 问得很好。 Git 非常有趣，吸引着许多 Linux 内核黑客，所以它很可能成为下一个主流的 SCM。Linus 将 Git 描述为一个高速的目录内容管理器，虽然它所做的工作不多但完成得十分高效。 </p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-vercon/index.html#main"><b><font color="#5c81a7">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N1021A"><span class="atitle">收益</span></a></p><p>无论您使用何种 SCM，都会获得一些普遍的收益。使用 SCM，可以跟踪文件中的变更来判断变更对软件的影响程度。当发生不正确的变更时，可以发现这些变更并将它们恢复回原始资源中。可以组合文件修订集并标记它们来制作发布，而发布又可以在任何时间签出以供重复构建代码的特定发布（SCM 的要求）。</p><p>不管使用集中式存储库还是分布式存储库，使用快照模型还是变更集模型，所带来的收益都是相同的。因为任何现代软件开发项目都必须要有 SCM，所以越早越多地使用它们就会受益越多。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-vercon/index.html#main"><b><font color="#5c81a7">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N10226"><span class="atitle">前景展望</span></a></p><p>本文只讨论了现在最为常用的 SCM 的一些最基础的知识。还有许多其他的开源 SCM 可以使用，例如 Aegis、Bazaar-NG、DARCS 和 Monotone。当然，SCM 也引起了一些争论，而这些争论通常很难有正确的答案。如果使用一种工具后效率极高，那就使用这种工具吧！SCM 大多时候都用在团队开发的情况下，而很少用于孤立的个人开发的环境中（除非您是个独断专行的老板，喜欢自己做所有决定）。所以，您尽可以尝试所有的可能性来熟悉一些不同的风格。SCM 是软件开发中的必需工具，也是您的开发工具箱中的必备部分。 </p><br /><br /><p><a name="resources"><span class="atitle">参考资料 </span></a></p><b>学习</b><br /><ul><li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/library/l-vercon/?S_TACT=105AGX52&amp;S_CMP=cn-a-l" target="_blank"><font color="#5c81a7">英文原文</font></a> 。<br /><br /></li><li>在 LinuxMafia，浏览大量的 Linux <a href="http://linuxmafia.com/faq/Apps/scm.html"><font color="#5c81a7">SCM</font></a> 。 <br /><br /></li><li>阅读 David Wheeler 关于开源 SCM 的 <a href="http://www.dwheeler.com/essays/scm.html"><font color="#5c81a7">有趣论文</font></a>，内容涵盖 CVS、Subversion、Arch 和 Monotone。 <br /><br /></li><li>Nick Moffitt 在 <a href="http://www.linuxjournal.com/node/7671/print"><font color="#5c81a7">Revision Control with Arch: Introduction to Arch</font></a>（Linux Journal，2004 年 11 月）中为我们介绍了 Arch 的一个十分有趣的方面。 <br /><br /></li><li>Tom Copeland 在 “<a href="http://www.ibm.com/developerworks/cn/java/j-statcvs/"><font color="#5c81a7">StatCVS 提供了对 CVS 储存库活动的深入观察</font></a>”（developerWorks，2005 年 2 月）一文中展示了如何用 StatCVS 从 CVS 历史数据中创建图表。 <br /><br /></li><li>在 “<a href="http://www.eweek.com/article2/0,1895,1788876,00.asp"><font color="#5c81a7">Torvalds Gives Inside Skinny on Git</font></a>”（eWeek，2005 年 4 月）一文中向 Linus 本人学习 Git 的更多知识。 <br /><br /></li><li>在 <a href="http://linux.yyz.us/git-howto.html"><font color="#5c81a7">Kernel Hackers' Guide</font></a> 中了解 Git。 <br /><br /></li><li>这里的 <a href="http://better-scm.berlios.de/comparison/comparison.html"><font color="#5c81a7">版本控制系统比较</font></a> 提供了多种 SCM 间的对比。 <br /><br /></li><li>通过本文作者编著的 <a href="http://www.charlesriver.com/Books/BookDetail.aspx?productID=91525"><font color="#5c81a7">GNU/Linux Application Programming</font></a> 一书（Charles River Media，2005 年 1 月）全面学习 Linux 编程，从工具到 API 等等。 <br /><br /></li><li>要获得关于 CVS 的更详尽的信息，请参阅 <a href="http://www.ibm.com/developerworks/cn/views/linux/tutorials.jsp?cv_doc_id=87496"><font color="#5c81a7">开发者和爱好者的 CVS</font></a>（developerWorks，2001 年 3 月）。 <br /><br /></li><li>在 <a href="http://www.ibm.com/developerworks/cn/linux/"><font color="#5c81a7">developerWorks Linux 专区</font></a>可以找到为 Linux 开发人员准备的更多资源。 <br /><br /></li><li>随时关注 <a href="http://www.ibm.com/developerworks/offers/techbriefings/?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">developerWorks 技术事件和网络广播</font></a>。 </li></ul><br /><b>获得产品和技术</b><br /><ul><li><a href="http://www.nongnu.org/cvs/"><font color="#5c81a7">CVS</font></a> 是应用最早和最广泛的 SCM 之一。 <br /><br /></li><li><a href="http://subversion.tigris.org/"><font color="#996699">Subversion</font></a> 是 CVS 的一个强有力的替代品。 <br /><br /></li><li><a href="http://www.gnu.org/software/gnu-arch"><font color="#5c81a7">GNU arch</font></a> 是由 Tom Lord 完成的 Arch SCM 规范的一个实现。 <br /><br /></li><li>参阅 sourceforge 的 <a href="http://aegis.sourceforge.net/"><font color="#5c81a7">Aegis</font></a>，这是一个基于事务的 SCM。 <br /><br /></li><li>关于 IBM 的 SCM，请访问 <a href="http://www.ibm.com/software/rational/offerings/scm.html"><font color="#5c81a7">Rational change and configuration management</font></a> 页面。 <br /><br /></li><li><a href="http://www.ibm.com/developerworks/offers/sek/?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">订购 SEK for Linux</font></a>，这有两张 DVD，含最新的 IBM for Linux 的试用软件，包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。 <br /><br /></li><li>使用 <a href="http://www.ibm.com/developerworks/downloads/?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">IBM 试用软件</font></a> 构建您的下一个 Linux 开发项目，这些软件可以从 developerWorks 直接下载。 <br /><br /></li></ul><br /><b>讨论</b><br /><ul><li>通过参与 <a href="http://www.ibm.com/developerworks/blogs/?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">developerWorks blogs</font></a> 加入 <a href="http://www.ibm.com/developerworks/community?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">developerWorks 社区</font></a>。 <br /></li></ul><script type="text/javascript"><!--
google_ad_client = "pub-3874079075380071";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
//2007-03-19: 3G-move, 三星, 摩托罗拉, 索爱, 诺基亚
google_ad_channel = "1730597762+1709572468+0778807001+6838187825+8377398382";
//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script><img src ="http://www.cnitblog.com/tilan/aggbug/21894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-15 23:10 <a href="http://www.cnitblog.com/tilan/articles/21894.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件工程</title><link>http://www.cnitblog.com/tilan/articles/21893.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 15 Jan 2007 15:03:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21893.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21893.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21893.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21893.html</trackback:ping><description><![CDATA[<font face="Verdana"> </font>
		<a href="http://www.itisedu.com/phrase/200602281725525.html" target="_new">
				<font face="Verdana">软件工程</font>
		</a>
		<font face="Verdana">(</font>
		<a href="http://www.itisedu.com/phrase/200604240910235.html" target="_new">
				<font face="Verdana">Software Engineering</font>
		</a>
		<font face="Verdana">，简称为SE)是一门研究用工程化方法构建和维护有效的、实用的和高质量的</font>
		<a href="http://www.itisedu.com/phrase/200604232134205.html" target="_new">
				<font face="Verdana">软件</font>
		</a>
		<font face="Verdana">的学科。它涉及到</font>
		<a href="http://www.itisedu.com/phrase/200602281700255.html" target="_new">
				<font face="Verdana">程序设计语言</font>
		</a>
		<font face="Verdana">，</font>
		<a href="http://www.itisedu.com/phrase/200602271218062.html" target="_new">
				<font face="Verdana">数据库</font>
		</a>
		<font face="Verdana">，</font>
		<a href="http://www.itisedu.com/phrase/200603282233345.html" target="_new">
				<font face="Verdana">软件开发</font>
		</a>
		<font face="Verdana">工具，系统平台，标准，</font>
		<a href="http://www.itisedu.com/phrase/200603061631585.html" target="_new">
				<font face="Verdana">设计模式</font>
		</a>
		<font face="Verdana">等方面。</font>
		<p>
				<font face="Verdana">      在现代社会中，软件应用于多个方面。典型的软件比如有电子邮件，</font>
				<a href="http://www.itisedu.com/phrase/200603112246585.html" target="_new">
						<font face="Verdana">嵌入式系统</font>
				</a>
				<font face="Verdana">，人机界面，办公套件，</font>
				<a href="http://www.itisedu.com/phrase/200602281634075.html" target="_new">
						<font face="Verdana">操作系统</font>
				</a>
				<font face="Verdana">，编译器，数据库，游戏等。同时，各个行业几乎都有</font>
				<a href="http://www.itisedu.com/phrase/200602281627065.html" target="_new">
						<font face="Verdana">计算机软件</font>
				</a>
				<font face="Verdana">的应用，比如工业，农业，银行，航空，政府部门等。这些应用促进了经济和社会的发展，使得人们的工作更加高效，同时提高了生活质量。</font>
		</p>
		<p>
				<font face="Verdana">      软件工程师是对应用软件创造软件的人们的统称，软件工程师按照所处的领域不同可以分为系统分析员，软件设计师，系统<a href="http://www.itisedu.com/phrase/200604231335565.html" target="_new">架构师</a>，<a href="http://www.itisedu.com/phrase/200604232224305.html" target="_new">程序</a>员，测试员等等。人们也常常用程序员来泛指各种软件工程师。</font>
		</p>
		<p>
				<font face="Verdana">     软件工程(SoftWare Engineering)的<a href="http://www.itisedu.com/phrase/200603061723295.html" target="_new">框架</a>可概括为：目标、过程和原则。</font>
		</p>
		<p>
				<font face="Verdana">     (1)软件工程目标：生产具有正确性、可用性以及开销合宜的产品。正确性指软件产品达到预期功能的程度。可用性指软件基本结构、实现及文档为用户可用的程度。开销合宜是指软件开发、运行的整个开销满足用户要求的程度。这些目标的实现不论在理论上还是在实践中均存在很多待解决的问题，它们形成了对过程、过程模型及工程方法选取的约束。</font>
		</p>
		<p>
				<font face="Verdana">     (2)软件工程过程：生产一个最终能满足<a href="http://www.itisedu.com/phrase/200603101518295.html" target="_new">需求</a>且达到工程目标的软件产品所需要的步骤。软件工程过程主要包括开发过程、运作过程、维护过程。它们覆盖了需求、设计、实现、确认以及维护等活动。需求活动包括问题分析和<a href="http://www.itisedu.com/phrase/200603062220345.html" target="_new">需求分析</a>。问题分析获取需求定义，又称<a href="http://www.itisedu.com/phrase/200603061756235.html" target="_new">软件需求</a>规约。需求分析生成功能规约。设计活动一般包括概要设计和详细设计。概要设计建立整个<a href="http://www.itisedu.com/phrase/200602281706245.html" target="_new">软件系统</a>结构，包括<a href="http://www.itisedu.com/phrase/200604161433025.html" target="_new">子系统</a>、模块以及相关层次的说明、每一模块的接口定义。详细设计产生程序员可用的模块说明，包括每一模块中数据结构说明及加工描述。实现活动把设计结果转换为可执行的程序代码。确认活动贯穿于整个开发过程，实现完成后的确认，保证最终产品满足用户的要求。维护活动包括使用过程中的扩充、修改与完善。伴随以上过程，还有管理过程、支持过程、培训过程等。</font>
		</p>
		<p>
				<font face="Verdana">      (3)软件工程的原则是指围绕工程设计、工程支持以及工程管理在软件开发过程中必须遵循的原则。</font>
		</p>
		<p>
				<font face="Verdana">
						<strong>一、软件工程概述</strong>
				</font>
		</p>
		<p>
				<font face="Verdana">      概念：应需而生</font>
		</p>
		<p>
				<font face="Verdana">　　软件工程是一<a href="http://www.itisedu.com/phrase/200603090857555.html" target="_new">类</a>工程。工程是将理论和知识应用于实践的科学。就软件工程而言，它借鉴了传统工程的原则和方法，以求高效地开发高质量软件。其中应用了<a href="http://www.itisedu.com/phrase/200603021438435.html" target="_new">计算机</a>科学、数学和管理科学。计算机科学和数学用于构造模型与算法，工程科学用于制定规范、设计范型、评估成本及确定权衡，管理科学用于计划、资源、质量和成本的管理。</font>
		</p>
		<p>
				<font face="Verdana">      软件工程这一概念，主要是针对20世纪60年代“<a href="http://www.itisedu.com/phrase/200603112323405.html" target="_new">软件危机</a>”而提出的。它首次出现在1968年NATO（北大西洋公约组织）会议上。自这一概念提出以来，围绕软件项目，开展了有关开发模型、方法以及支持工具的研究。其主要成果有：提出了瀑布模型，开发了一些结构化<a href="http://www.itisedu.com/phrase/200602281641255.html" target="_new">程序设计</a>语言（例如PASCAL语言，Ada语言）、<a href="http://www.itisedu.com/phrase/200602281749185.html" target="_new">结构化方法</a>等。并且围绕<a href="http://www.itisedu.com/phrase/200604240825565.html" target="_new">项目管理</a>提出了费用估算、文档<a href="http://www.itisedu.com/phrase/200604161505135.html" target="_new">复审</a>等方法和工具。综观60年代末至80年代初，其主要特征是，前期着重研究系统实现技术，后期开始强调开发管理和软件质量。</font>
		</p>
		<p>
				<font face="Verdana">      70年代初，自“<a href="http://www.itisedu.com/phrase/200603061612405.html" target="_new">软件工厂</a>”这一概念提出以来，主要围绕<a href="http://www.itisedu.com/phrase/200602282140185.html" target="_new">软件过程</a>以及<a href="http://www.itisedu.com/phrase/200602281831545.html" target="_new">软件复用</a>，开展了有关软件生产技术和软件生产管理的研究与实践。其主要成果有：提出了应用广泛的<a href="http://www.itisedu.com/phrase/200603010948085.html" target="_new">面向对象语言</a>以及相关的<a href="http://www.itisedu.com/phrase/200602281513385.html" target="_new">面向对象方法</a>，大力开展了计算机辅助软件工程的研究与实践。尤其是近几年来，针对软件复用及软件生产，软件<a href="http://www.itisedu.com/phrase/200604161439595.html" target="_new">构件</a>技术以及软件质量控制技术、质量保证技术得到了广泛的应用。目前各个软件企业都十分重视资质认证，并想通过这些工作进行企业管理和技术的提升。软件工程所涉及的要素可概括如下： </font>
		</p>
		<p>
				<font face="Verdana">      根据这一框架，可以看出：软件工程涉及了软件工程的目标、软件工程原则和软件工程活动。</font>
		</p>
		<p>
				<font face="Verdana">      目标：我的眼里只有“产品”</font>
		</p>
		<p>
				<font face="Verdana">      软件工程的主要目标是：生产具有正确性、可用性以及开销合宜的产品。正确性意指软件产品达到预期功能的程度。可用性指软件基本结构、实现及文档为用户可用的程度。开销合宜性是指软件开发、运行的整个开销满足用户要求的程度。这些目标的实现不论在理论上还是在实践中均存在很多问题有待解决，它们形成了对过程、过程模型及工程方法选取的约束。</font>
		</p>
		<p>
				<font face="Verdana">      软件工程活动是“生产一个最终满足需求且达到工程目标的软件产品所需要的步骤”。主要包括需求、设计、实现、确认以及支持等活动。需求活动包括问题分析和需求分析。问题分析获取需求定义，又称软件需求规约。需求分析生成功能规约。设计活动一般包括概要设计和详细设计。概要设计建立整个<a href="http://www.itisedu.com/phrase/200603131358465.html" target="_new">软件体系结构</a>，包括子系统、模块以及相关层次的说明、每一模块接口定义。详细设计产生程序员可用的模块说明，包括每一模块中数据结构说明及加工描述。实现活动把设计结果转换为可执行的程序代码。确认活动贯穿于整个开发过程，实现完成后的确认，保证最终产品满足用户的要求。支持活动包括修改和完善。伴随以上活动，还有管理过程、支持过程、培训过程等。 </font>
		</p>
		<p>
				<font face="Verdana">      框架：四项基本原则是基石 </font>
		</p>
		<p>
				<font face="Verdana">　　软件工程围绕工程设计、工程支持以及工程管理，提出了以下四项基本原则：</font>
		</p>
		<p>
				<font face="Verdana">      第一，选取适宜开发范型。该原则与系统设计有关。在系统设计中，软件需求、硬件需求以及其他因素之间是相互制约、相互影响的，经常需要权衡。因此，必须认识需求定义的易变性，采用适宜的开发范型予以控制，以保证软件产品满足用户的要求。</font>
		</p>
		<p>
				<font face="Verdana">      第二，采用合适的设计方法。在软件设计中，通常要考虑软件的模块化、抽象与信息隐蔽、局部化、一致性以及适应性等特征。合适的设计方法有助于这些特征的实现，以达到软件工程的目标。</font>
		</p>
		<p>
				<font face="Verdana">      第三，提供高质量的工程支持。“工欲善其事，必先利其器”。在软件工程中，<a href="http://www.itisedu.com/phrase/200602282117345.html" target="_new">软件工具</a>与环境对软件过程的支持颇为重要。软件工程项目的质量与开销直接取决于对软件工程所提供的支撑质量和效用。</font>
		</p>
		<p>
				<font face="Verdana">      第四，重视开发过程的管理。软件工程的管理，直接影响可用资源的有效利用，生产满足目标的软件产品，提高软件组织的生产能力等问题。因此，仅当软件过程得以有效管理时，才能实现有效的软件工程。</font>
		</p>
		<p>
				<font face="Verdana">      这一软件工程框架告诉我们，软件工程的目标是可用性、正确性和合算性；实施一个软件工程要选取适宜的开发范型，要采用合适的设计方法，要提供高质量的工程支撑，要实行开发过程的有效管理；软件工程活动主要包括需求、设计、实现、确认和支持等活动，每一活动可根据特定的软件工程，采用合适的开发范型、设计方法、支持过程以及过程管理。根据软件工程这一框架，软件工程学科的研究内容主要包括：软件开发范型、软件开发方法、软件过程、软件工具、<a href="http://www.itisedu.com/phrase/200602282250045.html" target="_new">软件开发环境</a>、计算机辅助软件工程(CASE) 及软件经济学等。 </font>
		</p>
		<p>
				<font face="Verdana">      作用：高效开发高质量软件 </font>
		</p>
		<p>
				<font face="Verdana">　　自从软件工程概念提出以来，经过30多年的研究与实践,虽然“软件危机”没得到彻底解决，但在软件开发方法和技术方面已经有了很大的进步。尤其应该指出的是，自80年代中期，美国工业界和政府部门开始认识到，在软件开发中，最关键的问题是软件开发组织不能很好地定义和管理其软件过程，从而使一些好的开发方法和技术都起不到所期望的作用。也就是说，在没有很好定义和管理软件过程的软件开发中，开发组织不可能在好的软件方法和工具中获益。</font>
		</p>
		<p>
				<font face="Verdana">      根据调查，中国的现状几乎和美国10多年前的情况一样，软件开发过程没有明确规定，文档不完整，也不规范，软件项目的成功往往归功于软件开发组的一些杰出个人或小组的努力。这种依赖于个别人员上的成功并不能为全组织的软件生产率和质量的提高奠定有效的基础，只有通过建立全组织的过程改善，采用严格的软件工程方法和管理，并且坚持不懈地付诸实践，才能取得全组织的软件过程能力的不断提高。</font>
		</p>
		<p>
				<font face="Verdana">      这一事实告诉我们，只有坚持软件工程的四条基本原则，既重视软件技术的应用，又重视软件工程的支持和管理，并在实践中贯彻实施，才能高效地开发出高质量的软件。 </font>
		</p>
		<p>
				<font face="Verdana">
						<strong>二、软件工程的七条基本原理</strong>
				</font>
		</p>
		<p>
				<font face="Verdana">      自从1968年提出“软件工程”这一术语以来，研究软件工程的专家学者们陆续 提出了100多条关于软件工程的准则或信条。 美国著名的软件工程专家 Boehm 综合这些专家的意见，并总结了TRW公司多年的开发软件的经验，于1983年提出了软件工程的七条基本原理。 </font>
		</p>
		<p>
				<font face="Verdana">　　Boehm 认为，着七条原理是确保软件产品质量和开发效率的原理的最小集合。 <br />　　它们是相互独立的，是缺一不可的最小集合；同时，它们又是相当完备的。 </font>
		</p>
		<p>
				<font face="Verdana">　　人们当然不能用数学方法严格证明它们是一个完备的集合，但是可以证明，在此之前已经提出的100多条软件工程准则都可以有这七条原理的任意组合蕴含或派生。 </font>
		</p>
		<p>
				<font face="Verdana">　　下面简要介绍软件工程的七条原理： </font>
		</p>
		<p>
				<font face="Verdana">　　1 用分阶段的生命周期计划严格管理 <br />　　这一条是吸取前人的教训而提出来的。统计表明，50%以上的失败项目是由于计划不周而造成的。在软件开发与维护的漫长生命周期中，需要完成许多性质各异的工作。这条原理意味着，应该把<a href="http://www.itisedu.com/phrase/200603061230195.html" target="_new">软件生命周期</a>分成若干阶段，并相应制定出切实可行的计划，然后严格按照计划对软件的开发和维护进行管理。 Boehm 认为，在整个软件生命周期中应指定并严格执行6类计划：项目概要计划、里程碑计划、项目控制计划、产品控制计划、验证计划、运行维护计划。 </font>
		</p>
		<p>
				<font face="Verdana">　　2 坚持进行阶段评审 <br />　　统计结果显示： 大部分错误是在编码之前造成的，大约占63%; &lt;2&gt; 错误发现的越晚，改正它要付出的代价就越大，要差2到3个数量级。 因此，软件的质量保证工作不能等到编码结束之后再进行，应坚持进行严格的阶段评审，以便尽早发现错误。 </font>
		</p>
		<p>
				<font face="Verdana">　　3 实行严格的产品控制 <br />　　开发人员最痛恨的事情之一就是改动需求。但是实践告诉我们，需求的改动往往是不可避免的。这就要求我们要采用科学的产品控制技术来顺应这种要求。也就是要采用变动控制，又叫基准<a href="http://www.itisedu.com/phrase/200602271137552.html" target="_new">配置管理</a>。当需求变动时，其它各个阶段的文档或代码随之相应变动，以保证软件的一致性。 </font>
		</p>
		<p>
				<font face="Verdana">　　4 采纳现代程序设计技术 <br />　　从六、七时年代的结构化软件开发技术，到最近的<a href="http://www.itisedu.com/phrase/200603101726185.html" target="_new">面向对象</a>技术，从第一、第二代语言，到第四代语言，人们已经充分认识到：方法大似气力。采用先进的技术即可以提高软件开发的效率，又可以减少软件维护的成本。 </font>
		</p>
		<p>
				<font face="Verdana">　　5 结果应能清楚地审查 <br />　　软件是一种看不见、摸不着的逻辑产品。软件开发小组的工作进展情况可见性差，难于评价和管理。为更好地进行管理，应根据软件开发的总目标及完成期限， 尽量明确地规定开发小组的责任和产品标准，从而使所得到的标准能清楚地审查。 </font>
		</p>
		<font face="Verdana">
				<p>
						<br />　　6 开发小组的人员应少而精 <br />　　开发人员的素质和数量是影响软件质量和开发效率的重要因素，应该少而精。 <br />　　这一条基于两点原因：高素质开发人员的效率比低素质开发人员的效率要高几倍到几十倍，开发工作中犯的错误也要少的多； 当开发小组为N人时，可能的通讯信道为N(N-1)/2, 可见随着人数N的增大，通讯开销将急剧增大。 </p>
				<p>　　7 承认不断改进软件工程实践的必要性 <br />　　遵从上述六条基本原理，就能够较好地实现软件的工程化生产。但是，它们只是对现有的经验的总结和归纳，并不能保证赶上技术不断前进发展的步伐。因此，Boehm提出应把承认不断改进软件工程实践的必要性作为软件工程的第七条原理。根据这条原理，不仅要积极采纳新的软件开发技术，还要注意不断总结经验，收集进度和消耗等数据，进行出错<a href="http://www.itisedu.com/phrase/200603051002565.html" target="_new">类型</a>和问题报告统计。这些数据既可以用来评估新的 软件技术的效果，也可以用来指明必须着重注意的问题和应该优先进行研究的工具和技术。 </p>
				<p>      面向方面的编程（Aspect Oriented <a href="http://www.itisedu.com/phrase/200604232129205.html" target="_new">Programming</a>，简称<a href="http://www.itisedu.com/phrase/200604231341385.html" target="_new">AOP</a>）被认为是近年来软件工程的另外一个重要发展。这里的方面指的是完成一个功能的<a href="http://www.itisedu.com/phrase/200603090845215.html" target="_new">对象</a>和函数的集合。在这一方面相关的内容有泛型编程（Generic Programming）和模板。</p>
				<p>参考<br />      胡崑山，《中国软件产业发展现状与人才需求》，2003年9月1日，            http://software.ccidnet.com/pub/article/c372_a62973_p1.html </p>
				<p>
						<font face="Verdana">
								<strong>三、软件工程的目标与常用模型</strong>
						</font>
				</p>
				<p>
						<font face="Verdana">      软件工程的目标是提高软件的质量与生产率，最终实现软件的工业化生产。质量是软件需求方最关心的问题，用户即使不图物美价廉，也要求个货真价实。生产率是软件供应方最关心的问题，老板和员工都想用更少的时间挣更多的钱。质量与生产率之间有着内在的联系，高生产率必须以质量合格为前提。如果质量不合格，对供需双方都是坏事情。从短期效益看，追求高质量会延长软件开发时间并且增大费用，似乎降低了生产率。从长期效益看，高质量将保证软件开发的全过程更加规范流畅，大大降低了软件的维护代价，实质上是提高了生产率，同时可获得很好的信誉。质量与生产率之间不存在根本的对立，好的软件工程方法可以同时提高质量与生产率。 </font>
				</p>
				<p>
						<font face="Verdana">      软件供需双方的代表能在餐桌上谈笑风生，归功于第一线开发人员的辛勤工作。质量与生产率的提高就指望程序员与程序经理。对开发人员而言，如果非得在质量与生产率之间分个主次不可，那么应该是质量第一，生产率第二。这是因为：（1）质量直接体现在软件的每段程序中，高质量自然是开发人员的技术追求，也是职业道德的要求。（2）高质量对所有的用户都有价值，而高生产率只对开发方有意义。（3）如果一开始就追求高生产率，容易使人急功近利，留下隐患。宁可进度慢些，也要保证每个环节的质量，以图长远利益。 </font>
				</p>
				<p>
						<font face="Verdana">      软件的质量因素很多，如正确性，性能、可靠性、容错性、易用性、灵活性、可扩充性、可理解性、可维护性等等。有些因素相互重叠，有些则相抵触，真要提高质量可不容易啊！ </font>
				</p>
				<p>
						<font face="Verdana">      软件工程的主要环节有：人员管理、项目管理、可行性与需求分析、系统设计、程序设计、测试、维护等，如图1.1所示。 </font>
				</p>
				<p align="center">
						<img src="http://www.itisedu.com/manage/Upload/image/200632922318332.gif" border="0" />
				</p>
				<p>
						<font face="Verdana">      软件工程模型建议用一定的流程将各个环节连接起来，并可用规范的方式操作全过程，如同工厂的生产线。常见的软件工程模型有：线性模型（图1.2），渐增式模型（图1.3），螺旋模型，快速原型模型，形式化描述模型等等 [Pressmam 1999, Sommerville 1992]。 </font>
				</p>
				<font face="Verdana">
						<p align="center">
								<img src="http://www.itisedu.com/manage/Upload/image/2006329223120904.gif" border="0" />
								<br />  </p>
				</font>
				<p>
						<font face="Verdana">      最早出现的软件工程模型是线性模型（又称瀑布模型）。线性模型太理想化，太单纯，已不再适合现代的软件开发<a href="http://www.itisedu.com/phrase/200603061709535.html" target="_new">模式</a>，几乎被业界抛弃。偶而被人提起，都属于被贬对象，未被留一丝惋惜。但我们应该认识到，“线性”是人们最容易掌握并能熟练应用的思想方法。当人们碰到一个复杂的“非线性”问题时，总是千方百计地将其分解或转化为一系列简单的线性问题，然后逐个解决。一个软件系统的整体可能是复杂的，而单个子程序总是简单的，可以用线性的方式来实现，否则干活就太累了。线性是一种简洁，简洁就是美。当我们领会了线性的精神，就不要再呆板地套用线性模型的外表，而应该用活它。例如渐增式模型实质就是分段的线性模型，如图1.3所示。螺旋模型则是接连的弯曲了的线性模型。在其它模型中都能够找到线性模型的影子。 </font>
				</p>
				<p>
						<font face="Verdana">      套用固定的模型不是程序员的聪明之举。比如“程序设计”与“测试”之间的关系，习惯上总以为程序设计在先，测试在后，如图1.4（a）所示。而对于一些复杂的程序，将测试分为同步测试与总测试更有效，如图1.4（b）所示。 </font>
				</p>
				<p align="center">
						<img src="http://www.itisedu.com/manage/Upload/image/2006329223139948.gif" border="0" />
				</p>
				<font face="Verdana">
						<p>
								<br />      不论是什么软件工程模型，总是少不了图1.1中的各个环节。本书擗开具体的软件工程模型，顺序讲述人员管理、项目管理、可行性与需求分析、系统设计、程序设计、测试，以及维护与再生工程。其中程序设计部分以C++/C语言为例。 </p>
				</font>
				<p>
				</p>
		</font>
		<font face="Verdana">
				<strong>四、软件<a href="http://www.itisedu.com/phrase/200603122156385.html" target="_new">体系结构</a>和工具的选择</strong>
		</font>
		<p>
				<font face="Verdana">　　软件体系结构表示了一个软件系统的高层结构，主要特点有：1）软件系统结构是一个高层次上的抽象，它并不涉及具体的系统结构（比如<a href="http://www.itisedu.com/phrase/200604291152445.html" target="_new">B/S</a>还是<a href="http://www.itisedu.com/phrase/200604291148225.html" target="_new">C/S</a>），也不关心具体的实现。2）软件体系结构必须支持系统所要求的功能，在设计软件体系结构的时候，必须考虑系统的动态行为。3）在设计软件体系结构的时候，必须考虑有现有系统的兼容性、安全性和可靠性。同时还要考虑系统以后的扩展性和伸缩性。所以有时候必须在多个不同方向的目标中进行决策。</font>
		</p>
		<p>
				<font face="Verdana">　　当前已经有一些关于规范化软件体系结构，比如：ISO的开放系统互联模型、X Window系统等等。软件系统的结构通常被定义为两个部分：一个是计算部件。另一个就是部件之间的交互。如果把软件系统看成一幅图的话，计算部件就是其中的节点，而部件之间的交互就是节点之间的弧线。部件之间的连接可以被认为是一种连接器，比如过程调用、事件广播、数据库查询等等。正确的体系结构设计是软件系统成功的关键。</font>
		</p>
		<p>
				<font face="Verdana">　　我们理解了软件工程的重要性以后，我们没有相应的工具，我们也很难很好的完成一个系统。在需求分析和设计阶段，我们需要什么样的工具呢？</font>
		</p>
		<p>
				<font face="Verdana">　　当然最好是基于<a href="http://www.itisedu.com/phrase/200602271429302.html" target="_new">UML</a>的CASE工具。当前比较流行的就是Rose，它是一个很好的分析和建立对象和对象关系的工具。在具体编码的时候，我们需要<a href="http://www.itisedu.com/phrase/200603292355295.html" target="_new">版本控制</a>工具，MS的SourceSafe就是一个很好的版本管理工具和项目管理工具。具体的开发工具当然很多，但是如果你是一个对VC侵淫了多年的程序员，你一定会选择它，因为它会让你感到什么是真正的面向对象的编程，而你在用VB，<a href="http://www.itisedu.com/phrase/200604041117205.html" target="_new">PowerBuilder</a>，<a href="http://www.itisedu.com/phrase/200604042241255.html" target="_new">Delphi</a>时很少会有同样的感受。至于数据库模式构建，我一向是采用<a href="http://www.itisedu.com/phrase/200604040934365.html" target="_new">Sybase</a>的S-Design，更好的工具就不知道了。</font>
		</p>
		<p>
				<font face="Verdana">　　另外需要注意的是，我们需要建立文档编写的若干模板，以便开发人员按照这个模板编写规范的技术和说明文档。帮助文档可以用微软的HTML Help Workshop(hhw.exe)制作，你也可以编译成.chm格式，它打包了文本和图形，只有一个<a href="http://www.itisedu.com/phrase/200602282323195.html" target="_new">文件</a>，使用和分发比较方便。最后，如果开发人员不是集中在一个地方的话，最好建立一个邮件列表，开发人员可以通过邮件系统讨论开发中的各项事宜。 </font>
		</p>
		<p>
				<font face="Verdana">
						<strong>五、软件开发方法综述</strong>
				</font>
		</p>
		<font face="Verdana">
				<p>
						<br />　　国外大的软件公司和机构一直在研究软件开发方法这个概念性的东西，而且也提出了很多实际的开发方法，比如：生命周期法、原型化方法、面向对象方法等等。下面介绍几种流行的开发方法：</p>
				<p>　　1、结构化方法 </p>
				<p>　　结构化开发方法是由E.Yourdon 和 L.L.Constantine 提出的，即所谓的SASD 方 法， 也可称为面向功能的软件开发方法或面向数据流的软件开发方法。Yourdon方法是80年代 使用最广泛的软件开发方法。它首先用结构化分析（SA）对软件进行需求分析，然后用结构化设计（SD）方法进行总体设计，最后是结构化编程（SP）。它给出了两类典型的<a href="http://www.itisedu.com/phrase/200602282202575.html" target="_new">软件结构</a>（变换型和事务型）使软件开发的成功率大大提高。 </p>
				<p>　　2、面向数据结构的软件开发方法 </p>
				<p>　　Jackson方法是最典型的面向数据结构的软件开发方法，Jackson方法把问题分解为可由三种基本结构形式表示的各部分的层次结构。三种基本的结构形式就是顺序、选择和重复。三种数据结构可以进行组合，形成复杂的结构体系。这一方法从目标系统的输入、输出数据结构入手，导出程序框架结构，再补充其它细节，就可得到完整的程序结构图。这一方法对输入、输出数据结构明确的中小型系统特别有效，如商业应用中的文件表格处理。该方法也可与其它方法结合，用于模块的详细设计。</p>
				<p>　　3、 面向问题的分析法 </p>
				<p>　　PAM（Problem Analysis Method）是80年代末由日立公司提出的一种软件开发方法。 它的基本思想是考虑到输入、输出数据结构，指导系统的分解，在系统分析指导下逐步综 合。这一方法的具体步骤是：从输入、输出数据结构导出基本处理框；分析这些处理框之间的先后关系；按先后关系逐步综合处理框，直到画出整个系统的PAD图。这一方法本质上是综合的自底向上的方法，但在逐步综合之前已进行了有目的的分解，这个目的就是充分考虑系统的输入、输出数据结构。PAM方法的另一个优点是使用PAD图。这是一种二维树形结构图，是到目前为止最好的详细设计表示方法之一。当然由于在输入、输出数据结构与整个系统之间同样存在着鸿沟，这一方法仍只适用于中小型问题。</p>
				<p>　　4、原型化方法</p>
				<p>　　产生原型化方法的原因很多，主要随着我们系统开发经验的增多，我们也发现并非所有的需求都能够预先定义而且反复修改是不可避免的。当然能够采用原型化方法是因为开发工具的快速发展，比如用VB，DELPHI等工具我们可以迅速的开发出一个可以让用户看的见、摸的着的系统框架，这样，对于计算机不是很熟悉的用户就可以根据这个样板提出自己的需求。</p>
				<p>　　开发原型化系统一般由以下几个阶段：<br />（1） 确定用户需求<br />（2） 开发原始模型<br />（3） 征求用户对初始原型的改进意见<br />（4） 修改原型。</p>
				<p>　　原型化开发比较适合于用户需求不清、业务理论不确定、需求经常变化的情况。当系统规模不是很大也不太复杂时采用该方法是比较好的。</p>
				<p>　5、面向对象的软件开发方法</p>
				<p>　　当前计算机业界最流行的几个单词就是分布式、并行和面向对象这几个术语。由此可以看到面向对象这个概念在当前计算机业界的地位。比如当前流行的两大面向对象技术<a href="http://www.itisedu.com/phrase/200604152041495.html" target="_new">DCOM</a>和<a href="http://www.itisedu.com/phrase/200604031336425.html" target="_new">CORBA</a>就是例子。当然我们实际用到的还是面向对象的编程语言，比如C++。不可否认，面向对象技术是软件技术的一次革命，在软件开发史上具有里程碑的意义。 </p>
				<p>　　随着<a href="http://www.itisedu.com/phrase/200604240956125.html" target="_new">OOP</a>（<a href="http://www.itisedu.com/phrase/200603050951565.html" target="_new">面向对象编程</a>）向<a href="http://www.itisedu.com/phrase/200604231256315.html" target="_new">OOD</a>（<a href="http://www.itisedu.com/phrase/200603050045535.html" target="_new">面向对象设计</a>）和<a href="http://www.itisedu.com/phrase/200603050028345.html" target="_new">OOA</a>（<a href="http://www.itisedu.com/phrase/200604231254345.html" target="_new">面向对象分析</a>）的发展，最终形成面向对象的软件开发方法OMT (<a href="http://www.itisedu.com/phrase/200604231338435.html" target="_new">Object</a> Modeling Technique）。这是一种自底向上和自顶向下相结合的方法，而且它以对象建模为基础，从而不仅考虑了输入、输出数据结构，实际上也包含了所有对象的数据结构。所以OMT彻底实现了PAM没有完全实现的目标。不仅如此，<a href="http://www.itisedu.com/phrase/200604231401365.html" target="_new">OO</a>技术在需求分析、可维护性和可靠性这三个软件开发的关键环节和质量指标上有了实质性的突破，基本地解决了在这些方面存在的严重问题。</p>
				<p>　　综上所述，面向对象系统采用了自底向上的归纳、自顶向下的分解的方法，它通过对对象模型的建立，能够真正建立基于用户的需求，而且系统的可维护性大大改善。当前业界关于面向对象建模的标准是UML（<a href="http://www.itisedu.com/phrase/200604231301515.html" target="_new">Unified Modeling Language</a>）。</p>
				<p>　　这里我们需要谈一下微软的<a href="http://www.itisedu.com/phrase/200604231607095.html" target="_new">MSF</a>（Microsoft Solutions <a href="http://www.itisedu.com/phrase/200604241001145.html" target="_new">Framework</a>）的框架，它简单的把系统设计分成三个阶段：概念设计、逻辑设计和物理设计。概念设计阶段就是从用户的角度出发可以得到多少个对象，并且以对象为主体，画出业务框架。逻辑设计阶段就是对概念设计阶段的对象进行再分析、细分、整合、删除。并建立各个对象的方法属性以及对象之间的关系。而物理设计实际上就是要确定我们实际需要的<a href="http://www.itisedu.com/phrase/200603302222545.html" target="_new">组件</a>、服务和采用的框架结构、具体的编程语言等。MCF整个结构比较清楚是基于对象开发的一个比较好的可操作的框架系统。</p>
				<p>　　6、可视化开发方法 </p>
				<p>　　其实可视化开发并不能单独的作为一种开发方法，更加贴切的说可以认为它是一种辅助工具，比如用过SYBASE的S-Design的人都知道，用这个工具可以进行显示的图形化的数据库模式的建立，并可以导入到不同的数据库中去。当然用过S-Design的人不一定很多，但用过VB，DELPHI，C++ Builder等开发工具的人一定不少，实际上你就是在使用可视化开发工具。</p>
				<p>　　当然，不可否认的是，你只是在编程这个环节上用了可视化，而不是在系统分析和系统设计这个高层次上用了可视化的方法。实际上，建立系统分析和系统设计的可视化工具是一个很好的卖点，国外有很多工具都致力于这方面产品的设计。比如<a href="http://www.itisedu.com/phrase/200604240816305.html" target="_new">Business Object</a>就是一个非常好的数据库可视化分析工具。</p>
				<p>　　可视化开发使我们把注意力集中在业务逻辑和业务流程上，用户界面可以用可视化工具方便的构成。通过操作界面元素，诸如菜单、按钮、对话框、编辑框、单选框、复选框、 列表框和滚动条等，由可视开发工具自动生成应用软件。 </p>
				<p>
						<strong>六、怎样培养软件工程的思维与方法</strong>
				</p>
				<p>
						<br />　　作为软件开发人员的一个通病是在项目初期的时候，就喜欢谈论实现的细节，并且乐此不疲。我们更喜欢讨论如何用灵活而简短的代码来实现一个特定的功能，而忽略了对整个系统<a href="http://www.itisedu.com/phrase/200604241328115.html" target="_new">架构</a>的考虑。所以作为一个开发人员，尤其是一个有经验的开发人员，应该把自己从代码中解脱出来，更多的时候在我们的脑子里甚至暂时要放弃去考虑如何实现的问题，而从项目或产品的总体去考虑一个软件产品。</p>
				<p>　　以下是我个人的一些经验：</p>
				<p>　　1．考虑整个项目或者产品的市场前景。作为一个真正的系统分析人员，不仅要从技术的角度来考虑问题，而且还要从市场的角度去考虑问题。也就是说我们同时需要考虑我们产品的用户群是谁，当我们产品投放到市场上的时候，是否具有生命力。比如即使我们采用最好的技术实现了一个单进程的操作系统，其市场前景也一定是不容乐观的。</p>
				<p>　　2．从用户的角度来考虑问题。比如一些操作对于开发人员来讲是非常显而易见的问题。但是对于一般的用户来说可能就非常难于掌握，也就是说，有时候，我们不得不在灵活性和易用性方面进行折中。另外，在功能实现上，我们也需要进行综合考虑，尽管一些功能十分强大，但是如果用户几乎不怎么使用它的话，就不一定在产品的第一版的时候就推出。从用户的角度考虑，也就是说用户认可的才是好的，并不是开发人员觉的好才好。</p>
				<p>　　3．从技术的角度考虑问题。虽然技术绝对不是唯一重要的，但是技术一定是非常重要的，是成功的必要环节。在产品设计的时候，必须考虑采用先进的技术和先进的体系结构。比如，如果可以采用多<a href="http://www.itisedu.com/phrase/200603091754305.html" target="_new">线程</a>进行程序中各个部分并行处理的话，就最好采用多线程处理。在Windows下开发的时候，能够把功能封装成一个单独的COM构件就不作成一个简单的DLL或者是以源代码存在的函数库或者是对象。比如能够在<a href="http://www.itisedu.com/phrase/200604291151335.html" target="_new">B/S结构</a>下运行并且不影响系统功能的话就不一定要在C/S下实现。</p>
				<p>4．合理进行模块的分割。从多层模型角度来讲，一般系统可以分成用户层、业务层和<a href="http://www.itisedu.com/phrase/200604241152425.html" target="_new">数据库层</a>三部分。当然每以部分都还可以进行细分。所以在系统实现设计的时候，尽量进行各个部分的分割并建立各个部分之间进行交互的标准。并且在实际开发的时候，确实有需要的话再进行重新调整。这样就可以保证各个部分齐头并进，开发人员也可以各施其职。</p>
				<p>　　5．人员的组织和调度。这里很重要的一点是到考虑人员的特长，有的人喜欢做界面，有的人喜欢做核心。如果有可能要根据人员的具体的情况进行具体的配置。同时要保证每一个开发人员在开发的时候首先完成需要和其他人员进行交互的部分，并且对自己的项目进度以及其他开发人员的进度有一个清晰的了解，保证不同部分的开发人员能够经常进行交流。</p>
				<p>　　6．开发过程中文档的编写。在开发过程中会碰到各种各样的问题和困难，当然还有各种各样的创意和新的思路。应该把这些东西都记录下来并进行及时整理，对于困难和问题，如果不能短时间解决的，可以考虑采用其他的技术替代，并在事后做专门的研究。对于各种创意，可以根据进度计划安排考虑是在本版本中实现还是在下一版本中实现。</p>
				<p>　　7．充分考虑实施时可能遇到的问题。开发是一回事情，用户真正能够使用好它又是另外一回事情。比如在<a href="http://www.itisedu.com/phrase/200604241249435.html" target="_new">MIS</a>系统开发中，最简单的一个问题就是用户如果数据输入错误的时候，如何进行操作。在以流程方式工作的时候，如何让用户理解自己在流程中的位置和作用，如何让用户真正利用计算机进行协作也是成败的关键。</p>
				<p>　　以上是我个人的一点体会，实际上，作为一个软件开发人员，我也喜欢看到问题就坐在计算机前面直接编码，但是我确实认为软件工程对于我们系统开发的指导作用是巨大的。作为软件工程的拥戴者，下面我简单结合自己的开发经历介绍基于软件工程的开发方法、编程规范和工具使用等方面的问题。 </p>
				<p>
						<br />
						<strong>七、软件开发的发展变化</strong>
				</p>
				<p>
						<br />　　国外很多项目的开发都是基于一些图形化的东西来做的，他们的目的是尽量少写代码甚至不写代码。代码能够通过图形化的方式自动生成，这样的一个好处就是如果用户的需求变化或者业务逻辑发生变化，我们需要做的就是对图形表示的调整，然后重新自动生成代码，这也就是国外开发很注重对项目的概念和逻辑分析的原因。</p>
				<p>　　他们的重点是把业务规则和需求用图形化的方式表现出来，然后通过CASE工具自动生成代码。所以当国人还在不停的开发一个又一个的MIS工具的时候，国外已经把很多精力放到了CASE工具的制作上。</p>
				<p>　　我们很多公司人员忙着写具体业务过程的相关代码，而国外很多都把精力放到对不同应用，不同行业的模型的建立和共性的提取上。所以，他们做出来的东西就相对具有很强的灵活性和扩展性，而我们是用户的需求稍微有一点变化，就要忙着改代码，甚至改体系结构。</p>
				<p>　　另外，因为他们注重模型的建立，所以在建立其他应用的时候，能够借鉴原先的模型，在高层次上做调整和优化，同时能够有效的提取原有系统中可以被使用的部分。所以我们应该从以代码为核心的软件开发模式转化到以模型为中心的、基于CASE的开发上来。</p>
				<p>　　关于协作与个人英雄主义</p>
				<p>　　社会进步的一个很明显的现象就是社会分工越来越细，软件的开发也不例外。为什么在软件开发的今天已经不能出现象裘伯君这样的软件英雄的原因也在这里，单凭个人之力，我们也许穷尽有生之年也开发不出象Windows这样的操作系统。<br />因为，当前软件行业的壁垒无非就是两个，一个就是以技术创新取胜，你模仿的了其中的界面，但是你没有办法实现其中的核心功能。结果是你只能购买其技术核心，而你作一些边角工作。不举别的例子，比如VB这样的开发工具，其核心部分是它和第三方提供的COM控件或者是DLL函数库，你所做的就是一个整合的工作。</p>
				<p>　　第二个就是以细致取胜，也就是说功能很多而且做的很精致，即使技术本身不是很复杂，你真要想做出一个这样的东西来没有一两年的工夫是不可能的。而真等你做出来了，它的新版本也早已经推出。真正能够在市面上叫得想、经得起考验得产品都是具有这两方面的特点。</p>
				<p>　　这两方面的特点决定了你一个人绝对是不可能胜任的，也许你可以独立的完成技术创新，但是你绝对不可能一个人实现所有这些纷繁复杂的功能。所以，这个时代需要创新的英雄，也更需要人与人之间的协作。<br />当今的软件发展已经不是一个人可以包打天下的年代。软件开发的管理、系统体系结构的设计、模块之间的衔接、核心算法的实现、灵活界面的制定、软件再开发接口的实现都需要专门的人来做。而把这些有效的集成显然就需要有效的利用软件工程的思想和方法。所以，真正的软件英雄绝对不再是写着别人看不懂代码的程序员，而是整个体系结构的分析、设计、标准制定、协调人员。</p>
				<p>
						<strong>八、我们是否需要软件工程</strong>
				</p>
				<p>
						<br />　　有一点大家可以达成共识的就是，如果一个象Windows这样的操作系统，不进行全面的规划，不采用软件工程的思想和方法，是绝对搞不出来的。</p>
				<p>　　Windows的成功不在于它在进程管理和调度，文件系统、内存管理、界面设计等方面有多少成功的创新，它的成功最大的一点就是把所有的技术能够合理的整合起来，并集中到一个Window操作系统特有的框架结构中去。</p>
				<p>　　更为重要的是，Windows的每一项技术创新都能够有效的整合到Windows框架中去，比如COM、<a href="http://www.itisedu.com/phrase/200604231236585.html" target="_new">XML</a>等技术，通过ActiveX、DCOM等技术使Windows从桌面操作系统发展成为一个基于网络的操作系统。</p>
				<p>　　OLE2技术把整个Office中相关的软件进行了有效的整合，显然，这里我们可以把Office的设计和WPS的设计进行比较，客观的讲，WPS对中国用户来说实在也是一个很好的产品。但是从整个系统设计概念上来讲，Office显然要比WPS高一个层次，它能够把WORD，EXCEL，POWERPOINT，ACCESS有效的整合在一起，使我们所有办公相关的文档、图表、数据库、演示变成了一个一体化的东西。而且通过宏调用，用户可以自己定制用户界面并编制适当的模板，单是这个二次开发功能就不是WPS现在所能及项背的，当然限于当前用户的水平还很少有人使用二次开发的功能。</p>
				<p>　　从微软产品系列可以看到软件工程的作用，微软的所有产品都有一个整体的框架结构，比如Office软件，通过OLE技术进行有效的通讯和联系。比如Visual系列开发工具，提供了相似的开发界面使用户学会一种开发工具以后能够很容易的学习其他的开发工具。比如<a href="http://www.itisedu.com/phrase/200604040933575.html" target="_new">SQL SERVER</a>和ACCESS，尽管它们适用的范围不同，但是它们表现给用户的界面，特别是在查询和分析上表现了高度的一致性。</p>
				<p>　　更值得一提的是，因为设计结构的合理性，因为在开发前期作了很多分析和调研，考虑了扩展性和伸缩性，微软的系列产品能够很快的利用新的技术并采用统一的结构形式表现出来。比如当网络成为计算机发展的主流的时候，几乎微软所有的工具都能够快速的支持基于网络的开发和应用。</p>
				<p> </p>
				<p>　　相比之下，我们国内很多公司的产品很少具有连续性，往往是新的一个产品完全重起炉灶，和老的产品没有半点关系。这就是我们在设计产品的时候，没有很好的进行抽象和概念、逻辑设计，造成的结果是从旧的产品中提取不出一些有用的、共性的东西为后来的产品所使用。</p>
				<p>　　当然，很多开发人员从心里也承认一个大的系统确实需要软件工程的依托，但是一个小的工程项目是否就可以仓促上马呢？答案是否定的。所谓麻雀碎小，五脏俱全。无论是大项目、还是小项目。它们作为一个项目，都需要有一个需求分析、系统结构建立、设计、编码、测试等阶段。这是任何一个项目都不可缺少的。</p>
				<p>　　往往可以看到很多大公司的IT部门的人员都在不停的作各种各样的报表，当各个部门提出一种新类型的报表的时候，就从数据库中提取相应的数据并画出业务人员所需要的样式结构，很少是提供了一个通用的模板，当然提供高层<a href="http://www.itisedu.com/phrase/200604241228185.html" target="_new">API</a>接口进行这种操作的就更少了。这样不可避免的使开发人员陷入一些琐碎的报表编制工作。而造成这个局面的很重要的一个原因就是没有在系统开发的前期进行很好的调研、需求分析和系统体系结构的设计。</p>
				<p>　　这里就我们开发过的一些小型软件项目来谈一些开发的总结和体会，一般来说，小型软件项目功能比较单一，而且模块与模块之间的衔接不是很多，同时对开发周期要求比较短。</p>
				<p>　　小项目虽然看起来比较简单，所以很多开发人员容易犯一些错误，记得我们在开发一个基于Internet的有偿服务系统的时候，有三个开发人员：一个负责前端界面的编写，一个负责数据通讯协议和实现（基于TCP基础上的应用协议），一个负责对数据库数据的查询、整理和提取。我们在开发的时候没有认真地进行项目实际前途和工作量的估计。没有认真地估计项目难度，比如对于通讯中多用户并发访问时的多线程问题和缓存处理问题，用户批量请求处理的实现复杂度问题等等。三个人之间的接口也是在开发中休息的时候，口头定义一下。结果发现有不严密的地方(比如在通讯服务器端是用VC编写的，开发人员是通过stream来传送数据的，<a href="http://www.itisedu.com/phrase/200603082208195.html" target="_new">客户端</a>是用Delphi编写，在接收数据的时候发现数据不准确，后来研究发现VC利用CSocket在传送数据流的时候对数据进行了自己定义的格式化，结果服务器端数据发送模块只好重写)，而且其中关于一个接口双方的理解不同，然后又返工重新修改。最后到系统基本完成的时候没有一份较正式的文档。然后因为有人毕业离开这个项目，然后他编写的模块需要升级，新的接收的人不得不花很多时间去阅读他的源代码。</p>
				<p>所以在开发小项目的时候也必须要建立合理的模式：而所谓合理的模式就是软件工程告诉我们的在开发一个项目的时候所需要的五步曲：获取需求、需求分析、设计、编码、测试。</p>
				<p>　　1．理解用户真正的需求。在进入正式开发之前，必须先从用户处获取准确的需求。在这上面花费相当时间是很必要的。</p>
				<p>　　我们软件项目可以大致分为专用软件和通用软件两大类。对于专用软件，一般用户对于软件要完成哪些功能已经有了一个比较清楚的轮廓，而且往往在开发合同中已经大致地规定了。</p>
				<p>　　但是，开发合同上规定的只是一个大概的框架，在进入开发之前必须与用户进行比较具体的交流和讨论，了解清楚用户心目中的产品究竟是什么样子，这里最好就采用原型化的方法作出一个简单的框架给用户看。</p>
				<p>　　对于通用软件，在开发之前必须做一定的市场调查工作，一方面是从经济效益考虑，调查产品的潜在市场有多大，一方面是从技术的角度，了解清楚潜在用户对软件的各种技术上的要求，另一方面是确定我们软件的定位，即我们软件具体是为哪一些用户群体服务的。然后对该群体用户现有硬件配置，软件配置，网络使用情况，数据库使用情况，计算机熟悉程度做一定的调研，根据调查的统计结果决定即将开发的软件的一些技术指标。 <br />　　<br />　　2．需求分析。需求分析需要做的事情有：高层构思、确立系统目标、划分业务领域、现行业务分析、建立业务模型(Enterprise Model)、信息需求分析、用户<a href="http://www.itisedu.com/phrase/200603141659315.html" target="_new">视图</a>规范化、数据元素标准化与一致性控制。</p>
				<p>　　在了解用户的需求之后，将需求用一种模型来表示，就是需求分析，一般我们可以<a href="http://www.itisedu.com/phrase/200604231249365.html" target="_new">面向对象的方法</a>，通过分析用户需求，用类、类之间的各种关系来表示整个系统。</p>
				<p>　　为了讨论软件运行的流程，可以采用UML的<a href="http://www.itisedu.com/phrase/200603042249305.html" target="_new">Use Case</a>图。在系统分析的时候需要明确应用域（application domain）的范围，然后明确我们系统需要做什么。同时我们需要决定用什么方法来完成需求的获取，这在很大程度上影响了需求分析的做法。</p>
				<p>　　例如可以采用Use Case来表示用户需求，那么从各种<a href="http://www.itisedu.com/phrase/200603101549275.html" target="_new">序列图</a>中选出相互交互的各个实体，就是一个个类。另外分析需要与设计过程相衔接。分析过程的内容是用对象和对象之间的关系来表示整个系统和系统的流程的，并不设计具体实现，如采用什么编程语言，在什么操作系统平台上运行等等。这些具体实现是在设计阶段来完成的。</p>
				<p>　　面向对象方法的优点是分析、设计、编码过程表示法统一，能比较好的衔接。现在很多CASE工具并不区分分析和设计的阶段。但是，这并不意味着开发就可以对分析和设计不加区分，如何用好辅助设计(case)工具还是开发人员的事情。</p>
				<p>　　3．设计过程。设计阶段的工作包括对分析模型进行必要的修改，同时可能需要对某些类结构做一些修改，确定用户表示层(也就是通俗所说的界面定义)、用户服务层、业务逻辑层、数据库服务层和具体数据库所需要做的工作。同时需要确定使用的体系结构（比如B/S还是C/S）和开发工具（如VB，VC，VI，C++ Builder，DELPHI，PowerBuiler等等）</p>
				<p>　　4．编码。进入编码工作之后，依然可能会发现前面分析或设计阶段的某些错误，这时应返回到前面的阶段进行必要的修改。同时在编码前规定编码的风格并在开发过程中保持一致的风格。</p>
				<p>
						<br />　　5．测试。测试是系统投入使用前最关键的一个步骤。即使是小项目也应该严格地进行测试。就实际上就是一个把错误留给自己还是留给客户的问题。</p>
				<p>　　最后，我们知道软件项目主要是由开发人员完成的，所以对人员的合理安排和配置也很重要，一般在开发过程中，需要有一位项目负责人，负责分析、设计和协调的工作。另外需要几个程序员完成不同层的代码（比如用户服务层、业务逻辑层、数据库服务层等等）。</p>
				<p>　　同时需要有一个文档整理人员随时整理系统开发过程中相关的文档。如果条件可能的话，要配置一个测试工程师，专门进行代码的测试工作，当然如果条件不允许的话，也可以由开发人员<a href="http://www.itisedu.com/phrase/200604240926075.html" target="_new">交叉测试</a>。这里需要注意的是，对于项目负责人而言，协调几个人的工作比自己完成一段编码更重要。</p>
				<p>　　由于协调上出了漏洞，可能导致很大的问题，所以项目负责人必须随时监控各开发人员的工作，包括内容是否与要求发生偏差，进度是否滞后等等。同时必须给每个开发人员明确的任务书。具体开发时每个开发人员必须非常明确自己的任务，这些任务应该采用明确的文档来表示。每个开发人员需要清楚自己所做的工作在整个系统中处于什么地位，这样就有可能会发现<a href="http://www.itisedu.com/phrase/200604161258515.html" target="_new">设计模型</a>中的漏洞，避免了各人的代码编写完毕之后又要修改的后果。 </p>
				<p>
						<strong>九、我国软件工程发展的现状</strong>
				</p>
				<p>
						<br />      很多国内搞计算机的专家都认为：国内的软件研发过程，个人色彩比较浓。过分地依靠个人无法形成产业规模，而没有规模就谈不上产业化了。</p>
				<p>　　不管怎么样，我们大家还是先要来看一看国内软件厂商到底提供给我们多少有震撼力的软件产品，从技术和利润的角度讲，软件系统最核心的部分还是操作系统、编译系统然后就是开发平台之类的东西，接下来就是一些应用系统，比如图形开发、游戏开发、企业应用、网站建设、杀毒、网络工具等等。</p>
				<p>　　操作系统以中科院为中心，做了一个COSIX，这个本质上是一个UNIX系统，UNIX最初的源代码是公开的，尽管COSIX是一个被称为中国的操作系统并是UNIX系列的（IX就代表UNIX系列），但是其中到底有多少独创的技术成分我们暂时还不知道，但有一点可以肯定，它现在的市场覆盖率绝对不大，而且能否在上面运行各种各样的编译系统、数据库、群件和应用系统可能还需要进一步测试。然后就是对硬件平台的支持也需要进一步完善。</p>
				<p>　　然后就是轰轰烈烈的Linux系统，Linux是遵守GNU标准的操作系统，中国有很多家公司推出了自己的Linux并且还有汉化的Linux，这就有比较疑惑的一点，为什么不在Linux上构架一个类似UNICODE这样的东西，而只做汉化这么本地化的产品呢？不知道是眼光还是市场的问题了。<br />MIS系统、财务软件是中国软件行业的重头戏，它们彻底的暴露了中国软件开发无序和重复低效劳动的一面。教育软件在某一种层面上看就是电子题库，当然也有优点，比如加入了多媒体教学（可视化程度不错）和所谓寓教于乐的特点，但是从本质上说还是题库。杀毒软件据说是中国软件的骄傲，由中国权威机构评测是达到了世界领先水平，但是好象还没有得到国际权威机构的认可。游戏软件就不用提了，国内业界能够流行的游戏软件成功的秘诀众所周知，不是技术和创意，实在是归功于我们悠久的历史。字处理软件和排版软件客观的说国内的也做的不错，但是从系统的扩展性和体系结构上说和MS和Adobe相比，差距也放在那里。其实这种现状的原因很简单，一个是我们缺少创新的能力，另一个就是我们欠缺软件工程的概念，系统开发前期的需求分析、设计没有做好或者做的不够好。</p>
				<p>　　当然，我们很少怀疑自己的技术能力，我们很多时候认为这是地理环境和经济环境的原因造成了中国软件业现在的局面。当然中国软件开发人员绝对可以算是优秀的，但是想想我们软件行业龙头企业到底有多少有技术创新和专利技术呢？姑且不论这个，实际上把一个操作系统分解开来，比如文件系统、进程管理和调度、IO调度等等，也许我们可以实现其中某一块的内容，但是如何把它们合理的整合起来绝对是一个涉及到软件工程的问题。</p>
				<p>　　作为一个开发人员，我们已经习惯了自己那一套编程模式，而且我们的这种习惯也不自觉的影响着新的开发人员。所以在头脑中建立一个软件工程的作用，从某种角度上讲，要比会几种开发语言、几个编程技巧实在是重要的多。</p>
				<p>　　举一个例子来说，我们也许可以写MFC中的几个类或者是用自己的类扩展MFC，但是我们又有几个人真正去认真分析和考虑MFC架构的设计和原理呢？扪心自问，我们又有多少人能够设计出MFC这样的框架系统呢？下面就我们的题目谈一些相关的话题。 </p>
				<p>
						<strong>十、我有一个梦</strong>
				</p>
				<p>　　毋庸质疑的是，计算机的发展和人类的历史相比甚至和其他很多科技产品相比都是非常短的，从第一台计算机的研制成功到现在也没有百年的历史，但是计算机及其相关技术的发展却绝对可以说是最快的。抛开硬件的发展（硬件的发展基本上是按照摩尔定律来的，每18个月，机器的速度性能都要提高一倍），单从软件的发展来说，从体系结构来讲，我们经历了从主机结构到文件服务器结构，从客户服务器系统到基于Internet的服务器浏览器结构的体系结构的变化。从编码的角度来讲，我们经历了从最开始的机器代码到汇编代码，从高级程序语言到<a href="http://www.itisedu.com/phrase/200603011759495.html" target="_new">人工智能</a>语言，从专用的程序设计语言到通用的程序设计语言。从开发工具来讲，我们经历了从分离的开发工具（有代码编辑器，中间代码生成器和连接器）到集成的开发系统，从最简单的单行命令式调试器到方便灵活的多功能的调试器。</p>
				<p>　　但是，今天所有的软件厂商和软件开发人员依然会想起当年的黑人人权运动领袖马丁？路德？金曾经说过的一句名言我有一个梦想。是的，所有的开发人员依然怀着梦想，希望能够有一个万能的系统开发的框架和方法，只要我们沿着这个框架，我们将能开发出适合所有领域的应用系统，于是，我们在念书的时候把这个希望投到了一门课上，这么课就是软件工程。但是当我们在学完这门课的时候，我们依然没有找到这么一个框架甚至连接近这么一个框架的东西也没有碰到。</p>
				<p>　　不管我们认为软件工程可能是多么的虚无，但是所有学工科并且有逻辑头脑的人都坚信理论对实践的指导意义，因为有了爱因斯坦及其许多伟大的科学家关于能量和质量方面的理论以后，我们才造出了原子弹。但是，遗憾的是软件工程并不是一个具体的理论，它更象一门抽象的科学。软件工程是一种方法论，而不是一种具体的摸的着，看的见的产品。它告诉我们在设计一个系统的时候，我们需要进行可行性研究、计划制订、需求分析、系统设计、编码、测试、维护等等。并且对这些过程中应该做什么提出了一个指导性的东西。但是没有任何专家和标准委员会保证只要按照这些标准，我们的系统肯定会顺利完成。而且事实上，软件开发针对的领域是如此之多并不没有一种对所有领域适用的万能框架。<br />　　不管认为软件工程已经到了非常成熟的阶段还是认为软件工程依然是一个搞不懂的黑箱子，软件工程确实已经经历了三个不同的阶段。第一个阶段是软件结构化生产阶段，以结构化分析与设计、结构化评审、结构化程序设计以及结构化测试为特征。从80年代中期，软件生产开始进入以过程为中心的第二阶段，以提出过程成熟模型<a href="http://www.itisedu.com/phrase/200603051508215.html" target="_new">CMM</a>、<a href="http://www.itisedu.com/phrase/200603061000265.html" target="_new">个体软件过程</a><a href="http://www.itisedu.com/phrase/200604231319415.html" target="_new">PSP</a>和<a href="http://www.itisedu.com/phrase/200604231333525.html" target="_new">群组软件过程</a><a href="http://www.itisedu.com/phrase/200604231334415.html" target="_new">TSP</a>为标志。第三个阶段就是以软件过程、面向对象和构件重用三把斧头出现的软件工业化生产阶段。</p>
				<p>　　言归正传，我们还是回到我们的文章标题上来，我们在开发的时候是兵马未动、粮草先行还是摸着石子过河。兵马未动、粮草先行当然意味着我们在开发的时候先不忙着编写代码做程序，我们先要制订一个关于开发的方法。这点就象<a href="http://www.itisedu.com/phrase/200603141328355.html" target="_new">元数据</a>（metadata）的概念，元数据并不定义数据，它是对数据的说明，也就是通常所说的关于数据的数据。我们设计的时候也是这样，定义开发的标准，如何进行开发、怎样开发。摸着石子过河就意味着我们先不管什么理论，方法，科学的问题，我们先动手做起来，如果做的也算成功的话，那就可以按照这种模式来，实际上，在任何事情的最初，我们都是这样。从辨证唯物主义者的观点来说，就是从实践中来，然后升华到理论，再用理论来指导实践。记得一个笑话说：外国人搞软件工程是在一个黑屋子里面抓黑猫，不过到现在还是没有抓住，而中国人是在一个黑屋子里面，而里面连猫都没有，然后有人说，我已经抓到猫了。这个笑话一方面是说明直到现在，软件工程还是一个在继续探索、发展的过程，另一个侧面也说明中国搞软件工程摸不着边的局面。</p>
				<p>　　实际上，不管有没有软件工程，不管是否存在一个万能的框架系统，我们的应用系统还是要做，各种各样的软件还是要开发。说到底，软件系统是因为有需求才存在的。有了应用域才有了软件存在的意义。很多时候，我们可以看到国外有各种各样的软件和创新，而我们没有，我们更多的是模仿和一些重复的功能相近的软件的原因就是因为我们没有这方面的需求，这也正解释了为什么ERP系统能在国外开展的很好，而在国内失败多于成功的原因。一方面当然是因为我们的企业按照市场经济发展的时间还不长，另一方面是我们的企业确实也没有这方面的需求。</p>
				<p>
				</p>
				<p>
						<font face="Verdana">
						</font>
				</p>
				<font face="Verdana">
						<strong>十一、软件工程的发展方向</strong>
				</font>
				<p>
				</p>
				<p>
						<font face="Verdana">      “<a href="http://www.itisedu.com/phrase/200603291800375.html" target="_new">敏捷开发</a>”（<a href="http://www.itisedu.com/phrase/200604240917025.html" target="_new">Agile Development</a>）被认为是软件工程的一个重要的发展。它强调软件开发应当是能够对未来可能出现的变化和不确定性作出全面反应的。</font>
				</p>
				<p>
						<font face="Verdana">      敏捷开发被认为是一种“轻量级”的方法。在轻量级方法中最负盛名的应该是“<a href="http://www.itisedu.com/phrase/200603071747045.html" target="_new">极限编程</a>”（<a href="http://www.itisedu.com/phrase/200604231325295.html" target="_new">Extreme Programming</a>，简称为<a href="http://www.itisedu.com/phrase/200604231325145.html" target="_new">XP</a>）。而与轻量级方法相对应的是“重量级方法”的存在。重量级方法强调以开发过程为中心，而不是以人为中心。重量级方法的例子比如CMM/PSP/TSP。</font>
				</p>
				<p>
				</p>
		</font>
		<font face="Verdana"> </font><img src ="http://www.cnitblog.com/tilan/aggbug/21893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-15 23:03 <a href="http://www.cnitblog.com/tilan/articles/21893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows上安装apache2.0.59 + svn1.4.0 + 自动邮件通知</title><link>http://www.cnitblog.com/tilan/articles/21890.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 15 Jan 2007 14:16:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21890.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21890.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21890.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21890.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21890.html</trackback:ping><description><![CDATA[<div id="articlebody">前几天写了linux版的，受广大论友的邀请，特写此windows的版本，希望大家能够共同为此论坛作出贡献，也希望越来越多的人能够更加方便地使用SVN。<br /><br />OS: Windows XP SP2<br /><br />1) 安装Apache Server<br />2) 安装SVN<br />3) 配置邮件通知以及修改log权限<br /><br />1. 安装apache2.0.59,从这里可以下载到<a href="http://apache.justdn.org/httpd/binaries/win32/apache_2.2.3-win32-x86-no_ssl.msi" target="_blank">http://apache.justdn.org/httpd/binaries/win32/apache_2.2.3-win32-x86-no_ssl.msi</a><br />安装过程中设置以下参数：<br />Network Domain: localhost<br />Server name: localhost<br />Administrator's Emai Address: <a href="mailto:windymax@126.com">windymax@126.com</a><br />安装到默认路径为C:\Program Files\Apache Group\Apache2<br /><br />2. 安装subversion1.4.0,从这里下载<a href="http://www.iusesvn.com/bbs/download/svn-win32-1.4.0.zip" target="_blank">http://www.iusesvn.com/bbs/download/svn-win32-1.4.0.zip</a><br />安装到默认路径为C:\Program Files\Subversion<br />默认安装后，在apache的配置文件中会自动加入以下两行。<br />LoadModule dav_svn_module "C:/Program Files/Subversion/bin/mod_dav_svn.so"<br />LoadModule authz_svn_module "C:/Program Files/Subversion/bin/mod_authz_svn.so"<br />把这行的注释去掉<br />LoadModule dav_fs_module modules/mod_dav_fs.so<br /><br />拷贝C:\Program Files\Subversion\bin下的libdb44.dll到这个目录下C:\Program Files\Apache Group\Apache2\bin<br />打开apache的配置文件在末尾处加入以下参数：<br />&lt;Location /svn&gt;<br />DAV svn<br />SVNPath d:\svndata\test<br />AuthType Basic<br />AuthName "Windy SVN"<br />AuthUserFile d:\svndata\test\passwd<br />Require valid-user<br />&lt;/Location&gt;<br />保存。(在这里权限文件我不多讲了，大家多做实验就明白了)<br /><br />建立仓库<br />打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />C:\Documents and Settings\windy&gt; d:   //进入D盘(因为我们要在D盘下创建仓库)<br />D:\&gt; md svndata   //创建一个名叫svndata的目录<br />D:\&gt; c:   //进入C盘<br />C:\Documents and Settings\windy&gt; cd\   //退到C盘根目录<br />C:\Documents and Settings\windy&gt; cd C:\Program Files\Subversion\bin  //进入subversion/bin目录<br />C:\Program Files\Subversion\bin&gt; svnadmin create d:\svndata\test   //用svnadmin命令创建名为test的仓库(这条命令成功后，在test下会出现很多文件夹和文件)<br />C:\Program Files\Subversion\bin&gt; cd C:\Program Files\Apache Group\Apache2\bin   //进入apache\bin目录<br />C:\Program Files\Apache Group\Apache2\bin&gt; htpasswd -cm d:\svndata\test\passwd user1   //用htpasswd命令创建第一个用户(user1)，同时生成密码认证文件，c参数为create,m参数为MD5加密方式<br />New password: ******<br />Re-type new password: ******<br />Adding password for user user1   //加入用户成功<br />C:\Program Files\Apache Group\Apache2\bin&gt; htpasswd -m d:\svndata\test\passwd user2   //用htpasswd命令创建第二个用户(user2),注意如果在这时加入c参数会覆盖掉之前创建的用户及文件。<br />New password: ******<br />Re-type new password: ******<br />Adding password for user user2   //加入用户成功<br /><br />重新启动apache，进行测试。<br />用IE打开<a href="http://localhost/svn" target="_blank">http://localhost/svn</a>，这时应该可以看到<br />Revision 0: /<br />--------------------------------------------------------------------------------<br />Powered by Subversion version 1.4.0 (r21228).    //说明我们已经配置成功了<br /><br />3. 配置邮件通知以及修改log权限<br />下载所需要的软件包<br />--在这里下载<a href="http://downloads.activestate.com/ActivePerl/Windows/5.8/ActivePerl-5.8.8.819-MSWin32-x86-267479.msi" target="_blank">http://downloads.activestate.com/ActivePerl/Windows/5.8/ActivePerl-5.8.8.819-MSWin32-x86-267479.msi</a>到D盘根目录下。<br />--下载<a href="http://download.microsoft.com/download/vc15/patch/1.52/w95/en-us/nmake15.exe" target="_blank">http://download.microsoft.com/download/vc15/patch/1.52/w95/en-us/nmake15.exe</a>到D盘根目录下。<br />--下载<a href="http://search.cpan.org/CPAN/authors/id/K/KW/KWILLIAMS/Module-Build-0.2805.tar.gz" target="_blank">http://search.cpan.org/CPAN/authors/id/K/KW/KWILLIAMS/Module-Build-0.2805.tar.gz</a>到D盘根目录下，将Module-Build-0.2805.tar.gz解压到D盘。<br />--下载<a href="http://search.cpan.org/CPAN/authors/id/G/GB/GBARR/Authen-SASL-2.10.tar.gz" target="_blank">http://search.cpan.org/CPAN/authors/id/G/GB/GBARR/Authen-SASL-2.10.tar.gz</a>到D盘根目录下，将Authen-SASL-2.10.tar.gz解压到D盘。<br />--下载<a href="http://search.cpan.org/CPAN/authors/id/A/AP/APLEINER/Net-SMTP_auth-0.08.tar.gz" target="_blank">http://search.cpan.org/CPAN/authors/id/A/AP/APLEINER/Net-SMTP_auth-0.08.tar.gz</a>到D盘根目录下，将Net-SMTP_auth-0.08.tar.gz解压到D盘。<br />--下载<a href="http://search.cpan.org/CPAN/authors/id/D/DW/DWHEELER/SVN-Notify-2.64.tar.gz" target="_blank">http://search.cpan.org/CPAN/authors/id/D/DW/DWHEELER/SVN-Notify-2.64.tar.gz</a>到D盘根目录下，将SVN-Notify-2.64.tar.gz解压到D盘。<br /><br />开始安装Perl以及模块<br />--安装Active Perl，一路默认安装，默认路径为C:\Perl<br />--测试perl是否正常工作(这步很关键)<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />   C:\Documents and Settings\windy&gt; perl   //如果没有报错，说明已经正常工作，因为安装perl时，安装程序会自动设置好环境perl(如果在系统环境变量中没有自动添加，需手动添加perl变量环境)，具体做法是：<br />  "回到桌面" -&gt; "鼠标右键我的电脑" -&gt; "属性" -&gt; "高级" -&gt; "环境变量" -&gt; "系统变量中Path最前面中添加C:\Perl\bin\;" -&gt;"完成"。   //测试，如果报错，请重新启动电脑后进行测试。<br />--将nmake15.exe改名为nmake.exe后拷贝到c:\windows\system32目录下。<br />--测试nmake是否是否正常工作(这步很关键)<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />   C:\Documents and Settings\windy&gt; nmake   <br />  Microsoft (R) Program Maintenance Utility   Version 1.50<br />  Copyright (c) Microsoft Corp 1988-94. All rights reserved.   //说明nmake已经正常工作<br />--安装Module-Build模块<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />  C:\Documents and Settings\windy&gt; d:<br />  D:\&gt; cd Module-Build-0.2805<br />  D:\Module-Build-0.2805&gt; perl Build.PL   //收集系统环境变量<br />  D:\Module-Build-0.2805&gt; Build   //进行编译<br />  D:\Module-Build-0.2805&gt; Build test   //测试<br />  D:\Module-Build-0.2805&gt; Build install   //编译后安装  <br />--安装Perl模块Authen::SASL，进入Authen-SASL-2.10目录，首先开打Makefile.PL<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />  C:\Documents and Settings\windy&gt; d:<br />  D:\&gt; cd Authen-SASL-2.10<br />  D:\Authen-SASL-2.10&gt; perl Makefile.PL   //收集系统环境变量<br />  出现选择安装提示，y和n先后安装一次<br />  D:\Authen-SASL-2.10&gt; nmake   //进行编译<br />  D:\Authen-SASL-2.10&gt; nmake test  //进行测试<br />  D:\Authen-SASL-2.10&gt; nmake install   //编译后安装<br />--安装Perl模块Net::SMTP_auth<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />  C:\Documents and Settings\windy&gt; d:<br />  D:\&gt; cd Net-SMTP_auth-0.08<br />  D:\Net-SMTP_auth-0.08&gt; perl Makefile.PL   //收集系统环境变量<br />  D:\Net-SMTP_auth-0.08&gt; nmake   //进行编译<br />  D:\Net-SMTP_auth-0.08&gt; nmake test   //测试<br />  D:\Net-SMTP_auth-0.08&gt; nmake install   //编译后安装<br />--安装Perl模块SVN::Notify<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />  C:\Documents and Settings\windy&gt; d:<br />  D:\&gt; cd SVN-Notify-2.64<br />  D:\SVN-Notify-2.64&gt; perl Build.PL   //收集系统环境变量<br />  D:\SVN-Notify-2.64&gt; Build   //进行编译<br />  D:\SVN-Notify-2.64&gt; Build test   //测试<br />  D:\SVN-Notify-2.64&gt; Build installl   //编译后安装  <br />--安装完毕。<br /><br />设置邮件通知<br />--拷贝post-commit.tmpl为post-commit.bat<br />--删除末尾参数，增加下面参数：<br />set REPOS=%1<br />set REV=%2<br />SET PATH=C:\PERL\BIN;<br />SET OS=Windows_NT<br />SET SystemRoot=C:\WINDOWS<br />svnnotify --repos-path %REPOS% -r %REV% --to <a href="mailto:windy@126.com">windy@126.com</a> --smtp smtp.126.com -H HTML::ColorDiff -d --subject-prefix [Windy SVN]<br />//--to要跟你要发送给谁的邮件地址，--smtp后跟你自已的邮件服务器地址，比如mail.126.com<br /><br />设置log可以修改<br />--拷贝pre-revprop-change.tmpl为pre-revprop-change.bat<br />--删除末尾参数，增加下面参数：<br />REM SVN pre-revprop-change hook allows edit of logmessages from TSVN <br /><br />setlocal<br />set REPOS=%1<br />set REV=%2<br />set USER=%3<br />set PROPNAME=%4<br />set ACTION=%5<br /><br />if  not "%ACTION%"=="M" goto refuse<br />if  not "%PROPNAME%"=="svn:log" goto refuse<br />goto OK<br /><br />:refuse<br />echo Cann't set %PROPNAME%/%ACTION%, only svn:log is allowed 1&gt;&amp;2<br />endlocal<br />exit 1<br /><br />:OK<br />endlocal<br />exit 0<br /><br />完成所有设置，开始测试。<br /><br /><script type="text/javascript"><!--
google_ad_client = "pub-7369080997543530";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text_image";
google_ad_channel = "9983550079";
//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script><br /><br /></div>
		<div id="commentlist">
				<h3>
						<span class="smalltxt">
						</span> </h3>
				<ul class="messagelist">
						<li>
								<div>反馈一：<br />--安装Perl模块SVN::Notify<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />  C:\Documents and Settings\windy&gt; d:<br />  D:\&gt; cd SVN-Notify-2.64<br />  D:\SVN-Notify-2.64&gt; perl Build.PL   //收集系统环境变量<br />  D:\SVN-Notify-2.64&gt; Build   //进行编译<br />  D:\SVN-Notify-2.64&gt; Build test   //测试<br />  D:\SVN-Notify-2.64&gt; Build installl   //编译后安装  <br />————这些命令运行不下去啊，报错:'build'不是内部或外部命令，也不是可运行的程序或批处理文件！！！<br />反馈二：<br />--拷贝post-commit.tmpl为post-commot.bat<br />————应该是必为post-commit.bat<br />反馈三：<br />设置log可以修改<br />--拷贝post-commit.tmpl为post-commot.bat<br />————应该是改 pre-revprop-change.tmp为pre-revprop-change.bat</div>
						</li>
						<li>
								<h4>
										<span class="smalltxt">
										</span> </h4>
								<div>
										<p style="FONT-WEIGHT: bold; MARGIN: 1em 1em 0px">QUOTE:</p>
										<blockquote style="BORDER-RIGHT: #ddd 1px dotted; PADDING-RIGHT: 0.5em; BORDER-TOP: #ddd 1px dotted; PADDING-LEFT: 0.5em; PADDING-BOTTOM: 0.5em; MARGIN: 0px 1em 1em; BORDER-LEFT: #ddd 1px dotted; LINE-HEIGHT: 1.8em; PADDING-TOP: 0.5em; BORDER-BOTTOM: #ddd 1px dotted">
												<br />反馈一：<br />--安装Perl模块SVN::Notify<br />  打开CMD命令行界面，"开始" -&gt; "运行" -&gt; "cmd" -&gt; "回车"<br />  C:\Documents and Settings\windy&gt; d:<br />  D:\&gt; ... </blockquote>perl Build.PL 你执行成功了吗？<br /><br />D:\SVN-Notify-2.64&gt;perl Build.pl<br />Deleting _build<br />Creating custom builder _build\lib\My\Builder.pm in _build\lib\My<br />Checking whether your kit is complete...<br />Looks good<br /><br />Checking prerequisites...<br />* Optional prerequisite Test:<img title="点击图片可在新窗口打开" style="CURSOR: pointer" src="http://www.iusesvn.com/bbs/images/smilies/tongue.gif" align="absMiddle" border="0" />od::Coverage is not installed<br />* Optional prerequisite Test:<img title="点击图片可在新窗口打开" style="CURSOR: pointer" src="http://www.iusesvn.com/bbs/images/smilies/tongue.gif" align="absMiddle" border="0" />od is not installed<br /><br />ERRORS/WARNINGS FOUND IN PREREQUISITES.  You may wish to install the versions<br />of the modules indicated above before proceeding with this installation<br /><br />Creating new 'Build' script for 'SVN-Notify' version '2.64'<br /><br />D:\SVN-Notify-2.64&gt;Build<br />lib\SVN\Notify\HTML.pm -&gt; blib\lib\SVN\Notify\HTML.pm<br />lib\SVN\Notify\HTML\ColorDiff.pm -&gt; blib\lib\SVN\Notify\HTML\ColorDiff.pm<br />lib\SVN\Notify\Alternative.pm -&gt; blib\lib\SVN\Notify\Alternative.pm<br />lib\SVN\Notify.pm -&gt; blib\lib\SVN\Notify.pm<br />bin\svnnotify -&gt; blib\script\svnnotify<br />Manifying blib\script/svnnotify -&gt; blib\bindoc\svnnotify.1<br />Manifying blib\lib/SVN/Notify.pm -&gt; blib\libdoc\SVN.Notify.3<br />Manifying blib\lib/SVN/Notify/HTML.pm -&gt; blib\libdoc\SVN.Notify.HTML.3<br />Manifying blib\lib/SVN/Notify/HTML/ColorDiff.pm -&gt; blib\libdoc\SVN.Notify.HTML<br />olorDiff.3<br />Manifying blib\lib/SVN/Notify/Alternative.pm -&gt; blib\libdoc\SVN.Notify.Alterna<br />ve.3<br />HTMLifying blib\script\svnnotify -&gt; blib\binhtml\bin\svnnotify.html<br />HTMLifying blib\lib\SVN\Notify.pm -&gt; blib\libhtml\site\lib\SVN\Notify.html<br />Build: blib\lib\SVN\Notify.pm: cannot resolve L&lt;perlio|perlio&gt; in paragraph 87<br />HTMLifying blib\lib\SVN\Notify\HTML.pm -&gt; blib\libhtml\site\lib\SVN\Notify\HTM<br />html<br />HTMLifying blib\lib\SVN\Notify\HTML\ColorDiff.pm -&gt; blib\libhtml\site\lib\SVN\<br />tify\HTML\ColorDiff.html<br />Build: blib\lib\SVN\Notify\HTML\ColorDiff.pm: unknown pod directive 'head1' in<br />aragraph 56.  ignoring.<br />HTMLifying blib\lib\SVN\Notify\Alternative.pm -&gt; blib\libhtml\site\lib\SVN\Not<br />y\Alternative.html<br />t\bin\testsvnlook -&gt; t\scripts\testsvnlook<br />t\bin\testsendmail -&gt; t\scripts\testsendmail<br /><br />D:\SVN-Notify-2.64&gt;Build test<br />t\alt..............ok<br />t\base.............ok<br />t\errors...........ok<br />t\html.............ok<br />t\htmlcolordiff....ok<br />t\options..........ok<br />t\pod-coverage.....skipped<br />        all skipped: Test:<img title="点击图片可在新窗口打开" style="CURSOR: pointer" src="http://www.iusesvn.com/bbs/images/smilies/tongue.gif" align="absMiddle" border="0" />od::Coverage 1.06 required for testing POD covera<br />t\pod..............skipped<br />        all skipped: Test:<img title="点击图片可在新窗口打开" style="CURSOR: pointer" src="http://www.iusesvn.com/bbs/images/smilies/tongue.gif" align="absMiddle" border="0" />od 1.20 required for testing POD<br />t\script...........ok<br />t\smtp.............ok<br />All tests successful, 2 tests skipped.<br />Files=10, Tests=714, 85 wallclock secs ( 0.00 cusr +  0.00 csys =  0.00 CPU)<br /><br />D:\SVN-Notify-2.64&gt;Build install<br />Skipping C:\Perl\man\man1\svnnotify.1<br />Skipping C:\Perl\html\bin\svnnotify.html<br />Skipping C:\Perl\site\lib\SVN\Notify.pm<br />Skipping C:\Perl\site\lib\SVN\Notify\HTML.pm<br />Skipping C:\Perl\site\lib\SVN\Notify\Alternative.pm<br />Skipping C:\Perl\site\lib\SVN\Notify\HTML\ColorDiff.pm<br />Skipping C:\Perl\man\man3\SVN.Notify.3<br />Skipping C:\Perl\man\man3\SVN.Notify.HTML.3<br />Skipping C:\Perl\man\man3\SVN.Notify.HTML.ColorDiff.3<br />Skipping C:\Perl\man\man3\SVN.Notify.Alternative.3<br />Skipping C:\Perl\html\site\lib\SVN\Notify.html<br />Skipping C:\Perl\html\site\lib\SVN\Notify\HTML.html<br />Skipping C:\Perl\html\site\lib\SVN\Notify\Alternative.html<br />Skipping C:\Perl\html\site\lib\SVN\Notify\HTML\ColorDiff.html<br />Skipping C:\Perl\bin\svnnotify<br />Skipping C:\Perl\bin\svnnotify.bat<br />Writing C:\Perl\site\lib\auto\SVN\Notify\.packlist<br /><br /></div>
						</li>
				</ul>
		</div>
		<script type="text/javascript">
				<!--
google_ad_client = "pub-3874079075380071";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
//2007-03-19: 3G-move, 三星, 摩托罗拉, 索爱, 诺基亚
google_ad_channel = "1730597762+1709572468+0778807001+6838187825+8377398382";
//-->
		</script>
		<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
		</script><img src ="http://www.cnitblog.com/tilan/aggbug/21890.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-15 22:16 <a href="http://www.cnitblog.com/tilan/articles/21890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Subversion 服务器mailer指南</title><link>http://www.cnitblog.com/tilan/articles/21835.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 12 Jan 2007 15:23:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21835.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21835.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21835.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21835.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21835.html</trackback:ping><description><![CDATA[<font size="5">
				<font face="Arial">Subversion </font>
				<font face="黑体">服务器</font>
				<font face="Arial">mailer</font>
				<font face="黑体">指南</font>
		</font>
		<font color="#000000">
				<font face="Times New Roman">
						<font size="3">Subversion</font>
						<font face="宋体">服务器为我们提供了很多的</font>
						<font face="Times New Roman">hook</font>
						<font face="宋体">，可以让我们在有人对仓库进行动作的时候进行一些相应的处理，这些</font>
						<font face="Times New Roman">hooks</font>
						<font face="宋体">都放在仓库目录下的</font>
						<font face="Times New Roman">hooks</font>
						<font face="宋体">子目录下面，具体</font>
						<font face="Times New Roman">hook</font>
						<font face="宋体">的含义可以参考</font>
						<font face="Times New Roman">Subversion</font>
						<font face="宋体">的帮助的第</font>
						<font face="Times New Roman">5</font>
						<font face="宋体">章的</font>
				</font>
				<font color="black">
						<font face="Arial">
								<a href="http://svnbook.red-bean.com/nightly/en/svn.reposadmin.create.html#svn.reposadmin.create.hooks" target="_blank">
										<u>
												<font color="#800080">Hook Scripts</font>
										</u>
								</a>
						</font>
				</font>
				<font color="#000000">
						<font face="宋体">。（</font>
						<font face="Times New Roman">Subversion</font>
						<font face="宋体">的在线官方文档</font>
				</font>
				<a href="http://svnbook.red-bean.com/" target="_blank">
						<u>
								<font face="Times New Roman">
										<font color="#800080">http://svnbook.red-bean.com/</font>
								</font>
						</u>
				</a>
				<font color="#000000">
						<font face="宋体">，有多种语言版本），那么我们怎么用这些</font>
						<font face="Times New Roman">hooks</font>
						<font face="宋体">来帮我们更加有效的利用</font>
						<font face="Times New Roman">Subversion</font>
						<font face="宋体">呢。常用的一个方面是当有人提交新版本的时候能够自动的发送邮件给指定的一群人，方便交流和管理。在</font>
						<font face="Times New Roman">Subversion 1.3</font>
						<font face="宋体">版本之前也有人用</font>
						<font face="Times New Roman">pre-commit</font>
						<font face="宋体">来让</font>
						<font face="Times New Roman">svnserve</font>
						<font face="宋体">也能根据目录来实现写权限，不过现在</font>
						<font face="Times New Roman">1.3</font>
						<font face="宋体">版本的</font>
						<font face="Times New Roman">svnserve</font>
						<font face="宋体">已经能够</font>
						<font face="宋体">使用</font>
						<b>
								<font face="Times New Roman">mod_authz_svn</font>
						</b>
						<font face="宋体">相同的首选策略文件。</font>
				</font>
		</font>
		<br />
		<font size="3">
				<font color="#000000">
						<font face="宋体">下面我们以</font>
						<font face="Times New Roman">post-commit</font>
						<font face="宋体">为例，实现有人提交新版本的时候能够自动的发送邮件给指定的一群人。当有用户提交新版本的时候，会触发</font>
						<font face="Times New Roman">post-commit</font>
						<font face="宋体">这个</font>
						<font face="Times New Roman">hook script</font>
						<font face="宋体">，它会接受到</font>
						<font face="宋体">仓库路径和当前提交版本的版本号这</font>
						<font face="Arial">2</font>
						<font face="宋体">个参数。接下来，我们怎么利用这个</font>
						<font face="Arial">script</font>
						<font face="宋体">来做我们所需要的事情呢，通过使用</font>
						<font face="Arial">mailer.py</font>
						<font face="宋体">这个</font>
						<font face="Arial">python</font>
						<font face="宋体">脚本就可以实现我们的需求了。首先</font>
						<font face="Arial">check out</font>
						<font face="宋体">这个文件，</font>
				</font>
				<font face="Arial">
						<a href="http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/mailer" target="_blank">
								<u>
										<font color="#0000ff">http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/mailer</font>
								</u>
						</a>
				</font>
				<font color="#000000">
						<font face="宋体">，一般来说安装好</font>
						<font face="Arial">python 2.3</font>
						<font face="宋体">和</font>
						<font face="Arial">
						</font>
						<font face="Times New Roman">Subversion</font>
						<font face="宋体">的</font>
						<font face="Times New Roman">python binding</font>
						<font face="宋体">之后就可以运行这个脚本了。</font>
				</font>
		</font>
		<br />
		<font size="3">
				<font color="#000000">
						<font face="宋体">首先我们看看这个脚本如何使用，不带参数执行该脚本，结果如下：</font>
				</font>
		</font>
		<br />
		<font face="Arial">
				<font style="FONT-SIZE: 9pt">
						<font color="#000000">USAGE: mailer.py commit<font face="Arial">      </font>REPOS REVISION [CONFIG-FILE]</font>
						<br />
						<font face="Arial">
								<font style="FONT-SIZE: 9pt">
										<font face="Arial">
												<font color="#000000">       mailer.py propchange  REPOS REVISION AUTHOR PROPNAME [CONFIG-FILE]</font>
										</font>
										<br />
										<font face="Arial">
												<font style="FONT-SIZE: 9pt">
														<font face="Arial">
																<font color="#000000">       mailer.py propchange2 REPOS REVISION AUTHOR PROPNAME ACTION</font>
														</font>
														<br />
														<font face="Arial">
																<font style="FONT-SIZE: 9pt">
																		<font face="Arial">
																				<font color="#000000">                             [CONFIG-FILE]</font>
																		</font>
																		<br />
																		<font face="Arial">
																				<font style="FONT-SIZE: 9pt">
																						<font face="Arial">
																								<font color="#000000">       mailer.py lock        REPOS AUTHOR [CONFIG-FILE]</font>
																						</font>
																						<br />
																						<font face="Arial">
																								<font style="FONT-SIZE: 9pt">
																										<font color="#000000">
																												<font face="Arial">       mailer.py unlock      </font>REPOS AUTHOR [CONFIG-FILE]</font>
																										<br />
																										<font size="3">
																												<font color="#000000">
																														<font face="宋体">第</font>
																														<font face="Arial">2</font>
																														<font face="宋体">个参数是对应不同的</font>
																														<font face="Arial">hook</font>
																														<font face="宋体">的，各参数对应的</font>
																														<font face="Arial">hook</font>
																														<font face="宋体">如下</font>
																														<font face="Arial">
																														</font>
																												</font>
																										</font>
																										<table class="t_table" align="center">
																												<tbody>
																														<tr>
																																<td width="227">
																																		<font size="3">
																																				<font color="#000000">
																																						<font face="宋体">参数</font>
																																						<font face="Arial">
																																						</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">hook</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																														</tr>
																														<tr>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">Commit</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">*commit </font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																														</tr>
																														<tr>
																																<td width="227">
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">Propchange</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">*revprop-change </font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																														</tr>
																														<tr>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">Propchange2</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">post-revprop-change </font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																														</tr>
																														<tr>
																																<td width="227">
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">Lock</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">*lock <font face="Arial">     </font></font>
																																				</font>
																																				<br />
																																		</font>
																																</td>
																														</tr>
																														<tr>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">Unlock</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																																<td>
																																		<font face="Arial">
																																				<font size="3">
																																						<font color="#000000">*unlock</font>
																																				</font>
																																		</font>
																																		<br />
																																</td>
																														</tr>
																												</tbody>
																										</table>
																								</font>
																						</font>
																				</font>
																		</font>
																</font>
														</font>
												</font>
										</font>
								</font>
						</font>
				</font>
		</font>
		<br />这里我们用的是post-commit hook，于是我们选择用commit参数。REPOS REVISION由hook提供，我们只需要指定CONFIG-FILE文件，如果没有指定该文件，mailer将会依次在REPOS/conf/、mailer所在目录查找。<br /><br />我们只要在post-commit hook中加上 mailer commit “$1” “$2” mailer.conf或者如果你的服务器架设在windows下的话，用python c:\repos\hooks\mailer.py commit %1 %2 c:\repos\hooks\mailer.conf，mailer.py的路径最好用绝对路径，因为svnserve在hook启动时候的路径是svnserve所在目录。这样我们就可以让Subversion server在有人commit之后尝试发送邮件给我们了。这里为什么要用尝试，因为还有另外一份很重要的文件需要我们修改后才能正常发送邮件。<br /><br />这个重要的文件就是mailer.conf文件，在先前我们check out的文件夹下面有一个简单的例子mailer.conf.example，我们逐行解释一下。注意，不要随便注释某些参数，可能会导致脚本无法运行。<br /><br />[general]<br /><br />#mail_command = /usr/sbin/sendmail<br /><br /># mailer模块发送邮件的方式有3种，Pipe，SMTP，stdout<br /><br />#mail_command将指定Pipe方式发送给mail_command指定的程序<br /><br /><br /><br />#smtp_hostname = localhost<br /><br />#smtp_hostname将指定SMTP方式发送给smtp_hostname指定的服务器<br /><br /># Username and password for SMTP servers requiring authorisation<br /><br />#smtp_username = example<br /><br />#smtp_password = example<br /><br /><br /><br />#如果既没有指定Pipe方式也没有指定SMTP方式，则发送到stdout<br /><br /><br /><br />[defaults]<br /><br />#这里定义一些默认的行为<br /><br />diff = /usr/bin/diff -u -L %(label_from)s -L %(label_to)s %(from)s %(to)s<br /><br />#diff程序以及参数等<br /><br /><br /><br />commit_subject_prefix =<br /><br />#commit动作的邮件的标题前缀<br /><br /><br /><br />propchange_subject_prefix =<br /><br /># propchange动作的邮件的标题前缀<br /><br /><br /><br />lock_subject_prefix =<br /><br /># lock动作的邮件的标题前缀<br /><br /><br /><br />unlock_subject_prefix =<br /><br /># unlock动作的邮件的标题前缀<br /><br /><br /><br />from_addr = <a href="mailto:invalid@example.com">invalid@example.com</a><br /><br />#邮件的from addresses<br /><br /><br /><br />to_addr = <a href="mailto:invalid@example.com">invalid@example.com</a><br /><br />#邮件的接收地址，用空格分隔，这里也可以用mapping_specification来表示<br /><br /><br /><br />reply_to =<br /><br />#邮件的回复地址<br /><br /><br /><br />generate_diffs = add copy modify<br /><br />#diff的设置，这里设置什么时候来使用diff，有效地设置是add,copy,modify,delete<br /><br />#如果不想用diff，可以其他无效的单词来设置，如“no”，如果为空，<br /><br />#则相当于add,copy,modify,delete同时有效<br /><br /><br /><br />suppress_deletes = yes<br /><br />#如果generate_diffs为空，delete选项无效 （不建议使用这种方式）<br /><br /><br /><br />#suppress_adds = yes<br /><br />#如果generate_diffs为空，add选项无效 （不建议使用这种方式）<br /><br /><br /><br />show_nonmatching_paths = yes<br /><br />#是否显示不匹配的路径。<br /><br /><br /><br /># truncate_subject = 200<br /><br />#邮件主题的截取长度，0为关闭，如果注释，则为0<br /><br /># --------------------------------------------------------------------------<br /><br /><br /><br />[maps]<br /><br />#maps section定义一些选项的映射关系，<br /><br />#可以通过option_name_to_remap = mapping_specification的形式来定义选项的取值。<br /><br />#可以remap的option_name 为defaults section中除diff外其他的key值<br /><br />#注意mapping_specification不要用大写字母开头，会导致无效。<br /><br />#一个简单的例子如下<br /><br />#[for game]<br /><br />#for_paths = game<br /><br />#to_addr = game<br /><br />#[maps]<br /><br />#to_addr = [mailing-lists]<br /><br />#[ mailing-lists]<br /><br />#game = <a href="mailto:a@abc.com">a@abc.com</a><a href="mailto:b@abc.com">b@abc.com</a> c&lt;<a href="mailto:c@abc.com">c@abc.com</a>&gt;<br /><br /><br /><br />#其他的section均为用户自定义的group<br /><br />#自定义的group可重定义defaults section中间定义的选项的取值<br /><br />#如何匹配这些group是由<br /><br />#   for_repos<br /><br />#   for_paths<br /><br />#这2个选项的定义来决定的<br /><br />#一个简单的例子如下:<br /><br />#仓库的结构如下<br /><br />#   REPOS/<br /><br />#     clients/<br /><br />#       gsvn/<br /><br />#       rapidsvn/<br /><br />#       winsvn/<br /><br /># 可以用正则表达式来匹配某些目录，同时定义一个字符串变量NAME，<br /><br /># %(NAME)s就可以获得该变量的值，如：<br /><br />#   for_paths = clients/(?P&lt;client&gt;[^/]*)($|/)<br /><br />#   to_addr = commits@%(client)s.tigris.org<br /><br />#一个预定义的变量为author，它缺省由mailer.py的AUTHOR定义或者是<br /><br />#该版本的author，如果没有定义前面2个的值，author的值为"no_author"<br /><br /><br /><br />配置好这个文件之后，我们的邮件系统就可以正式投入运营啦，通过一些手段，我们也可以把这个文件放入一个仓库中便于进行有效的管理。<br /><script type="text/javascript"><!--
google_ad_client = "pub-3874079075380071";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
//2007-03-19: 3G-move, 三星, 摩托罗拉, 索爱, 诺基亚
google_ad_channel = "1730597762+1709572468+0778807001+6838187825+8377398382";
//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script><img src ="http://www.cnitblog.com/tilan/aggbug/21835.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-12 23:23 <a href="http://www.cnitblog.com/tilan/articles/21835.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Subversion的其他属性</title><link>http://www.cnitblog.com/tilan/articles/21818.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 12 Jan 2007 06:44:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21818.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21818.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21818.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21818.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21818.html</trackback:ping><description><![CDATA[<p>我们已经详细讲述了Subversion存储和检索版本库中不同版本的文件和目录的细节，并且用了好几个章节来论述这个工具的基本功能。到此为止，Subversion还仅仅表现出一个普通的版本控制理念。但是Subversion并没有就此止步。</p>
		<p>作为目录和文件版本化的补充，Subversion提供了对每一个版本化的目录和文件添加、修改和删除版本化的元数据的接口，我们用<em class="firstterm">属性</em>来表示这些元数据。我们可以认为它们是一个两列的表，附加到你的工作拷贝的每个条目上，映射属性名到任意的值。一般来说，属性的名称和值可以是你希望的任何值，限制就是名称必须是可读的文本，并且最好的一点是这些属性也是版本化的，就像你的文本内容文件，你可以像提交文本修改一样修改、提交和恢复属性修改，当你更新时也会接收到别人的属性修改。</p>
		<div class="sidebar">
				<p class="title">
						<b>Subversion的其他属性</b>
				</p>
				<p>Subversion的属性也可以在别的地方出现，就像文件和目录可能附加有任意的属性名和值，每个修订版本作为一个整体也可以附加任意的属性，也有同样的限制—可读的文本名称和任何你希望的，二进制值—除了修订版本不是版本化的，参见<a title="未受版本控制的属性" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5.html#svn-ch-5-sect-1.2">“未受版本控制的属性”一节</a>获得版本化的属性信息。</p>
		</div>
		<p>在本小节，我们将会检验这个工具—不仅是对Subversion的用户，也对Subversion本身—对于属性的支持。你会学到与属性相关的<span><strong class="command">svn</strong></span>子命令，和属性怎样影响你的普通Subversion工作流，希望你会感到Subversion的属性可以提高你的版本控制体验。</p>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-7-sect-2.1">
												</a>为什么需要属性？</h3>
								</div>
						</div>
				</div>
				<p>属性可能会是工作拷贝的有益补充，实际上，Subversion本身使用属性来存放特殊的信息，作为支持特别操作的一种方法，同样，你也可以使用属性来实现自己的目的，当然，你对属性作的任何事情也可以针对普通的版本化文件，但是先考虑下面Subversion使用属性的例子。</p>
				<p>假定你希望设计一个网站存放许多数码图片，并且显示他们的标题和时间戳，现在你的图片集经常修改，所以你希望你的网站能够尽量的自动化，这些图片可能非常大，所以根据这个网站的特性，你希望在网站给用户提供图标图像。你可以用传统的文件做这件事，你可以有一个<code class="filename">image123.jpg</code>和一个<code class="filename">image123-thumbnail.jpg</code>对应在同一个目录，有时候你希望保持文件名相同，你可以使用不同的目录，如<code class="filename">thumbnails/image123.jpg</code>。你可以用一种相似的样式来保存你的标题和时间戳同原始图像文件分开。很快你的目录树会是一团糟，每个新图片的添加都会成倍的增加混乱。</p>
				<p>现在考虑使用Subversion文件的属性来做相同的设置，想象我们有一个单独的图像文件<code class="filename">image123.jpg</code>，然后这个文件的属性集包括<code class="literal">caption</code>、<code class="literal">datestamp</code>甚至<code class="literal">thumbnail</code>。现在你的工作拷贝目录看起来更容易管理—实际上，它看起来只有图像文件，但是你的自动化脚本知道得更多，它们知道可以用<span><strong class="command">svn</strong></span>（更好的选择是使用Subversion的语言绑定—见<a title="使用C和C++以外的语言" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-8-sect-2.html#svn-ch-8-sect-2.3">“使用C和C++以外的语言”一节</a>）来挖掘更多的站点显示需要的额外信息，而不必去阅读一个索引文件或者是玩一个路径处理的游戏。</p>
				<p>你怎样（而且如果）使用Subversion完全在你，像我们提到的，Subversion拥有它自己的属性集，我们会在后面的章节讨论，但首先，让我们讨论怎样使用<span><strong class="command">svn</strong></span>的属性处理选项。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-7-sect-2.2">
												</a>处理属性</h3>
								</div>
						</div>
				</div>
				<p>
						<span>
								<strong class="command">svn</strong>
						</span>命令提供一些方法来添加和修改文件或目录的属性，对于短的，可读的属性，最简单的添加方法是在<span><strong class="command">propset</strong></span>子命令里指定正确的名称和值。</p>
				<pre class="screen">$ svn propset copyright '(c) 2003 Red-Bean Software' calc/button.c
property 'copyright' set on 'calc/button.c'
$
</pre>
				<p>但是我们已经“吹嘘”过Subversion为属性值提供的灵活性，如果你计划有一个多行的可读文本，甚至是二进制文件的属性值，你通常不希望在命令行里指定，所以<span><strong class="command">propset</strong></span>子命令使用<code class="option">--file</code>（<code class="option">-F</code>）选项来指定一个保存新属性值的文件的名字。</p>
				<pre class="screen">$ svn propset license -F /path/to/LICENSE calc/button.c
property 'license' set on 'calc/button.c'
$
</pre>
				<p>作为<span><strong class="command">propset</strong></span>命令的补充，<span><strong class="command">svn</strong></span>提供了一个<span><strong class="command">propedit</strong></span>命令，这个命令使用定制的编辑器程序（见<a title="config" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7.html#svn-ch-7-sect-1.3.2">“config”一节</a>）来添加和修改属性。当你运行这个命令，<span><strong class="command">svn</strong></span>调用你的编辑器程序打开一个临时文件，文件中保存当前的属性值（或者是空文件，如果你正在添加新的属性）。然后你只需要修改为你想要的值，保存临时文件，然后离开编辑器程序。如果Subversion发现你已经修改了属性值，就会接受新值，如果你未作任何修改而离开，不会产生属性修改操作。</p>
				<pre class="screen">$ svn propedit copyright calc/button.c  ### exit the editor without changes
No changes to property 'copyright' on 'calc/button.c'
$
</pre>
				<p>我们也应该注意导，像其它<span><strong class="command">svn</strong></span>子命令一样，这些关联的属性可以一次添加到多个路径上，这样就可以通过一个命令修改一组文件的属性。举个例子，我们可以：</p>
				<pre class="screen">$ svn propset copyright '(c) 2002 Red-Bean Software' calc/*
property 'copyright' set on 'calc/Makefile'
property 'copyright' set on 'calc/button.c'
property 'copyright' set on 'calc/integer.c'
…
$
</pre>
				<p>如果不能方便的得到存储的属性值，那么属性的添加和编辑操作也不会很容易，所以<span><strong class="command">svn</strong></span>提供了两个子命令来显示文件和目录存储的属性名和值。<span><strong class="command">svn proplist</strong></span>命令会列出路径上存在的所有属性名称，一旦你知道了某个节点的属性名称，你可以用<span><strong class="command">svn propget</strong></span>获取它的值，这个命令获取给定的路径（或者是一组路径）和属性名称，打印这个属性的值到标准输出。</p>
				<pre class="screen">$ svn proplist calc/button.c
Properties on 'calc/button.c':
  copyright
  license
$ svn propget copyright calc/button.c
(c) 2003 Red-Bean Software
</pre>
				<p>还有一个<span><strong class="command">proplist</strong></span>变种命令会列出所有属性的名称和值，只需要设置<code class="option">--verbose</code>（<code class="option">-v</code>）选项。</p>
				<pre class="screen">$ svn proplist --verbose calc/button.c
Properties on 'calc/button.c':
  copyright : (c) 2003 Red-Bean Software
  license : ================================================================
Copyright (c) 2003 Red-Bean Software.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions 
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the recipe for Fitz's famous
red-beans-and-rice.
…
</pre>
				<p>最后一个与属性相关的子命令是<span><strong class="command">propdel</strong></span>，因为Subversion允许属性值为空，所有不能用<span><strong class="command">propedit</strong></span>或者<span><strong class="command">propset</strong></span>命令删除一个属性。举个例子，这个命令<span class="emphasis"><em>不会</em></span>产生预期的效果：</p>
				<pre class="screen">$ svn propset license '' calc/button.c
property 'license' set on 'calc/button.c'
$ svn proplist --verbose calc/button.c
Properties on 'calc/button.c':
  copyright : (c) 2003 Red-Bean Software
  license : 
$
</pre>
				<p>你需要用<span><strong class="command">propdel</strong></span>来删除属性，语法与其它与属性相关命令相似：</p>
				<pre class="screen">$ svn propdel license calc/button.c
property 'license' deleted from ''.
$ svn proplist --verbose calc/button.c
Properties on 'calc/button.c':
  copyright : (c) 2003 Red-Bean Software
$
</pre>
				<p>现在你已经熟悉了所有与属性相关的<span><strong class="command">svn</strong></span>子命令，让我们看看属性修改如何影响Subversion的工作流。我们前面提到过，文件和目录的属性是版本化的，这一点类似于版本化的文件内容。后果之一，就是Subversion具有了同样的机制来合并—用干净或者冲突的方式—其他人的修改应用到你的修改。</p>
				<div class="sidebar">
						<p class="title">
								<b>修改修订版本的属性</b>
						</p>
						<p>还记的这些未版本化的属性？你也可以使用<span><strong class="command">svn</strong></span>命令修改这些属性。只需要添加<code class="option">--revprop</code>命令参数，并且说明希望修改属性的修订版本。因为修订版本是全局的，你不需要指定一个路径，只要你已经位于你希望修改属性的工作拷贝路径，举个例子，你希望修改一个存在版本的提交日志信息。 <sup>[<a id="id487142" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7-sect-2.html#ftn.id487142">27</a>]</sup></p>
						<pre class="screen">$ svn propset svn:log '* button.c: Fix a compiler warning.' -r11 --revprop
property 'svn:log' set on repository revision '11'
$
</pre>
						<p>注意，修改这些未版本化的属性的能力一定要明确的添加给版本库管理员（见<a title="钩子脚本" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-2.html#svn-ch-5-sect-2.1">“钩子脚本”一节</a>）。因为属性没有版本化，如果编辑的时候不小心，就会冒丢失信息的风险，版本库管理员可以设置方法来防范这种意外，缺省情况下，修改未版本化的属性是禁止的。</p>
				</div>
				<p>就像文件内容，你的属性修改是本地修改，只有使用<span><strong class="command">svn commit</strong></span>命令提交后才会保存到版本库中，属性修改也可以很容易的取消—<span><strong class="command">svn revert</strong></span>命令会恢复你的文件和目录为编辑前状态，包括内容、属性和其它的信息。另外，你可以使用<span><strong class="command">svn status</strong></span>和<span><strong class="command">svn diff</strong></span>接受感兴趣的文件和目录属性的状态信息。</p>
				<pre class="screen">$ svn status calc/button.c
 M     calc/button.c
$ svn diff calc/button.c
Property changes on: calc/button.c
___________________________________________________________________
Name: copyright
   + (c) 2003 Red-Bean Software

$
</pre>
				<p>注意<span><strong class="command">status</strong></span>子命令显示的<code class="literal">M</code>在第二列而不是在第一列，这是因为我们修改了<code class="filename">calc/button.c</code>的属性，而不是它的文本内容，如果我们都修改了，我们也会看到<code class="literal">M</code>出现在第一列（见<a title="svn status" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-3-sect-5.html#svn-ch-3-sect-5.3.1">“<span><strong class="command">svn status</strong></span>”一节</a>）。</p>
				<div class="sidebar">
						<p class="title">
								<b>属性冲突</b>
						</p>
						<p>与文件内容一样，本地的属性修改也会同别人的提交冲突，如果你更新你的工作拷贝目录并且接收到有资源属性修改与你的修改冲突，Subversion会报告资源处于冲突状态。</p>
						<pre class="screen">% svn update calc
M  calc/Makefile.in
 C calc/button.c
Updated to revision 143.
$ 
</pre>
						<p>Subversion也会在冲突资源的同一个目录创建一个<code class="filename">.prej</code>扩展名的文件，保存冲突的细节。你一定要检查这个文件的内容来决定如何解决冲突，在你解决冲突之前，你会在使用<span><strong class="command">svn status</strong></span>时看到这个资源的输出的第二列是一个<code class="literal">C</code>，提交本地修改的尝试会失败。</p>
						<pre class="screen">$ svn status calc
 C     calc/button.c
?      calc/button.c.prej
$ cat calc/button.c.prej 
prop 'linecount': user set to '1256', but update set to '1301'.
$
</pre>
						<p>为了解决属性冲突，只需要确定冲突的属性保存了它们应该的值，然后使用<span><strong class="command">svn resolved</strong></span>命令告诉Subversion你已经手工解决了问题。</p>
				</div>
				<p>你也许已经注意到了Subversion在显示属性时的非标准方式。你还可以运行<span><strong class="command">svn diff</strong></span>并且重定向输出来产生一个有用的补丁文件，<span><strong class="command">patch</strong></span>程序会忽略属性补丁—作为规则，它会忽略任何不理解的噪音。很遗憾，这意味着完全应用<span><strong class="command">svn diff</strong></span>产生的补丁时，任何属性修改必须手工实施。</p>
				<p>就象你看到的，属性修改的出现并没有对典型的Subversion工作流有显著的影响，更新工作拷贝、检查文件和目录的状态、报告所作的修改和提交修改到版本库等等的工作方式完全与属性的存在与否无关。<span><strong class="command">svn</strong></span>程序有一些额外的子命令用来进行属性修改，但那是唯一显而易见不对称的命令。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-7-sect-2.3">
												</a>特别属性</h3>
								</div>
						</div>
				</div>
				<p>Subversion没有关于属性的特殊政策—你可以通过它们实现自己的目的。Subversion只是要求你不要使用<code class="literal">svn:</code>开头的命名空间作为属性名，这是Subversion自己使用的命名空间。实际上，Subversion定义了某些特殊的属性，这些属性对它们所附加的文件和目录有特殊的影响。在本小节，我们会解开这个谜团，并且描述这些属性怎样让你的生活更加容易。</p>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-7-sect-2.3.1">
														</a>
														<code class="literal">svn:executable</code>
												</h4>
										</div>
								</div>
						</div>
						<p>
								<code class="literal">svn:executable</code>属性用来控制一个版本化的文件自动执行文件权限设定，这个属性没有特定的值—它只是说明一个Subversion可以保留的文件权限的期望值，删除这个属性会恢复操作系统对这些权限的完全控制。</p>
						<p>在多数操作系统，执行一个文件或命令的能力是由执行位管理的，这些位通常是关闭的，必须由用户显式的指定，这意味着你必须改变文件的执行位，然后更新你的工作拷贝，燃火如果你的文件成为更新的一部分，它的执行位会被关闭，所以Subversion提供了<code class="literal">svn:executable</code>这个属性来保持打开执行位。</p>
						<p>这个属性对于没有可执行权限位的文件系统无效，如FAT32和NTFS。 <sup>[<a id="id487472" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7-sect-2.html#ftn.id487472">28</a>]</sup> 也就是说，尽管它没有定义的值，在设置这个属性时，Subversion会强制它的值为<code class="literal">*</code>，最后，这个属性只对文件有效，目录无效。 </p>
				</div>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-7-sect-2.3.2">
														</a>
														<code class="literal">svn:mime-type</code>
												</h4>
										</div>
								</div>
						</div>
						<p>
								<code class="literal">svn:mime-type</code>属性为Subversion的许多目的服务，除了保存一个文件的多用途网际邮件扩展（MIME）分类以外，这个属性值也描述了一些Subversion自己使用的行为特性。 </p>
						<p>举个例子，如果一个文件<code class="literal">svn:mime-type</code>属性设置为非文本的MIME类型（通常是那些不是<code class="literal">text/</code>开头的类型，但也有例外），Subversion会假定这个文件保存了二进制内容—也就是不可读的—数据。一个好处就是Subversion通常在更新到工作拷贝时提供了一个前后相关的以行为基础的修改合并，但是对于保存二进制数据的文件，没有“<span class="quote">行</span>”的概念，所以对这些文件，Subversion不会在更新时尝试执行合并操作，相反，任何时候你在本地修改的一个二进制文件有了更新，你的文件会被重命名为<code class="filename">.orig</code>为扩展名，然后Subversion保存一个新的工作拷贝文件，保存更新时得到的修改，但原来的文件名已经不是你自己的本地修改。这个行为模式是用来保护用户在对不可文本合并的文件尝试执行文本的合并时失败的情形。</p>
						<p>另外，如果<code class="literal">svn:mime-type</code>属性被设置，Subversion的Apache模块会使用这个值来在HTTP头里输入<code class="literal">Content-type:</code>，这给了web浏览器如何显示一个文件提供了至关重要的线索。 </p>
				</div>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-7-sect-2.3.3">
														</a>
														<code class="literal">svn:ignore</code>
												</h4>
										</div>
								</div>
						</div>
						<p>这个<code class="literal">svn:ignore</code>属性保存了一个Subversion特定操作忽略的文件模式列表，或许这个是最常用的属性，它可以与<code class="literal">global-ignores</code>运行配置选项配合使用（见<a title="config" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7.html#svn-ch-7-sect-1.3.2">“config”一节</a>）来过滤<span><strong class="command">svn status</strong></span>、<span><strong class="command">svn add</strong></span>和<span><strong class="command">svn import</strong></span>命令中操作的未版本化文件。</p>
						<p>
								<code class="literal">svn:ignore</code>背后的基本原理很容易解释，Subversion不会假定工作拷贝中的所有文件或子目录是版本控制的一部分，资源必须被显式的使用<span><strong class="command">svn add</strong></span>或者<span><strong class="command">svn import</strong></span>放到Subversion的管理控制之下，作为结果，经常有许多工作拷贝的资源并没有版本化。</p>
						<p>现在，<span><strong class="command">svn status</strong></span>命令会的显示会包括所有未纳入版本控制且没有用<code class="literal">global-ignores</code>（或是内置的缺省值）过滤掉的文件和子目录，这样可以帮助用户查看是否忘记了把某些自愿加入到版本控制。</p>
						<p>但是Subversion不可能猜测到每个需要忽略的资源的名字，但是也有一些资源是<span class="emphasis"><em>所有</em></span>特定版本库的工作拷贝都有忽略的，强制版本库的每个用户来添加这些模式到他们的运行配置区域不仅仅是一个负担，也会与用户取出的其他工作拷贝配置需要存在潜在的冲突。</p>
						<p>解决方案是保存的忽略模式必须对出现在给定目录和这个目录本身的资源是独立的，一个常见的例子就是一个未版本化资源对一个目录来说是唯一的，会出现在那个位置，包括程序编译的输出，或者是—用一个本书的例子—DocBook的文件生成的HTML、PDF或者是PostScript文件。</p>
						<div class="sidebar">
								<p class="title">
										<b>CVS用户的忽略模式</b>
								</p>
								<p>Subversion的<code class="literal">svn:ignore</code>属性与CVS的<code class="filename">.cvsignore</code>文件的语法和功能非常类似，实际上，如果你移植一个CVS的工作拷贝到Subversion，你可以直接使用<code class="filename">.cvsignore</code>作为<span><strong class="command">svn propset</strong></span>输入文件参数： </p>
								<pre class="screen">$ svn propset svn:ignore -F .cvsignore .
property 'svn:ignore' set on '.'
$
</pre>
								<p>但是CVS和Subversion处理忽略模式的方式有一些不同，这两个系统在不同的时候使用忽略模式，忽略模式应用的对象也由微小的不同，但是Subversion不会识别重置回到没有忽略模式的<code class="literal">!</code>模式的使用。 </p>
						</div>
						<p>为了这个目的，<code class="literal">svn:ignore</code>属性是解决方案，它的值是一个多行的文件模式集，一行一个模式，这个属性已经设置到这个你希望应用模式的目录。 <sup>[<a id="id487817" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7-sect-2.html#ftn.id487817">29</a>]</sup> 举个例子，你的<span><strong class="command">svn status</strong></span>有如下的输出： </p>
						<pre class="screen">$ svn status calc
 M     calc/button.c
?      calc/calculator
?      calc/data.c
?      calc/debug_log
?      calc/debug_log.1
?      calc/debug_log.2.gz
?      calc/debug_log.3.gz
</pre>
						<p>在这个例子里，你对<code class="filename">button.c</code>文件作了一些属性修改，但是你的工作拷贝也有一些未版本化的文件：你从源代码编译的最新的<code class="filename">计算器</code>程序是<code class="filename">data.c</code>，一系列调试输出日志文件，现在你知道你的编译系统会编译生成<code class="filename">计算器</code>程序。 <sup>[<a id="id487876" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7-sect-2.html#ftn.id487876">30</a>]</sup> 就像你知道的，你的测试组件总是会留下这些调试日志，这对所有的工作拷贝都是一样的，不仅仅使你的。你也知道你不会有兴趣在<span><strong class="command">svn status</strong></span>命令中显示这些信息，所以使用<span><strong class="command">svn propedit svn:ignore calc</strong></span>来为<code class="filename">calc</code>目录增加一些忽略模式，举个例子，你或许会添加如下的值作为<code class="literal">svn:ignore</code>属性：</p>
						<pre class="programlisting">calculator
debug_log*
</pre>
						<p>当你添加完这些属性，你会在<code class="filename">calc</code>目录有一个本地修改，但是注意你的<span><strong class="command">svn status</strong></span>输出有什么其他的不同：</p>
						<pre class="screen">$ svn status
 M     calc
 M     calc/button.c
?      calc/data.c
</pre>
						<p>现在，所有多余的输出不见了！当然，这些文件还在工作拷贝中，Subversion仅仅是不再提醒你它们的存在和未版本化。现在所有讨厌的噪音都已经删除了，你留下了更加感兴趣的项目—如你忘记添加到版本控制的源代码文件。 </p>
						<p>如果想查看被忽略的文件，可以设置Subversion的<code class="option">--no-ignore</code>选项：</p>
						<pre class="screen">$ svn status --no-ignore
 M     calc/button.c
I      calc/calculator
?      calc/data.c
I      calc/debug_log
I      calc/debug_log.1
I      calc/debug_log.2.gz
I      calc/debug_log.3.gz
</pre>
						<p>
								<span>
										<strong class="command">svn add</strong>
								</span>和<span><strong class="command">svn import</strong></span>也会使用这个忽略模式列表，这两个操作都包括了询问Subversion来开始管理一组文件和目录。比强制用户挑拣目录树中那个文件要纳入版本控制的方式更好，Subversion使用忽略模式来检测那个文件不应该在大的迭代添加和导入操作中进入版本控制系统。</p>
				</div>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-7-sect-2.3.4">
														</a>
														<code class="literal">svn:keywords</code>
												</h4>
										</div>
								</div>
						</div>
						<p>Subversion具备有添加<em class="firstterm">关键字</em>的能力—一些有用的，关于版本化的文件动态信息的片断—不必直接添加到文件本身。关键字通常会用来描述文件最后一次修改的一些信息，因为这些信息每次都有改变，更重要的一点，这是在文件修改<span class="emphasis"><em>之后</em></span>，除了版本控制系统，对于任何处理完全保持最新的数据都是一场争论，作为人类作者，信息变得陈旧是不可避免的。</p>
						<p>举个例子，你有一个文档希望显示最后修改的日期，你需要麻烦每个作者提交之前做这件事情，同时会改变描述这部分细细的部分，但是迟早会有人忘记做这件事，不选择简单的告诉Subversion来执行替换<code class="literal">LastChangedDate</code>关键字的操作，在你的文档需要放置这个关键字的地方放置一个<em class="firstterm">keyword anchor</em>，这个anchor只是一个格式为<code class="literal">$</code><em class="replaceable"><code>KeywordName</code></em><code class="literal">$</code>字符串。 </p>
						<p>所有作为anchor出现在文件里的关键字是大小写敏感的：为了关键字的扩展，你必须使用正确的按顺序大写。你必须考虑<code class="literal">svn:keywords</code>的属性值也是大小写敏感—特定的关键字名会忽略大小写，但是这个特性已经被废弃了。</p>
						<p>Subversion定义了用来替换的关键字列表，这个列表保存了如下五个关键字，有一些也包括了可用的别名： </p>
						<div class="variablelist">
								<dl>
										<dt>
												<span class="term">
														<code class="literal">Date</code>
												</span>
										</dt>
										<dd>
												<p>这个关键字保存了文件最后一次在版本库修改的日期，看起来类似于<code class="literal">$Date: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $</code>，它也可以用<code class="literal">LastChangedDate</code>来指定。 </p>
										</dd>
										<dt>
												<span class="term">
														<code class="literal">Revision</code>
												</span>
										</dt>
										<dd>
												<p>这个关键字描述了这个文件最后一次修改的修订版本，看起来像<code class="literal">$Revision: 144 $</code>，也可以通过<code class="literal">LastChangedRevision</code>或者<code class="literal">Rev</code>引用。 </p>
										</dd>
										<dt>
												<span class="term">
														<code class="literal">Author</code>
												</span>
										</dt>
										<dd>
												<p>这个关键字描述了最后一个修改这个文件的用户，看起来类似<code class="literal">$Author: harry $</code>，也可以用<code class="literal">LastChangedBy</code>来指定。 </p>
										</dd>
										<dt>
												<span class="term">
														<code class="literal">HeadURL</code>
												</span>
										</dt>
										<dd>
												<p>这个关键字描述了这个文件在版本库最新的版本的完全URL，看起来类似<code class="literal">$HeadURL: http://svn.collab.net/repos/trunk/README $</code>，可以缩写为<code class="literal">URL</code>。 </p>
										</dd>
										<dt>
												<span class="term">
														<code class="literal">Id</code>
												</span>
										</dt>
										<dd>
												<p>这个关键字是其他关键字一个压缩组合，它看起来就像<code class="literal">$Id: calc.c 148 2002-07-28 21:30:43Z sally $</code>，可以解释为文件<code class="filename">calc.c</code>上一次修改的修订版本号是148，时间是2002年7月28日，作者是<code class="literal">sally</code>。 </p>
										</dd>
								</dl>
						</div>
						<p>只在你的文件增加关键字anchor不会做什么特别的事情，Subversion不会尝试对你的文件内容执行文本替换，除非明确的被告知这样做，毕竟，你可以撰写一个文档 <sup>[<a id="id488292" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7-sect-2.html#ftn.id488292">31</a>]</sup> 关于如何使用关键字，你希望Subversion不会替代你漂亮的关于不需要替换的关键字anchor实例！ </p>
						<p>为了告诉Subversion是否替代某个文件的关键字，我们要再次求助于属性相关的子命令，当<code class="literal">svn:keywords</code>属性设置到一个版本化的文件，这些属性控制了那些关键字将会替换到那个文件。这个值是空格分隔的前面列表的名称或是别名列表。</p>
						<p>举个例子，假定你有一个版本化的文件<code class="filename">weather.txt</code>，内容如下： </p>
						<pre class="programlisting">Here is the latest report from the front lines.
$LastChangedDate$
$Rev$
Cumulus clouds are appearing more frequently as summer approaches.
</pre>
						<p>当没有<code class="literal">svn:keywords</code>属性设置到这个文件，Subversion不会有任何特别操作，现在让我们允许<code class="literal">LastChangedDate</code>关键字的替换。 </p>
						<pre class="screen">$ svn propset svn:keywords "Date Author" weather.txt
property 'svn:keywords' set on 'weather.txt'
$
</pre>
						<p>现在你已经对<code class="filename">weather.txt</code>的属性作了修改，你会看到文件的内容没有改变（除非你之前做了一些属性设置），注意这个文件包含了<code class="literal">Rev</code>的关键字anchor，但我们没有在属性值中包括这个关键字，Subversion会高兴的忽略替换这个文件中的关键字，也不会替换<code class="literal">svn:keywords</code>属性中没有出现的关键字。 </p>
						<div class="sidebar">
								<p class="title">
										<b>关键字和虚假的差异</b>
								</p>
								<p>用户可见的关键字替换会让你以为每一个具有此特性的文件的每个版本都会与前一个版本至少在关键字替换的地方不同，但是实际上并不是如此，当用<span><strong class="command">svn diff</strong></span>检查本地修改时，或者是在使用<span><strong class="command">svn commit</strong></span>传输修改之前，Subversion不会“<span class="quote">取消替换</span>”任何上次替换的关键字，结果就是版本库保存的文件只保存用户实际做的修改。 </p>
						</div>
						<p>在你提交了属性修改后，Subversion会立刻更新你的工作文件为新的替代文本，你将无法找到<code class="literal">$LastChangedDate$</code>的关键字anchor，你会看到替换的结果，这个结果也保存了关键字的名字，与美元符号（<code class="literal">$</code>）绑定在一起，而且我们预测的，<code class="literal">Rev</code>关键字不会被替换，因为我们没有要求这样做。</p>
						<p>注意我们设置<code class="literal">svn:keywords</code>属性为"Date Author"，关键字anchor使用别名<code class="literal">$LastChangedDate$</code>并且正确的扩展。 </p>
						<pre class="screen">Here is the latest report from the front lines.
$LastChangedDate: 2002-07-22 21:42:37 -0700 (Mon, 22 Jul 2002) $
$Rev$
Cumulus clouds are appearing more frequently as summer approaches.
</pre>
						<p>如果有其他人提交了<code class="filename">weather.txt</code>的修改，你的此文件的拷贝还会显示同样的替换关键字值—直到你更新你的工作拷贝，此时你的<code class="filename">weather.txt</code>重的关键字将会被替换来反映最新的提交信息。 </p>
				</div>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-7-sect-2.3.5">
														</a>
														<code class="literal">svn:eol-style</code>
												</h4>
										</div>
								</div>
						</div>
						<p>不像我们说过的版本化文件的<code class="literal">svn:mime-type</code>属性，Subversion假定这个文件保存了可读的数据，一般来讲，Subversion因为这个属性来判断一个文件是否可以用上下文区别报告，否则，对Subversion来说只是字节。</p>
						<p>这意味着缺省情况下，Subversion不会关注任何<em class="firstterm">行结束标记（end-of-line，EOL）</em>，不幸的是不同的操作系统在文本文件使用不同的行结束标志，举个例子，Windows平台下的A编辑工具使用一对SCII控制字符—回车（<code class="literal">CR</code>）和一个移行（<code class="literal">LF</code>）。Unix软件，只使用一个<code class="literal">LF</code>来表示一个行的结束。 </p>
						<p>并不是所有操作系统的工具准备好了理解与<em class="firstterm">本地行结束样式</em>不一样的行结束格式，一个常见的结果是Unix程序会把Windows文件中的<code class="literal">CR</code>当作一个不同的字符（通常表现为<code class="literal">^M</code>），而Windows程序会把Unix文件合并为一个非常大的行，因为没有发现标志行结束的回车加换行（或者是<code class="literal">CRLF</code>）字符。</p>
						<p>对外来EOL标志的敏感会让在各个操作系统分享文件的人们感到沮丧，例如，考虑有一个源代码文件，开发者会在Windows和Unix系统上编辑这个文件，如果所有的用户使用的工具可以展示文件的行结束，那就没有问题。</p>
						<p>但实践中，许多常用的工具不会正确的读取外来的EOL标志，或者是将文件的行结束转化为本地的样式，如果是前者，他需要一个外部的转化工具（如<span><strong class="command">dos2unix</strong></span>或是他的伴侣，<span><strong class="command">unix2dos</strong></span>）来准备需要编辑的文件。后一种情况不需要额外的准备工作，两种方法都会造成文件会与原来的文件在每一行上都不一样！在提交之前，用户有两个选择，或者选择用一个转化工具恢复文件的行结束样式，或者是简单的提交文件—包含新的EOL标志。 </p>
						<p>这个情景的结局看起来像是要浪费时间对提交的文件作不必要的修改，浪费时间是痛苦的，但是如果提交修改了文件的每一行，判断那个文件是通过正常的方式修改的会是一件复杂的工作，bug在那一行修正的？那一行引入了语法错误？ </p>
						<p>这个问题的解决方案是<code class="literal">svn:eol-style</code>属性，当这个属性设置为一个正确的值，Subversion使用它来判断针对行结束样式执行何种特殊的操作，而不会因为多种操作系统的每次提交发生震荡。正确的值有：</p>
						<div class="variablelist">
								<dl>
										<dt>
												<span class="term">
														<code class="literal">native</code>
												</span>
										</dt>
										<dd>
												<p>这会导致保存EOL标志的文件使用Subversion运行的操作系统的本地编码，换句话说，如果一个Windows用户取出一个工作拷贝包含的一个文件有<code class="literal">svn:eol-style</code>的属性设置为<code class="literal">native</code>，这个文件会使用<code class="literal">CRLF</code>的EOL标志，一个Unix用户取出相同的文件会看到他的文件使用<code class="literal">LF</code>的EOL标志。 </p>
												<p>注意Subversion实际上使用<code class="literal">LF</code>的EOL标志，而不会考略操作系统，尽管这对用户来说是透明的。 </p>
										</dd>
										<dt>
												<span class="term">
														<code class="literal">CRLF</code>
												</span>
										</dt>
										<dd>
												<p>这会导致这个文件使用<code class="literal">CRLF</code>序列作为EOL标志，不管使用何种操作系统。 </p>
										</dd>
										<dt>
												<span class="term">
														<code class="literal">LF</code>
												</span>
										</dt>
										<dd>
												<p>这会导致文件使用<code class="literal">LF</code>字符作为EOL标志，不管使用何种操作系统。 </p>
										</dd>
										<dt>
												<span class="term">
														<code class="literal">CR</code>
												</span>
										</dt>
										<dd>
												<p>这会导致文件使用<code class="literal">CR</code>字符作为EOL标志，不管使用何种操作系统。这种行结束样式不是很常见，它用在一些老的苹果机（Subversion不会运行的机器上）。 </p>
										</dd>
								</dl>
						</div>
				</div>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-7-sect-2.3.6">
														</a>
														<code class="literal">svn:externals</code>
												</h4>
										</div>
								</div>
						</div>
						<p>
								<code class="literal">svn:externals</code>属性保存了指导Subversion从一个或多个取出的工作拷贝移出目录的指示，关于这个关键字的更多信息，见<a title="外部定义" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7-sect-3.html">“外部定义”一节</a>。 </p>
				</div>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-7-sect-2.3.7">
														</a>
														<code class="literal">svn:special</code>
												</h4>
										</div>
								</div>
						</div>
						<p>
								<code class="literal">svn:special</code>是唯一一个不是用户直接设置和修改的<code class="literal">svn:</code>属性，当“<span class="quote">特别的</span>”对象如一个对象链接计划加入到版本库，Subversion会自动设置这个属性。版本库像普通文件一样保存<code class="literal">svn:special</code>对象，然而，当一个客户端在检出和更新操作时看到这个属性时，就会翻译这个文件的内容，并且将文件转化为特殊类型的对象，在Subversion1.1中，只有版本化的符号链接有这个属性附加，但在以后的版本中其它特殊的节点也有可能使用这个属性。</p>
						<p>注意：Windows客户端不会有符号链接，因此会忽略含有<code class="literal">svn:special</code>声明为符号链的文件，在Windows，用户会以一个工作拷贝中的版本化的文件作为结束。 </p>
				</div>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-7-sect-2.4">
												</a>自动属性设置</h3>
								</div>
						</div>
				</div>
				<p>属性是Subversion一个强大的特性，成为本章和其它章讨论的许多Subversion特性的关键组成部分—文本区别和合并支持、关键字替换、新行的自动转换等等。但是为了从属性得到完全的利益，他们必须设置到正确的文件和目录。不幸的是，在日常工作中很容易忘记这一步工作，特别是当没有设置属性不会引起明显的错误时（至少相对与未能添加一个文件到版本控制这种操作），为了帮助你在需要添加属性的文件上添加属性，Subversion提供了一些简单但是有用的特性。</p>
				<p>当你使用<span><strong class="command">svn add</strong></span>或是<span><strong class="command">svn import</strong></span>准备加入一个版本控制的文件时，Subversion会运行一个基本探测来检查文件是包括了可读还是不可读的内容，如果Subversion猜测错误，或者是你希望使用<code class="literal">svn:mime-type</code>属性更精确的设置—或许是<code class="literal">image/png</code>或者<code class="literal">application/x-shockwave-flash</code>—你可以一直删除或编辑那个属性。</p>
				<p>Subversion也提供了自动属性特性，允许你创建文件名到属性名称与值影射，这个影射在你的运行配置区域设置，它们会影响添加和导入操作，而且不仅仅会覆盖Subversion所有缺省的MIME类型判断操作，也会设置额外的Subversion或者自定义的属性。举个例子，你会创建一个影射文件说在任何时候你添加了一个JPEG文件—一些符合<code class="literal">*.jpg</code>的文件—Subversion一定会自动设置它们的<code class="literal">svn:mime-type</code>属性为<code class="literal">image/jpeg</code>。或者是任何匹配<code class="literal">*.cpp</code>的文件，必须把<code class="literal">svn:eol-style</code>设置为<code class="literal">native</code>，并且<code class="literal">svn:keywords</code>设置为<code class="literal">Id</code>。自动属性支持是Subversion工具箱中属性相关最垂手可得的工具，见<a title="config" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-7.html#svn-ch-7-sect-1.3.2">“config”一节</a>来查看更多的配置支持。</p>
		</div><img src ="http://www.cnitblog.com/tilan/aggbug/21818.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-12 14:44 <a href="http://www.cnitblog.com/tilan/articles/21818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>subversion 管理员的工具箱</title><link>http://www.cnitblog.com/tilan/articles/21817.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 12 Jan 2007 06:41:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21817.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21817.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21817.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21817.html</trackback:ping><description><![CDATA[<p>Subversion提供了一些用来创建、查看、修改和修复版本库的工具。让我们首先详细了解一下每个工具，然后，我们再看一下仅在Berkeley DB后端分发版本中提供的版本数据库工具。</p>
		<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h4 class="title">
												<a id="svn-ch-5-sect-3.1.1">
												</a>svnlook</h4>
								</div>
						</div>
				</div>
				<p>
						<span>
								<strong class="command">svnlook</strong>
						</span>是Subversion提供的用来查看版本库中不同的修订版本和事务。这个程序不会修改版本库内容－这是个“<span class="quote">只读</span>”的工具。<span><strong class="command">svnlook</strong></span>通常用在版本库钩子程序中，用来记录版本库即将提交（<span><strong class="command">用在pre-commit钩子时）</strong></span>或者已经提交的（用在<span><strong class="command">post-commit</strong></span>钩子时）修改。版本库管理员可以将这个工具用于诊断。</p>
				<p>
						<span>
								<strong class="command">svnlook</strong>
						</span> 的语法很直接：</p>
				<pre class="screen">$ svnlook help
general usage: svnlook SUBCOMMAND REPOS_PATH [ARGS &amp; OPTIONS ...]
Note: any subcommand which takes the '--revision' and '--transaction'
      options will， if invoked without one of those options， act on
      the repository's youngest revision.
Type "svnlook help &lt;subcommand&gt;" for help on a specific subcommand.
…
</pre>
				<p>几乎<span><strong class="command">svnlook</strong></span>的每一个子命令都能操作修订版本或事务树，显示树本身的信息，或是它与版本库中上一个修订版本的不同。你可以用<code class="option">--revision</code> 和 <code class="option">--transaction</code>选项指定要查看的修订版本或事务。注意，虽然修订版本号看起来像自然数，但是事务名称是包含英文字母与数字的字符串。请记住文件系统只允许浏览未提交的事务（还没有形成一个新的修订版本的事务）。多数版本库没有这种事务，因为事务通常或者被提交了（这样便不能被查看），或者被中止并删除了。</p>
				<p>如果没有<code class="option">--revision</code>和<code class="option">--transaction</code>选项，<span><strong class="command">svnlook</strong></span>会查看版本库中最年轻的修订版本（或“<span class="quote">HEAD</span>”）。当版本库中的<code class="filename">/path/to/repos</code>的最年轻的修订版本是19时，下边的两个命令执行结果完全相同：</p>
				<pre class="screen">$ svnlook info /path/to/repos
$ svnlook info /path/to/repos --revision 19
</pre>
				<p>这些子命令的唯一例外，是<span><strong class="command">svnlook youngest</strong></span>命令，它不需要选项，只会显示出<code class="literal">HEAD</code>的修订版本号。</p>
				<pre class="screen">$ svnlook youngest /path/to/repos
19
</pre>
				<p>
						<span>
								<strong class="command">svnlook</strong>
						</span>的输出被设计为人和机器都易理解，拿<code class="literal">info</code>子命令举例来说：</p>
				<pre class="screen">$ svnlook info /path/to/repos
sally
2002-11-04 09:29:13 -0600 (Mon， 04 Nov 2002)
27
Added the usual
Greek tree.
</pre>
				<p>
						<code class="literal">info</code>子命令的输出定义如下：</p>
				<div class="orderedlist">
						<ol type="1">
								<li>
										<p>作者，后接换行。</p>
								</li>
								<li>
										<p>日期，后接换行。</p>
								</li>
								<li>
										<p>日志消息的字数，后接换行。</p>
								</li>
								<li>
										<p>日志信息本身， 后接换行。</p>
								</li>
						</ol>
				</div>
				<p>这种输出是人可阅读的，像是时间戳这种有意义的条目，使用文本表示，而不是其他比较晦涩的方式（例如许多无聊的人推荐的十亿分之一秒的数量）。这种输出也是机器可读的—因为日志信息可以有多行，没有长度的限制，<span><strong class="command">svnlook</strong></span>在日志消息之前提供了消息的长度，这使得脚本或者其他对这个命令进行的封装提供了更强的功能，比如日志消息使用了多少内存，或在这个输出成为最后一个字节之前应该略过多少字节。</p>
				<p>另一个<span><strong class="command">svnlook</strong></span>常见的用法是查看修订版本树或事务树的内容。<span><strong class="command">svnlook tree</strong></span> 命令显示在请求的树中的目录和文件。如果你提供了<code class="option">--show-ids</code>选项，它还会显示每个路径的文件系统节点修订版本ID（这一点对开发者往往更有用）。</p>
				<pre class="screen">$ svnlook tree /path/to/repos --show-ids
/ &lt;0.0.1&gt;
 A/ &lt;2.0.1&gt;
  B/ &lt;4.0.1&gt;
   lambda &lt;5.0.1&gt;
   E/ &lt;6.0.1&gt;
    alpha &lt;7.0.1&gt;
    beta &lt;8.0.1&gt;
   F/ &lt;9.0.1&gt;
  mu &lt;3.0.1&gt;
  C/ &lt;a.0.1&gt;
  D/ &lt;b.0.1&gt;
   gamma &lt;c.0.1&gt;
   G/ &lt;d.0.1&gt;
    pi &lt;e.0.1&gt;
    rho &lt;f.0.1&gt;
    tau &lt;g.0.1&gt;
   H/ &lt;h.0.1&gt;
    chi &lt;i.0.1&gt;
    omega &lt;k.0.1&gt;
    psi &lt;j.0.1&gt;
 iota &lt;1.0.1&gt;
</pre>
				<p>如果你看过树中目录和文件的布局，你可以使用<span><strong class="command">svnlook cat</strong></span>，<span><strong class="command">svnlook propget</strong></span>， 和<span><strong class="command">svnlook proplist</strong></span>命令来查看这些目录和文件的细节。</p>
				<p>
						<span>
								<strong class="command">svnlook</strong>
						</span>还可以做很多别的查询，显示我们先前提到的信息的一些子集，报告指定的修订版本或事务中哪些路径曾经被修改过，显示对文件和目录做过的文本和属性的修改，等等。下面是<span><strong class="command">svnlook</strong></span>命令能接受的子命令的介绍，以及这些子命令的输出：</p>
				<div class="variablelist">
						<dl>
								<dt>
										<span class="term">
												<code class="literal">author</code>
										</span>
								</dt>
								<dd>
										<p>显示该树的作者。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">cat</code>
										</span>
								</dt>
								<dd>
										<p>显示树中某文件的内容。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">changed</code>
										</span>
								</dt>
								<dd>
										<p>显示树中修改过的所有文件和目录。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">date</code>
										</span>
								</dt>
								<dd>
										<p>显示该树的时间戳。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">diff</code>
										</span>
								</dt>
								<dd>
										<p>使用统一区别格式显示被修改的文件。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">dirs-changed</code>
										</span>
								</dt>
								<dd>
										<p>显示树中本身被修改或者其中文件被修改的目录。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">history</code>
										</span>
								</dt>
								<dd>
										<p>显示受到版本控制的路径（更改和复制发生过的地方）中重要的历史点。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">info</code>
										</span>
								</dt>
								<dd>
										<p>显示树的作者、时间戳、日志大小和日志信息。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">log</code>
										</span>
								</dt>
								<dd>
										<p>显示树的日志信息。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">propget</code>
										</span>
								</dt>
								<dd>
										<p>显示树中路径的属性值。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">proplist</code>
										</span>
								</dt>
								<dd>
										<p>显示树中属性集合的名字与值。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">tree</code>
										</span>
								</dt>
								<dd>
										<p>显示树列表，可选的显示与路径有关的文件系统节点的修订版本号。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">uuid</code>
										</span>
								</dt>
								<dd>
										<p>显示版本库的UUID—全局唯一标示。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">youngest</code>
										</span>
								</dt>
								<dd>
										<p>显示最年轻的修订版本号。</p>
								</dd>
						</dl>
				</div>
		</div>
		<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h4 class="title">
												<a id="svn-ch-5-sect-3.1.2">
												</a>svnadmin</h4>
								</div>
						</div>
				</div>
				<p>
						<span>
								<strong class="command">svnadmin</strong>
						</span>程序是版本库管理员最好的朋友。除了提供创建Subversion版本库的功能，这个程序使你可以维护这些版本库。<span><strong class="command">svnadmin</strong></span>的语法跟 <span><strong class="command">svnlook</strong></span>类似：</p>
				<pre class="screen">$ svnadmin help
general usage: svnadmin SUBCOMMAND REPOS_PATH  [ARGS &amp; OPTIONS ...]
Type "svnadmin help &lt;subcommand&gt;" for help on a specific subcommand.

Available subcommands:
   create
   deltify
   dump
   help (?， h)
…
</pre>
				<p>我们已经提过<span><strong class="command">svnadmin</strong></span>的<code class="literal">create</code>子命令（参照<a title="版本库的创建和配置" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-2.html">“版本库的创建和配置”一节</a>）。本章中我们会详细讲解大多数其他的命令。现在，我们来简单的看一下每个可用的子命令提供了什么功能。</p>
				<div class="variablelist">
						<dl>
								<dt>
										<span class="term">
												<code class="literal">create</code>
										</span>
								</dt>
								<dd>
										<p>创建一个新的Subversion版本库。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">deltify</code>
										</span>
								</dt>
								<dd>
										<p>在指定的修订版本范围内，对其中修改过的路径做增量化操作。如果没有指定修订版本，这条命令会修改<code class="literal">HEAD</code>修订版本。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">dump</code>
										</span>
								</dt>
								<dd>
										<p>导出版本库修订一定版本范围内的内容，使用可移植转储格式。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">hotcopy</code>
										</span>
								</dt>
								<dd>
										<p>对版本库做热拷贝，用这个方法你能任何时候安全的备份版本库而无需考虑是否正在使用。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">list-dblogs</code>
										</span>
								</dt>
								<dd>
										<p>（Berkeley DB版本库专有）列出Berkeley DB中与版本库有关的日志文件清单。这个清单包括所有的日志文件—仍然被版本库使用的和不再使用的。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">list-unused-dblogs</code>
										</span>
								</dt>
								<dd>
										<p>（Berkeley DB版本库专有)列出Berkeley DB版本库有关的不在使用日志文件路径清单。你能安全的从版本库中删除那些日志文件，也可以将它们存档以用来在灾难事件后版本库的恢复。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">load</code>
										</span>
								</dt>
								<dd>
										<p>导入由<code class="literal">dump</code>子命令导出的可移植转储格式的一组修订版本。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">lstxns</code>
										</span>
								</dt>
								<dd>
										<p>列出刚刚在版本库的没有提交的Subversion事务清单。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">recover</code>
										</span>
								</dt>
								<dd>
										<p>恢复版本库，通常在版本库发生了致命错误的时候，例如阻碍进程干净的关闭同版本库的连接的错误。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">rmtxns</code>
										</span>
								</dt>
								<dd>
										<p>从版本库中清除Subversion事务（通过加工<code class="literal">lstxns</code>子命令的输出即可）。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">setlog</code>
										</span>
								</dt>
								<dd>
										<p>替换给定修订版本的<code class="literal">svn:log</code>（提交日志信息）属性值。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">verify</code>
										</span>
								</dt>
								<dd>
										<p>验证版本库的内容，包括校验比较本地版本化数据和版本库。</p>
								</dd>
						</dl>
				</div>
		</div>
		<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h4 class="title">
												<a id="svn-ch-5-sect-3.1.3">
												</a>svndumpfilter</h4>
								</div>
						</div>
				</div>
				<p>因为Subversion使用底层的数据库储存各类数据，手工调整是不明智的，即使这样做并不困难。何况，一旦你的数据存进了版本库，通常很难再将它们从版本库中删除。<sup>[<a id="id465486" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#ftn.id465486">13</a>]</sup>但是不可避免的，总会有些时候你需要处理版本库的历史数据。你也许想把一个不应该出现的文件从版本库中彻底清除。或者，你曾经用一个版本库管理多个工程，现在又想把它们分开。要完成这样的工作，管理员们需要更易于管理和扩展的方法表示版本库中的数据，Subversion版本库转储文件格式就是一个很好的选择。</p>
				<p>Subversion版本库转储文件记录了所有版本数据的变更信息，而且以易于阅读的格式保存。可以使用<span><strong class="command">svnadmin dump</strong></span>命令生成转储文件，然后用<span><strong class="command">svnadmin load</strong></span>命令生成一个新的版本库。（参见 <a title="版本库的移植" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#svn-ch-5-sect-3.5">“版本库的移植”一节</a>）。转储文件易于阅读意味着你可以小心翼翼的查看和修改它。当然，问题是如果你有一个运行了两年的版本库，那么生成的转储文件会很庞大，阅读和手工修改起来都会花费很多时间。</p>
				<p>虽然在管理员的日常工作中并不会经常使用，不过<span><strong class="command">svndumpfilter</strong></span>可以对特定的路径进行过滤。这是一个独特而很有意义的用法，可以帮助你快速方便的修改转储的数据。使用时，只需提供一个你想要保留的（或者不想保留的）路径列表，然后把你的版本库转储文件送进这个过滤器。最后你就可以得到一个仅包含你想保留的路径的转储数据流。</p>
				<p>
						<span>
								<strong class="command">svndumpfilter</strong>
						</span>的语法如下：</p>
				<pre class="screen">$ svndumpfilter help
general usage: svndumpfilter SUBCOMMAND [ARGS &amp; OPTIONS ...]
Type "svndumpfilter help &lt;subcommand&gt;" for help on a specific subcommand.

Available subcommands:
   exclude
   include
   help (?， h)
</pre>
				<p>有意义的子命令只有两个。你可以使用这两个子命令说明你希望保留和不希望保留的路径：</p>
				<div class="variablelist">
						<dl>
								<dt>
										<span class="term">
												<code class="literal">exclude</code>
										</span>
								</dt>
								<dd>
										<p>将指定路径的数据从转储数据流中排除。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="literal">include</code>
										</span>
								</dt>
								<dd>
										<p>将指定路径的数据添加到转储数据流中。</p>
								</dd>
						</dl>
				</div>
				<p>现在我来演示如何使用这个命令。我们会在其它章节（参见 <a title="选择一种版本库布局" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-6.html#svn-ch-5-sect-6.1">“选择一种版本库布局”一节</a>）讨论关于如何选择设定版本库布局的问题，比如应该使用一个版本库管理多个项目还是使用一个版本库管理一个项目，或者如何在版本库中安排数据等等。不过，有些时候，即使在项目已经展开以后，你还是希望对版本库的布局做一些调整。最常见的情况是，把原来存放在同一个版本库中的几个项目分开，各自成家。</p>
				<p>假设有一个包含三个项目的版本库： <code class="literal">calc</code>，<code class="literal">calendar</code>，和 <code class="literal">spreadsheet</code>。它们在版本库中的布局如下：</p>
				<pre class="screen">/
   calc/
      trunk/
      branches/
      tags/
   calendar/
      trunk/
      branches/
      tags/
   spreadsheet/
      trunk/
      branches/
      tags/
</pre>
				<p>现在要把这三个项目转移到三个独立的版本库中。首先，转储整个版本库：</p>
				<pre class="screen">$ svnadmin dump /path/to/repos &gt; repos-dumpfile
* Dumped revision 0.
* Dumped revision 1.
* Dumped revision 2.
* Dumped revision 3.
…
$
</pre>
				<p>然后，将转储文件三次送入过滤器，每次仅保留一个顶级目录，就可以得到三个转储文件：</p>
				<pre class="screen">$ cat repos-dumpfile | svndumpfilter include calc &gt; calc-dumpfile
…
$ cat repos-dumpfile | svndumpfilter include calendar &gt; cal-dumpfile
…
$ cat repos-dumpfile | svndumpfilter include spreadsheet &gt; ss-dumpfile
…
$
</pre>
				<p>现在你必须要作出一个决定了。这三个转储文件中，每个都可以用来创建一个可用的版本库，不过它们保留了原版本库的精确路径结构。也就是说，虽然项目<code class="literal">calc</code>现在独占了一个版本库，但版本库中还保留着名为<code class="filename">calc</code>的顶级目录。如果希望<code class="filename">trunk</code>、<code class="filename">tags</code>和<code class="filename">branches</code>这三个目录直接位于版本库的根路径下，你可能需要编辑转储文件，调整<code class="literal">Node-path</code>和<code class="literal">Copyfrom-path</code>头参数，将路径<code class="filename">calc/</code>删除。同时，你还要删除转储数据中创建<code class="filename">calc</code>目录的部分。一般来说，就是如下的一些内容：</p>
				<pre class="screen">Node-path: calc
Node-action: add
Node-kind: dir
Content-length: 0

</pre>
				<div class="warning" style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
						<h3 class="title">警告</h3>
						<p>如果你打算通过手工编辑转储文件来移除一个顶级目录，注意不要让你的编辑器将换行符转换为本地格式（比如将\r\n转换为\n）。否则文件的内容就与所需的格式不相符，这个转储文件也就失效了。</p>
				</div>
				<p>剩下的工作就是创建三个新的版本库，然后将三个转储文件分别导入：</p>
				<pre class="screen">$ svnadmin create calc; svnadmin load calc &lt; calc-dumpfile
&lt;&lt;&lt; Started new transaction， based on original revision 1
     * adding path : Makefile ... done.
     * adding path : button.c ... done.
…
$ svnadmin create calendar; svnadmin load calendar &lt; cal-dumpfile
&lt;&lt;&lt; Started new transaction， based on original revision 1
     * adding path : Makefile ... done.
     * adding path : cal.c ... done.
…
$ svnadmin create spreadsheet; svnadmin load spreadsheet &lt; ss-dumpfile
&lt;&lt;&lt; Started new transaction， based on original revision 1
     * adding path : Makefile ... done.
     * adding path : ss.c ... done.
…
$
</pre>
				<p>
						<span>
								<strong class="command">svndumpfilter</strong>
						</span>的两个子命令都可以通过选项设定如何处理“<span class="quote">空</span>”修订版本。如果某个指定的修订版本仅包含路径的更改，过滤器就会将它删除，因为当前为空的修订版本通常是无用的甚至是让人讨厌的。为了让用户有选择的处理这些修订版本，<span><strong class="command">svndumpfilter</strong></span>提供了以下命令行选项：</p>
				<div class="variablelist">
						<dl>
								<dt>
										<span class="term">
												<code class="option">--drop-empty-revs</code>
										</span>
								</dt>
								<dd>
										<p>不生成任何空修订版本，忽略它们。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="option">--renumber-revs</code>
										</span>
								</dt>
								<dd>
										<p>如果空修订版本被剔除（通过使用<code class="option">--drop-empty-revs</code>选项），依次修改其它修订版本的编号，确保编号序列是连续的。</p>
								</dd>
								<dt>
										<span class="term">
												<code class="option">--preserve-revprops</code>
										</span>
								</dt>
								<dd>
										<p>如果空修订版本被保留，保持这些空修订版本的属性（日志信息，作者，日期，自定义属性，等等）。如果不设定这个选项，空修订版本将仅保留初始时间戳，以及一个自动生成的日志信息，表明此修订版本由<span><strong class="command">svndumpfilter</strong></span>处理过。</p>
								</dd>
						</dl>
				</div>
				<p>尽管<span><strong class="command">svndumpfilter</strong></span>十分有用，能节省大量的时间，但它却是把不折不扣的双刃剑。首先，这个工具对路径语义极为敏感。仔细检查转储文件中的路径是不是以斜线开头。也许<code class="literal">Node-path</code>和<code class="literal">Copyfrom-path</code>这两个头参数对你有些帮助。</p>
				<pre class="screen">…
Node-path: spreadsheet/Makefile
…
</pre>
				<p>如果这些路径以斜线开头，那么你传递给<span><strong class="command">svndumpfilter include</strong></span>和<span><strong class="command">svndumpfilter exclude</strong></span>的路径也必须以斜线开头（反之亦然）。如果因为某些原因转储文件中的路径没有统一使用或不使用斜线开头，<sup>[<a id="id466012" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#ftn.id466012">14</a>]</sup>也许需要修正这些路径，统一使用斜线开头或不使用斜线开头。</p>
				<p>此外，复制操作生成的路径也会带来麻烦。Subversion支持在版本库中进行复制操作，也就是复制一个存在的路径，生成一个新的路径。问题是，<span><strong class="command">svndumpfilter</strong></span>保留的某个文件或目录可能是由某个<span><strong class="command">svndumpfilter</strong></span>排除的文件或目录复制而来的。也就是说，为了确保转储数据的完整性，<span><strong class="command">svndumpfilter</strong></span>需要切断这些复制自被排除路径的文件与源文件的关系，还要将这些文件的内容以新建的方式添加到转储数据中。但是由于Subversion版本库转储文件格式中仅包含了修订版本的更改信息，因此源文件的内容基本上无法获得。如果你不能确定版本库中是否存在类似的情况，最好重新考虑一下到底保留/排除哪些路径。</p>
		</div>
		<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h4 class="title">
												<a id="svn-ch-5-sect-3.1.4">
												</a>svnshell.py</h4>
								</div>
						</div>
				</div>
				<p>Subversion源代码树中有一个类似于shell的版本库访问界面。Python脚本<span><strong class="command">svnshell.py</strong></span>（位于源代码树的<code class="filename">tools/examples/</code>下）通过Subversion语言绑定接口（所以运行这个脚本须要正确的编译和安装这些程序包）连接到版本库和文件系统库。</p>
				<p>运行这个脚本，你可以浏览版本库中的目录，就像在shell下浏览文件系统一样。一开始，你“<span class="quote">位于</span>”修订版本<code class="literal">HEAD</code>的根目录中， 在命令提示符中可以看到相应的提示。 任何时候都可以使用<code class="literal">help</code>命令显示当前可用的命令帮助。</p>
				<pre class="screen">$ svnshell.py /path/to/repos
&lt;rev: 2 /&gt;$  help
Available commands:
  cat FILE     : dump the contents of FILE
  cd DIR       : change the current working directory to DIR
  exit         : exit the shell
  ls [PATH]    : list the contents of the current directory
  lstxns       : list the transactions available for browsing
  setrev REV   : set the current revision to browse
  settxn TXN   : set the current transaction to browse
  youngest     : list the youngest browsable revision number
&lt;rev: 2 /&gt;$
</pre>
				<p>浏览版本库的目录结构就像在Unix或Windows shell中一样——使用<code class="literal">cd</code>命令。任何时候，命令提示符中都会显示当前所在的修订版本（前缀为<code class="literal">rev:</code>）或事务（前缀为<code class="literal">txn:</code>，以及你所在的路径。你可以用<code class="literal">setrev</code>和<code class="literal">settxn</code>切换到其它修订版本或事务中去。你可以像在Unix shell中那样，使用<code class="literal">ls</code>命令列出目录的内容，使用<code class="literal">cat</code>命令列出文件的内容。</p>
				<div class="example">
						<a id="svn-ch-8-sect-3.1.3-ex-1">
						</a>
						<p class="title">
								<b>例 5.1. 使用svnshell浏览版本库</b>
						</p>
						<div class="example-contents">
								<pre class="screen">&lt;rev: 2 /&gt;$ ls
   REV   AUTHOR  NODE-REV-ID     SIZE         DATE NAME
----------------------------------------------------------------------------
     1    sally &lt;     2.0.1&gt;          Nov 15 11:50 A/
     2    harry &lt;     1.0.2&gt;       56 Nov 19 08:19 iota
&lt;rev: 2 /&gt;$ cd A
&lt;rev: 2 /A&gt;$ ls
   REV   AUTHOR  NODE-REV-ID     SIZE         DATE NAME
----------------------------------------------------------------------------
     1    sally &lt;     4.0.1&gt;          Nov 15 11:50 B/
     1    sally &lt;     a.0.1&gt;          Nov 15 11:50 C/
     1    sally &lt;     b.0.1&gt;          Nov 15 11:50 D/
     1    sally &lt;     3.0.1&gt;       23 Nov 15 11:50 mu
&lt;rev: 2 /A&gt;$ cd D/G 
&lt;rev: 2 /A/D/G&gt;$ ls
   REV   AUTHOR  NODE-REV-ID     SIZE         DATE NAME
----------------------------------------------------------------------------
     1    sally &lt;     e.0.1&gt;       23 Nov 15 11:50 pi
     1    sally &lt;     f.0.1&gt;       24 Nov 15 11:50 rho
     1    sally &lt;     g.0.1&gt;       24 Nov 15 11:50 tau
&lt;rev: 2 /A&gt;$ cd ../..
&lt;rev: 2 /&gt;$ cat iota
This is the file 'iota'.
Added this text in revision 2.

&lt;rev: 2 /&gt;$ setrev 1; cat iota
This is the file 'iota'.

&lt;rev: 1 /&gt;$ exit
$
</pre>
						</div>
				</div>
				<br class="example-break" />
				<p>在上例中可以看到，可以将几条命令现在同一行中，并以分号隔开。此外，这个shell也能正确处理相对路径和绝对路径，以及特殊的路径<code class="literal">.</code>和<code class="literal">..</code>。</p>
				<p>
						<code class="literal">youngest</code>命令将列出最年轻的修订版本。这可以用来确定<code class="literal">setrev</code>命令参数的范围—你可以浏览所有0到最年轻修订版本中的任何一个（它们都以整数为标识）。确定可以浏览的事务就不这么简单了。你需要使用<span><strong class="command">lstxns</strong></span>命令列出哪些事务可以浏览。<span><strong class="command">lstxns</strong></span>命令的输出与<span><strong class="command">svnadmin lstxns</strong></span>的输出相同，设置了<code class="option">--transaction</code>选项的<span><strong class="command">svnlook</strong></span>命令也可以得到相同的结果。</p>
				<p>使用<span><strong class="command">exit</strong></span>命令可以退出这个shell。也可以使用文件结束符—Control-D（在某些Win32的Python版本中用Control-Z代替）。</p>
		</div>
		<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h4 class="title">
												<a id="svn-ch-5-sect-3.1.5">
												</a>Berkeley DB工具</h4>
								</div>
						</div>
				</div>
				<p>如果你使用Berkeley DB版本库，那么所有纳入版本控制的文件系统结构和数据都储存在一系列数据库的表中，而这个位于版本库的<code class="filename">db</code>子目录下。这个子目录是一个标准的Berkeley DB环境目录，可以应用任何Berkeley数据库工具进行操作（参考SleepyCat网站<code class="systemitem">http://www.sleepycat.com/</code>上关于这些工具的介绍）。</p>
				<p>对于Subversion的日常使用来说，这些工具并没有什么用处。大多数Subversion版本库必须的数据库操作都集成到<span><strong class="command">svnadmin</strong></span>工具中。比如，<span><strong class="command">svnadmin list-unused-dblogs</strong></span>和<span><strong class="command">svnadmin list-dblogs</strong></span>实现了Berkeley <span><strong class="command">db_archive</strong></span>命令功能的一个子集，而<span><strong class="command">svnadmin recover</strong></span>则起到了 <span><strong class="command">db_recover</strong></span>工具的作用。</p>
				<p>当然，还有一些Berkeley DB工具有时是有用的。<span><strong class="command">db_dump</strong></span>将Berkeley DB数据库中的键值对以特定的格式写入文件中，而<span><strong class="command">db_load</strong></span>则可以将这些键值对注入到数据库中。Berkeley数据库本身不支持跨平台转移，这两个工具在这样的情况下就可以实现在平台间转移数据库的功能，而无需关心操作系统或机器架构。此外，<span><strong class="command">db_stat</strong></span>工具能够提供关于Berkeley DB环境的许多有用信息，包括详细的锁定和存储子系统的统计信息。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-5-sect-3.2">
												</a>版本库清理</h3>
								</div>
						</div>
				</div>
				<p>Subversion版本库一旦按照需要配置完成，一般情况下不需要特别的关照。不过有些时候还是需要管理员手工干预一下。<span><strong class="command">svnadmin</strong></span>工具就能够帮你完成以下这类工作：</p>
				<div class="itemizedlist">
						<ul type="disc">
								<li>
										<p>修改提交日志信息，</p>
								</li>
								<li>
										<p>移除中止的事务，</p>
								</li>
								<li>
										<p>恢复“<span class="quote">塞住</span>”的版本库，以及</p>
								</li>
								<li>
										<p>将一个版本库中的内容搬移到另一个版本库中。</p>
								</li>
						</ul>
				</div>
				<p>
						<span>
								<strong class="command">svnadmin</strong>
						</span>的子命令中最经常用到的恐怕就是<code class="literal">setlog</code>。用户在提交时输入的日志信息随着相关事务提交到版本库并升级成为修订版本后，便作为新修订版本的非版本化（即没有进行版本管理）属性保存下来。换句话说，版本库只记得最新的属性值，而忽略以前的。</p>
				<p>有时用户输入的日志信息有错误（比如拼写错误或者内容错误）。如果配置版本库时设置了（使用<code class="literal">pre-revprop-change</code>和 <code class="literal">post-revprop-change</code>钩子；参见<a title="钩子脚本" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-2.html#svn-ch-5-sect-2.1">“钩子脚本”一节</a>）允许用户在提交后修改日志信息的选项，那么用户可以使用<span><strong class="command">svn</strong></span>程序的<code class="literal">propset</code>命令（参见<a title="第&amp;nbsp;9&amp;nbsp;章&amp;nbsp;Subversion完全参考" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-9.html">第 9 章 <i>Subversion完全参考</i></a>）“<span class="quote">修正</span>”日志信息中的错误。不过为了避免永远丢失信息，Subversion版本库通常设置为仅能由管理员修改非版本化属性（这也是默认的选项）。</p>
				<p>如果管理员想要修改日志信息，那么可以使用<span><strong class="command">svnadmin setlog</strong></span>命令。这个命令从指定的文件中读取信息，取代版本库中某个修订版本的日志信息（<code class="literal">svn:log</code>属性）。</p>
				<pre class="screen">$ echo "Here is the new， correct log message" &gt; newlog.txt
$ svnadmin setlog myrepos newlog.txt -r 388
</pre>
				<p>即使是<span><strong class="command">svnadmin setlog</strong></span>命令也受到限制。<code class="literal">pre-</code>和 <code class="literal">post-revprop-change</code>钩子同样会被触发，因此必须进行相应的设置才能允许修改非版本化属性。不过管理员可以使用<span><strong class="command">svnadmin setlog</strong></span>命令的<code class="option">--bypass-hooks</code>选项跳过钩子。</p>
				<div class="warning" style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
						<h3 class="title">警告</h3>
						<p>不过需要注意的是，一旦跳过钩子也就跳过了钩子所提供的所有功能，比如邮件通知（通知属性有改动）、系统备份（可以用来跟踪非版本化的属性变更）等等。换句话说，要留心你所作出的修改，以及你作出修改的方式。</p>
				</div>
				<p>
						<span>
								<strong class="command">svnadmin</strong>
						</span>的另一个常见用途是查询异常的—可能是已经死亡的—Subversion事务。通常提交操作失败时，与之相关的事务就会被清除。也就是说，事务本身及所有与该事务相关（且仅与该事务相关）的数据会从版本库中删除。不过偶尔也会出现操作失败而事务没有被清除的情况。出现这种情况可能有以下原因：客户端的用户粗暴的结束了操作，操作过程中出现网络故障，等等。不管是什么原因，死亡的事务总是有可能会出现。这类事务不会产生什么负面影响，仅仅是消耗了一点点磁盘空间。不过，严厉的管理员总是希望能够将它们清除出去。</p>
				<p>可以使用<span><strong class="command">svnadmin</strong></span>的<code class="literal">lstxns</code> 命令列出当前的异常事务名。</p>
				<pre class="screen">$ svnadmin lstxns myrepos
19
3a1
a45
$
</pre>
				<p>将输出的结果条目作为<span><strong class="command">svnlook</strong></span>（设置<code class="option">--transaction</code>选项）的参数，就可以获得事务的详细信息，如事务的创建者、创建时间，事务已作出的更改类型，由这些信息可以判断出是否可以将这个事务安全的删除。如果可以安全删除，那么只需将事务名作为参数输入到<span><strong class="command">svnadmin rmtxns</strong></span>，就可以将事务清除掉了。其实<code class="literal">rmtxns</code>子命令可以直接以<code class="literal">lstxns</code>的输出作为输入进行清理。</p>
				<pre class="screen">$ svnadmin rmtxns myrepos `svnadmin lstxns myrepos`
$
</pre>
				<p>在按照上面例子中的方法清理版本库之前，你或许应该暂时关闭版本库和客户端的连接。这样在你开始清理之前，不会有正常的事务进入版本库。下面例子中的shell脚本可以用来迅速获得版本库中异常事务的信息：</p>
				<div class="example">
						<a id="svn-ch-5-sect-3.2-ex-1">
						</a>
						<p class="title">
								<b>例 5.2. txn-info.sh（异常事务报告）</b>
						</p>
						<div class="example-contents">
								<pre class="programlisting">#!/bin/sh

### Generate informational output for all outstanding transactions in
### a Subversion repository.

REPOS="${1}"
if [ "x$REPOS" = x ] ; then
  echo "usage: $0 REPOS_PATH"
  exit
fi

for TXN in `svnadmin lstxns ${REPOS}`; do 
  echo "---[ Transaction ${TXN} ]-------------------------------------------"
  svnlook info "${REPOS}" --transaction "${TXN}"
done
</pre>
						</div>
				</div>
				<br class="example-break" />
				<p>可以用下面的命令使用上例中脚本： <span><strong class="command">/path/to/txn-info.sh /path/to/repos</strong></span>。该命令的输出主要由多个<span><strong class="command">svnlook info</strong></span>参见<a title="svnlook" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#svn-ch-5-sect-3.1.1">“svnlook”一节</a>）的输出组成，类似于下面的例子：</p>
				<pre class="screen">$ txn-info.sh myrepos
---[ Transaction 19 ]-------------------------------------------
sally
2001-09-04 11:57:19 -0500 (Tue， 04 Sep 2001)
0
---[ Transaction 3a1 ]-------------------------------------------
harry
2001-09-10 16:50:30 -0500 (Mon， 10 Sep 2001)
39
Trying to commit over a faulty network.
---[ Transaction a45 ]-------------------------------------------
sally
2001-09-12 11:09:28 -0500 (Wed， 12 Sep 2001)
0
$
</pre>
				<p>一个废弃了很长时间的事务通常是提交错误或异常中断的结果。事务的时间戳可以提供给我们一些有趣的信息，比如一个进行了9个月的操作居然还是活动的等等。</p>
				<p>简言之，作出事务清理的决定前应该仔细考虑一下。许多信息源—比如Apache的错误和访问日志，已成功完成的Subversion提交日志等等—都可以作为决策的参考。管理员还可以直接和那些似乎已经死亡事务的提交者直接交流（比如通过邮件），来确认该事务确实已经死亡了。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-5-sect-3.3">
												</a>管理磁盘空间</h3>
								</div>
						</div>
				</div>
				<p>虽然存储器的价格在过去的几年里以让人难以致信的速度滑落，但是对于那些需要对大量数据进行版本管理的管理员们来说，磁盘空间的消耗依然是一个重要的因素。版本库每增加一个字节都意味着需要多一个字节的磁盘空间进行备份，对于多重备份来说，就需要消耗更多的磁盘空间。Berkeley DB版本库的主要存储机制是基于一个复杂的数据库系统建立的，因此了解一些数据性质是有意义的，比如哪些数据必须保留。哪些数据需要备份、哪些数据可以安全的删除等等。本节的内容专注于Berkeley DB类型的版本库。FSFS类型的版本库不需要进行数据清理和回收。</p>
				<p>目前为止，Subversion版本库中耗费磁盘空间的最大凶手是日志文件，每次Berkeley DB在修改真正的数据文件之前都会进行预写入（pre-writes）操作。这些文件记录了数据库从一个状态变化到另一个状态的所有动作——数据库文件反应了特定时刻数据库的状态，而日志文件则记录了所有状态变化的信息。因此，日志文件会以很快的速度膨胀起来。</p>
				<p>幸运的是，从版本4.2开始，Berkeley DB的数据库环境无需额外的操作即可删除无用的日志文件。如果编译<span><strong class="command">svnadmin</strong></span>时使用了高于4.2版本的Berkeley DB，那么由此<span><strong class="command">svnadmin</strong></span>程序创建的版本库就具备了自动清除日志文件的功能。如果想屏蔽这个功能，只需设置<span><strong class="command">svnadmin create</strong></span>命令的<code class="option">--bdb-log-keep</code>选项即可。如果创建版本库以后想要修改关于此功能的设置，只需编辑版本库中<code class="filename">db</code>目录下的<code class="filename">DB_CONFIG</code>文件，注释掉包含<code class="literal">set_flags DB_LOG_AUTOREMOVE</code>内容的这一行，然后运行<span><strong class="command">svnadmin recover</strong></span>强制设置生效就行了。查阅<a title="Berkeley DB配置" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-2.html#svn-ch-5-sect-2.2">“Berkeley DB配置”一节</a>获得更多关于数据库配置的帮助信息。</p>
				<p>如果不自动删除日志文件，那么日志文件会随着版本库的使用逐渐增加。这多少应该算是数据库系统的特性，通过这些日志文件可以在数据库严重损坏时恢复整个数据库的内容。但是一般情况下，最好是能够将无用的日志文件收集起来并删除，这样就可以节省磁盘空间。使用<span><strong class="command">svnadmin list-unused-dblogs</strong></span>命令可以列出无用的日志文件：</p>
				<pre class="screen">$ svnadmin list-unused-dblogs /path/to/repos
/path/to/repos/log.0000000031
/path/to/repos/log.0000000032
/path/to/repos/log.0000000033

$ svnadmin list-unused-dblogs /path/to/repos | xargs rm
## disk space reclaimed!
</pre>
				<p>为了尽可能减小版本库的体积，Subversion在版本库中采用了<em class="firstterm">增量化技术</em>（或称为“<span class="quote">增量存储技术</span>”）。增量化技术可以将一组数据表示为相对于另一组数据的不同。如果这两组数据十分相似，增量化技术就可以仅保存其中一组数据以及两组数据的差别，而不需要同时保存两组数据，从而节省了磁盘空间。每次一个文件的新版本提交到版本库，版本库就会将之前的版本（之前的多个版本）相对于新版本做增量化处理。采用了这项技术，版本库的数据量大小基本上是可以估算出来的—主要是版本化的文件的大小—并且远小于“<span class="quote">全文</span>”保存所需的数据量。</p>
				<div class="note" style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
						<h3 class="title">注意</h3>
						<p>由于Subversion版本库的增量化数据保存在单一Berkeley DB数据库文件中，减少数据的体积并不一定能够减小数据库文件的大小。但是，Berkeley DB会在内部记录未使用的数据库文件区域，并且在增加数据库文件大小之前会首先使用这些未使用的区域。因此，即使增量化技术不能立杆见影的节省磁盘空间，也可以极大的减慢数据库的膨胀速度。</p>
				</div>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-5-sect-3.4">
												</a>版本库的恢复</h3>
								</div>
						</div>
				</div>
				<p>
						<a title="Berkeley DB" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5.html#svn-ch-5-sect-1.3.1">“Berkeley DB”一节</a>中曾提到，Berkeley DB版本库如果没有正常关闭可能会进入冻结状态。这时，就需要管理员将数据库恢复到正常状态。</p>
				<p>Berkeley DB使用一种锁机制保护版本库中的数据。锁机制确保数据库不会同时被多个访问进程修改，也就保证了从数据库中读取到的数据始终是稳定而且正确的。当一个进程需要修改数据库中的数据时，首先必须检查目标数据是否已经上锁。如果目标数据没有上锁，进程就将它锁上，然后作出修改，最后再将锁解除。而其它进程则必须等待锁解除后才能继续访问数据库中的相关内容。</p>
				<p>在操作Subversion版本库的过程中，致命错误（如内存或硬盘空间不足）或异常中断可能会导致某个进程没能及时将锁解除。结果就是后端的数据库系统被“<span class="quote">塞住</span>”了。一旦发生这种情况，任何访问版本库的进程都会挂起（每个访问进程都在等待锁被解除，但是锁已经无法解除了）。</p>
				<p>首先，如果你的版本库出现这种情况，没什么好惊慌的。Berkeley DB的文件系统采用了数据库事务、检查点以及预写入日志等技术来取保只有灾难性的事件<sup>[<a id="id467417" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#ftn.id467417">15</a>]</sup>才能永久性的破坏数据库环境。所以虽然一个过于稳重的版本库管理员通常都会按照某种方案进行大量的版本库离线备份，不过不要急着通知你的管理员进行恢复。</p>
				<p>然后，使用下面的方法试着“<span class="quote">恢复</span>”你的版本库：</p>
				<div class="orderedlist">
						<ol type="1">
								<li>
										<p>确保没有其它进程访问（或者试图访问）版本库。对于网络版本库，关闭Apache HTTP服务器是个好办法。</p>
								</li>
								<li>
										<p>成为版本库的拥有者和管理员。这一点很重要，如果以其它用户的身份恢复版本库，可能会改变版本库文件的访问权限，导致在版本库“<span class="quote">恢复</span>”后依旧无法访问。</p>
								</li>
								<li>
										<p>运行命令<span><strong class="command">svnadmin recover /path/to/repos</strong></span>。 输出如下：</p>
										<pre class="screen">Repository lock acquired。
Please wait; recovering the repository may take some time...

Recovery completed.
The latest repos revision is 19.
</pre>
										<p>此命令可能需要数分钟才能完成。</p>
								</li>
								<li>
										<p>重新启动Subversion服务器。</p>
								</li>
						</ol>
				</div>
				<p>这个方法能修复几乎所有版本库锁住的问题。记住，要以数据库的拥有者和管理员的身份运行这个命令，而不一定是<code class="literal">root</code>用户。恢复过程中可能会使用其它数据存储区（例如共享内存区）重建一些数据库文件。如果以<code class="literal">root</code>用户身份恢复版本库，这些重建的文件拥有者将变成<code class="literal">root</code>用户，也就是说，即使恢复了到版本库的连接，一般的用户也无权访问这些文件。</p>
				<p>如果因为某些原因，上面的方法没能成功的恢复版本库，那么你可以做两件事。首先，将破损的版本库保存到其它地方，然后从最新的备份中恢复版本库。然后，发送一封邮件到Subversion用户列表（地址是：<code class="email">&lt;<a href="mailto:users@subversion.tigris.org">users@subversion.tigris.org</a>&gt;</code>），写清你所遇到的问题。对于Subversion的开发者来说，数据安全是最重要的问题。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-5-sect-3.5">
												</a>版本库的移植</h3>
								</div>
						</div>
				</div>
				<p>Subversion文件系统将数据保存在许多数据库表中，而这些表的结构只有Subversion开发者们才了解（也只有他们才感兴趣）不过，有些时候我们会想到把所有的数据（或者一部分数据）保存在一个独立的、可移植的、普通格式的文件中。Subversion通过<span><strong class="command">svnadmin</strong></span>的两个子命令<code class="literal">dump</code>和<code class="literal">load</code>提供了类似的功能。</p>
				<p>对版本库的转储和装载的需求主要还是由于Subversion自身处于变化之中。在Subversion的成长期，后端数据库的设计多次发生变化，这些变化导致之前的版本库出现兼容性问题。当然，将Berkeley DB版本库移植到不同的操作系统或者CPU架构上，或者在Berkeley DB和FSFS后端之间进行转化也需要转储和装载功能。按照下面的介绍，只需简单几步就可以完成数据库的移植：</p>
				<div class="orderedlist">
						<ol type="1">
								<li>
										<p>使用<span class="emphasis"><em>当前</em></span>版本的<span><strong class="command">svnadmin</strong></span>将版本库转储到文件中。</p>
								</li>
								<li>
										<p>升级Subversion。</p>
								</li>
								<li>
										<p>移除以前的版本库，并使用<span class="emphasis"><em>新版本</em></span>的<span><strong class="command">svnadmin</strong></span>在原来版本库的位置建立空的版本库。</p>
								</li>
								<li>
										<p>还是使用<span class="emphasis"><em>新版本</em></span>的<span><strong class="command">svnadmin</strong></span>从转储文件中将数据装载到新建的空版本库中。</p>
								</li>
								<li>
										<p>记住从以前的版本库中复制所有的定制文件到新版本库中，包括<code class="filename">DB_CONFIG</code>文件和钩子脚本。最好阅读一下新版本的release notes，看看此次升级是否会影响钩子和配置选项。</p>
								</li>
								<li>
										<p>如果移植的同时改变的版本库的访问地址（比如移植到另一台计算机或者改变了访问策略），那么可以通知用户运行<span><strong class="command">svn switch --relocate</strong></span>来切换他们的工作副本。参见<a title="svn switch" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-9-sect-1.2-re-switch.html">svn switch</a>。</p>
								</li>
						</ol>
				</div>
				<p>
						<span>
								<strong class="command">svnadmin dump</strong>
						</span>命令会将版本库中的修订版本数据按照特定的格式输出到转储流中。转储数据会输出到标准输出流，而提示信息会输出到标准错误流。这就是说，可以将转储数据存储到文件中，而同时在终端窗口中监视运行状态。例如：</p>
				<pre class="screen">$ svnlook youngest myrepos
26
$ svnadmin dump myrepos &gt; dumpfile
* Dumped revision 0.
* Dumped revision 1.
* Dumped revision 2.
…
* Dumped revision 25.
* Dumped revision 26.
</pre>
				<p>最后，版本库中的指定的修订版本数据被转储到一个独立的文件中（在上面的例子中是<code class="filename">dumpfile</code>）。注意，<span><strong class="command">svnadmin dump</strong></span>从版本库中读取修订版本树与其它“<span class="quote">读者</span>”（比如<span><strong class="command">svn checkout</strong></span>）的过程相同，所以可以在任何时候安全的运行这个命令。</p>
				<p>另一个命令，<span><strong class="command">svnadmin load</strong></span>，从标准输入流中读取Subversion转储数据，并且高效的将数据转载到目标版本库中。这个命令的提示信息输出到标准输出流中：</p>
				<pre class="screen">$ svnadmin load newrepos &lt; dumpfile
&lt;&lt;&lt; Started new txn, based on original revision 1
     * adding path : A ... done.
     * adding path : A/B ... done.
     …
------- Committed new rev 1 (loaded from original rev 1) &gt;&gt;&gt;

&lt;&lt;&lt; Started new txn, based on original revision 2
     * editing path : A/mu ... done.
     * editing path : A/D/G/rho ... done.

------- Committed new rev 2 (loaded from original rev 2) &gt;&gt;&gt;

…

&lt;&lt;&lt; Started new txn, based on original revision 25
     * editing path : A/D/gamma ... done.

------- Committed new rev 25 (loaded from original rev 25) &gt;&gt;&gt;

&lt;&lt;&lt; Started new txn, based on original revision 26
     * adding path : A/Z/zeta ... done.
     * editing path : A/mu ... done.

------- Committed new rev 26 (loaded from original rev 26) &gt;&gt;&gt;

</pre>
				<p>既然<span><strong class="command">svnadmin</strong></span>使用标准输入流和标准输出流作为转储和装载的输入和输出，那么更漂亮的用法是（管道两端可以是不同版本的<span><strong class="command">svnadmin</strong></span>：</p>
				<pre class="screen">$ svnadmin create newrepos
$ svnadmin dump myrepos | svnadmin load newrepos
</pre>
				<p>默认情况下，转储文件的体积可能会相当庞大——比版本库自身大很多。这是因为在转储文件中，每个文件的每个版本都以完整的文本形式保存下来。这种方法速度很快，而且很简单，尤其是直接将转储数据通过管道输入到其它进程中时（比如一个压缩程序，过滤程序，或者一个装载进程）。不过如果要长期保存转储文件，那么可以使用<code class="option">--deltas</code>选项来节省磁盘空间。设置这个选项，同一个文件的数个连续修订版本会以增量式的方式保存—就像储存在版本库中一样。这个方法较慢，但是转储文件的体积则基本上与版本库的体积相当。</p>
				<p>之前我们提到<span><strong class="command">svnadmin dump</strong></span>输出指定的修订版本。使用<code class="option">--revision</code>选项可以指定一个单独的修订版本，或者一个修订版本的范围。如果忽略这个选项，所有版本库中的修订版本都会被转储。</p>
				<pre class="screen">$ svnadmin dump myrepos --revision 23 &gt; rev-23.dumpfile
$ svnadmin dump myrepos --revision 100:200 &gt; revs-100-200.dumpfile
</pre>
				<p>Subversion在转储修订版本时，仅会输出与前一个修订版本之间的差异，通过这些差异足以从前一个修订版本中重建当前的修订版本。换句话说，在转储文件中的每一个修订版本仅包含这个修订版本作出的修改。这个规则的唯一一个例外是当前<span><strong class="command">svnadmin dump</strong></span>转储的第一个修订版本。</p>
				<p>默认情况下，Subversion不会把转储的第一个修订版本看作对前一个修订版本的更改。 首先，转储文件中没有比第一个修订版本更靠前的修订版本了！其次，Subversion不知道装载转储数据时（如果真的需要装载的话）的版本库是什么样的情况。为了保证每次运行<span><strong class="command">svnadmin dump</strong></span>都能得到一个独立的结果，第一个转储的修订版本默认情况下会完整的保存目录、文件以及属性等数据。</p>
				<p>不过，这些都是可以改变的。如果转储时设置了<code class="option">--incremental</code>选项，<span><strong class="command">svnadmin</strong></span>会比较第一个转储的修订版本和版本库中前一个修订版本，就像对待其它转储的修订版本一样。转储时也是一样，转储文件中将仅包含第一个转储的修订版本的增量信息。这样的好处是，可以创建几个连续的小体积的转储文件代替一个大文件，比如：</p>
				<pre class="screen">$ svnadmin dump myrepos --revision 0:1000 &gt; dumpfile1
$ svnadmin dump myrepos --revision 1001:2000 --incremental &gt; dumpfile2
$ svnadmin dump myrepos --revision 2001:3000 --incremental &gt; dumpfile3
</pre>
				<p>这些转储文件可以使用下列命令装载到一个新的版本库中：</p>
				<pre class="screen">$ svnadmin load newrepos &lt; dumpfile1
$ svnadmin load newrepos &lt; dumpfile2
$ svnadmin load newrepos &lt; dumpfile3
</pre>
				<p>另一个有关的技巧是，可以使用<code class="option">--incremental</code>选项在一个转储文件中增加新的转储修订版本。举个例子，可以使用<code class="literal">post-commit</code>钩子在每次新的修订版本提交后将其转储到文件中。或者，可以编写一个脚本，在每天夜里将所有新增的修订版本转储到文件中。这样，<span><strong class="command">svnadmin</strong></span>的<code class="literal">dump</code>和<code class="literal">load</code>命令就变成了很好的版本库备份工具，万一出现系统崩溃或其它灾难性事件，它的价值就体现出来了。</p>
				<p>转储还可以用来将几个独立的版本库合并为一个版本库。使用<span><strong class="command">svnadmin load</strong></span>的<code class="option">--parent-dir</code>选项，可以在装载的时候指定根目录。也就是说，如果有三个不同版本库的转储文件，比如<code class="filename">calc-dumpfile</code>，<code class="filename">cal-dumpfile</code>，和<code class="filename">ss-dumpfile</code>，可以在一个新的版本库中保存所有三个转储文件中的数据：</p>
				<pre class="screen">$ svnadmin create /path/to/projects
$
</pre>
				<p>然后在版本库中创建三个目录分别保存来自三个不同版本库的数据：</p>
				<pre class="screen">$ svn mkdir -m "Initial project roots" \
      file:///path/to/projects/calc \
      file:///path/to/projects/calendar \
      file:///path/to/projects/spreadsheet
Committed revision 1.
$ 
</pre>
				<p>最后，将转储文件分别装载到各自的目录中：</p>
				<pre class="screen">$ svnadmin load /path/to/projects --parent-dir calc &lt; calc-dumpfile
…
$ svnadmin load /path/to/projects --parent-dir calendar &lt; cal-dumpfile
…
$ svnadmin load /path/to/projects --parent-dir spreadsheet &lt; ss-dumpfile
…
$
</pre>
				<p>我们再介绍一下Subversion版本库转储数据的最后一种用途——在不同的存储机制或版本控制系统之间转换。因为转储数据的格式的大部分是可以阅读的，<sup>[<a id="id467972" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#ftn.id467972">16</a>]</sup>所以使用这种格式描述变更集（每个变更集对应一个新的修订版本）会相对容易一些。事实上，<span><strong class="command">cvs2svn.py</strong></span>工具（参见 <a title="转化CVS版本库到Subversion" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ap-a-sect-11.html">“转化CVS版本库到Subversion”一节</a>）正是将CVS版本库的内容转换为转储数据格式，如此才能将CVS版本库的数据导入Subversion版本库之中。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-5-sect-3.6">
												</a>版本库备份</h3>
								</div>
						</div>
				</div>
				<p>尽管现代计算机的诞生带来了许多便利，但有一件事听起来是完全正确的—有时候，事情变的糟糕，很糟糕，动力损耗、网络中断、坏掉的内存和损坏的硬盘都是对魔鬼的一种体验，即使对于最尽职的管理员，命运也早已注定。所以我们来到了这个最重要的主题—怎样备份你的版本库数据。</p>
				<p>Subversion版本库管理员通常有两种备份方式—增量的和完全的。我们在早先的章节曾经讨论过如何使用<span><strong class="command">svnadmin dump --incremental</strong></span>命令执行增量备份（见<a title="版本库的移植" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#svn-ch-5-sect-3.5">“版本库的移植”一节</a>），从本质上讲，这个方法只是备份了从你上次备份版本库到现在的变化。</p>
				<p>一个完全的版本库备份照字面上讲就是对整个版本库目录的复制（包括伯克利数据库或者文件FSFS环境），现在，除非你临时关闭了其他对版本库的访问，否则仅仅做一次迭代的拷贝会有产生错误备份的风险，因为有人可能会在并行的写数据库。</p>
				<p>如果是伯克利数据库，恼人的文档描述了保证安全拷贝的步骤，对于FSFS的数据，也有类似的顺序。我们有更好的选择，我们不需要自己去实现这个算法，因为Subversion开发小组已经为你实现了这些算法。Subversion源文件分发版本的<code class="filename">tools/backup/</code>目录有一个<span><strong class="command">hot-backup.py</strong></span>文件。只要给定了版本库路径和备份路径，<span><strong class="command">hot-backup.py</strong></span>—一个包裹了<span><strong class="command">svnadmin hotcopy</strong></span>但更加智能的命令—将会执行必要的步骤来备份你的活动的版本库—不需要你首先禁止公共的版本库访问—而且之后会从你的版本库清理死掉的伯克利日志文件。</p>
				<p>甚至当你用了一个增量备份时，你也会希望有计划的运行这个程序。举个例子，你考虑在你的调度程序（如Unix下的<span><strong class="command">cron</strong></span>）里加入<span><strong class="command">hot-backup.py</strong></span>，或者你喜欢更加细致的备份解决方案，你可以让你的post-commit的钩子脚本执行<span><strong class="command">hot-backup.py</strong></span>（见see <a title="钩子脚本" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-2.html#svn-ch-5-sect-2.1">“钩子脚本”一节</a>），这样会导致你的版本库的每次提交执行一次备份，只要在你的<code class="filename">hooks/post-commit</code>脚本里添加如下代码：</p>
				<pre class="programlisting">(cd /path/to/hook/scripts; ./hot-backup.py ${REPOS} /path/to/backups &amp;)
</pre>
				<p>作为结果的备份是一个完全功能的版本库，当发生严重错误时可以作为你的活动版本库的替换。</p>
				<p>两种备份方式都有各自的优点，最简单的方式是完全备份，将会每次建立版本库的完美复制品，这意味着如果当你的活动版本库发生了什么事情，你可以用备份恢复。但不幸的是，如果你维护多个备份，每个完全的备份会吞噬掉和你的活动版本库同样的空间。</p>
				<p>增量备份会使用的版本库转储格式，在Subversion的数据库模式改变时非常完美，因此当我们升级Subversion数据库模式的时候，一个完整的版本库导出和导入是必须的，做一半工作非常的容易（导出部分），不幸的是，增量备份的创建和恢复会占用很长时间，因为每一次提交都会被重放。</p>
				<p>在每一种备份情境下，版本库管理员需要意识到对未版本化的修订版本属性的修改对备份的影响，因为这些修改本身不会产生新的修订版本，所以不会触发post-commit的钩子程序，也不会触发pre-revprop-change和post-revprop-change的钩子。 <sup>[<a id="id468201" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#ftn.id468201">17</a>]</sup> 而且因为你可以改变修订版本的属性，而不需要遵照时间顺序—你可在任何时刻修改任何修订版本的属性—因此最新版本的增量备份不会捕捉到以前特定修订版本的属性修改。</p>
				<p>通常说来，在每次提交时，只有妄想狂才会备份整个版本库，然而，假设一个给定的版本库拥有一些恰当粒度的冗余机制（如每次提交的邮件）。版本库管理员也许会希望将版本库的热备份引入到系统级的每夜备份，对大多数版本库，归档的提交邮件为保存资源提供了足够的冗余措施，至少对于最近的提交。但是它是你的数据—你喜欢怎样保护都可以。</p>
				<p>通常情况下，最好的版本库备份方式是混合的，你可以平衡完全和增量备份，另外配合提交邮件的归档，Subversion开发者，举个例子，在每个新的修订版本建立时备份Subversion的源代码版本库，并且保留所有的提交和属性修改通知文件。你的解决方案类似，必须迎合你的需要，平衡便利和你的偏执。然而这些不会改变你的硬件来自钢铁的命运。<sup>[<a id="id468236" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#ftn.id468236">18</a>]</sup> 这一定会帮助你减少尝试的时间。</p>
		</div>
		<div class="footnotes">
				<br />
				<hr align="left" width="100" />
				<div class="footnote">
						<p>
								<sup>[<a id="ftn.id465486" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#id465486">13</a>] </sup>顺便说一句，这是Subversion的<span class="emphasis"><em>特性</em></span>，而不是bug。</p>
				</div>
				<div class="footnote">
						<p>
								<sup>[<a id="ftn.id466012" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#id466012">14</a>] </sup>尽管<span><strong class="command">svnadmin dump</strong></span>对是否以斜线作为路径的开头有统一的规定——这个规定就是不以斜线作为路径的开头——其它生成转储文件的程序不一定会遵守这个规定。</p>
				</div>
				<div class="footnote">
						<p>
								<sup>[<a id="ftn.id467417" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#id467417">15</a>] </sup>比如：硬盘 + 大号电磁铁 = 毁灭。</p>
				</div>
				<div class="footnote">
						<p>
								<sup>[<a id="ftn.id467972" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#id467972">16</a>] </sup>Subversion版本库的转储文件格式类似于RFC-822格式，后者广泛的应用于电子邮件系统中。</p>
				</div>
				<div class="footnote">
						<p>
								<sup>[<a id="ftn.id468201" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#id468201">17</a>] </sup>
								<span>
										<strong class="command">svnadmin setlog</strong>
								</span>可以被绕过钩子程序被调用。</p>
				</div>
				<div class="footnote">
						<p>
								<sup>[<a id="ftn.id468236" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-3.html#id468236">18</a>] </sup>你知道的—只是对各种变化莫测的问题的统称。</p>
				</div>
		</div><img src ="http://www.cnitblog.com/tilan/aggbug/21817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-12 14:41 <a href="http://www.cnitblog.com/tilan/articles/21817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>subversion 分支维护</title><link>http://www.cnitblog.com/tilan/articles/21816.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 12 Jan 2007 06:40:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21816.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21816.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21816.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21816.html</trackback:ping><description><![CDATA[<p>你一定注意到了Subversion极度的灵活性，因为它用相同的底层机制（目录拷贝）实现了分支和标签，因为分支和标签是作为普通的文件系统出现，会让人们感到害怕，因为它<span class="emphasis"><em>太</em></span>灵活了，在这个小节里，我们会提供安排和管理数据的一些建议。</p>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-4-sect-7.1">
												</a>版本库布局</h3>
								</div>
						</div>
				</div>
				<p>有一些标准的，推荐的组织版本库的方式，许多人创建一个<code class="filename">trunk</code>目录来保存开发的“<span class="quote">主线</span>”，一个<code class="filename">branches</code>目录存放分支拷贝，一个目录保存标签拷贝，如果一个版本库只是存放一个项目，人们会在顶级目录创建这些目录：</p>
				<pre class="screen">/trunk
/branches
/tags
</pre>
				<p>如果一个版本库保存了多个项目，管理员会通过项目来布局（见<a title="选择一种版本库布局" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-5-sect-6.html#svn-ch-5-sect-6.1">“选择一种版本库布局”一节</a>关于“<span class="quote">项目根目录</span>”）：</p>
				<pre class="screen">/paint/trunk
/paint/branches
/paint/tags
/calc/trunk
/calc/branches
/calc/tags
</pre>
				<p>当然，你可以自由的忽略这些通常的布局方式，你可以创建任意的变化，只要是对你和你的项目有益，记住无论你选择什么，这不会是一种永久的承诺，你可以随时重新组织你的版本库。因为分支和标签都是普通的目录，<span><strong class="command">svn move</strong></span>命令可以任意的改名和移动它们，从一种布局到另一种大概只是一系列服务器端的移动，如果你不喜欢版本库的组织方式，你可以任意修改目录结构。</p>
				<p>记住，尽管移动目录非常容易，你必须体谅你的用户，你的修改会让你的用户感到迷惑，如果一个用户的拥有一个版本库目录的工作拷贝，你的<span><strong class="command">svn move</strong></span>命令也许会删除最新的版本的这个路径，当用户运行<span><strong class="command">svn update</strong></span>，会被告知这个工作拷贝引用的路径已经不再存在，用户需要强制使用<span><strong class="command">svn switch</strong></span>转到新的位置。 </p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-4-sect-7.2">
												</a>数据的生命周期</h3>
								</div>
						</div>
				</div>
				<p>另一个Subversion模型的可爱特性是分支和标签可以有有限的生命周期，就像其它的版本化的项目，举个例子，假定你最终完成了<code class="filename">calc</code>项目你的个人分支上的所有工作，在合并了你的所有修改到<code class="filename">/calc/trunk</code>后，没有必要继续保留你的私有分支目录：</p>
				<pre class="screen">$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch \
             -m "Removing obsolete branch of calc project."

Committed revision 375.
</pre>
				<p>你的分支已经消失了，当然不是真的消失了：这个目录只是在<code class="literal">HEAD</code>修订版本里消失了，如果你使用<span><strong class="command">svn checkout</strong></span>、<span><strong class="command">svn switch</strong></span>或者<span><strong class="command">svn list</strong></span>来检查一个旧的版本，你仍会见到这个旧的分支。</p>
				<p>如果浏览你删除的目录还不足够，你可以把它找回来，恢复数据对Subversion来说很简单，如果你希望恢复一个已经删除的目录（或文件）到<code class="literal">HEAD</code>，仅需要使用<span><strong class="command">svn copy -r</strong></span>来从旧的版本拷贝出来：</p>
				<pre class="screen">$ svn copy -r 374 http://svn.example.com/repos/calc/branches/my-calc-branch \
                  http://svn.example.com/repos/calc/branches/my-calc-branch

Committed revision 376.
</pre>
				<p>在我们的例子里，你的个人分支只有一个相对短的生命周期：你会为修复一个Bug或实现一个小的特性来创建它，当任务完成，分支也该结束了。在软件开发过程中，有两个“<span class="quote">主要的</span>”分支一直存在很长的时间也是很常见的情况，举个例子，假定我们是发布一个稳定的<code class="filename">calc</code>项目的时候了，但我们仍会需要几个月的时间来修复Bug，你不希望添加新的特性，但你不希望告诉开发者停止开发，所以作为替代，你为软件创建了一个“<span class="quote">分支</span>”，这个分支更改不会很多：</p>
				<pre class="screen">$ svn copy http://svn.example.com/repos/calc/trunk \
         http://svn.example.com/repos/calc/branches/stable-1.0 \
         -m "Creating stable branch of calc project."

Committed revision 377.
</pre>
				<p>而且开发者可以自由的继续添加新的（试验的）特性到<code class="filename">/calc/trunk</code>，你可以宣布这样一种政策，只有bug修正提交到<code class="filename">/calc/branches/stable-1.0</code>，这样的话，人们继续在主干上工作，某个人会选择在稳定分支上做出一些Bug修正，甚至在稳定版本发布之后。你或许会在这个维护分支上工作很长时间—也就是说，你会一直继续为客户提供这个版本的支持。</p>
		</div><img src ="http://www.cnitblog.com/tilan/aggbug/21816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-12 14:40 <a href="http://www.cnitblog.com/tilan/articles/21816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>subversion 标签</title><link>http://www.cnitblog.com/tilan/articles/21815.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 12 Jan 2007 06:39:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21815.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21815.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21815.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21815.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21815.html</trackback:ping><description><![CDATA[<p>另一个常见的版本控制系统概念是标签（<em class="firstterm">tag</em>），一个标签只是一个项目某一时间的“<span class="quote">快照</span>”，在Subversion里这个概念无处不在—每一次提交的修订版本都是一个精确的快照。</p>
		<p>然而人们希望更人性化的标签名称，像<code class="literal">release-1.0</code>。他们也希望可以对一个子目录快照，毕竟，记住release-1.0是修订版本4822的某一小部分不是件很容易的事。</p>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-4-sect-6.1">
												</a>建立最简单的标签</h3>
								</div>
						</div>
				</div>
				<p>
						<span>
								<strong class="command">svn copy</strong>
						</span>再次登场，你希望建立一个<code class="filename">/calc/trunk</code>的一个快照，就像<code class="literal">HEAD</code>修订版本，建立这样一个拷贝：</p>
				<pre class="screen">$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/tags/release-1.0 \
      -m "Tagging the 1.0 release of the 'calc' project."

Committed revision 351.
</pre>
				<p>这个例子假定<code class="filename">/calc/tags</code>目录已经存在（如果不是，见<a title="svn mkdir" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-9-sect-1.2-re-mkdir.html">svn mkdir</a>），拷贝完成之后，一个表示当时<code class="literal">HEAD</code>版本的/calc/trunk目录的镜像已经永久的拷贝到<code class="filename">release-1.0</code>目录。当然，你会希望更精确一点，以防其他人在你不注意的时候提交修改，所以，如果你知道<code class="filename">/calc/trunk</code>的版本350是你想要的快照，你可以使用<span><strong class="command">svn copy</strong></span>加参数 <code class="option">-r 350</code>。</p>
				<p>但是等一下：标签的产生过程与建立分支是一样的？是的，实际上在Subversion中标签与分支没有区别，都是普通的目录，通过copy命令得到，与分支一样，一个目录之所以是标签只是<span class="emphasis"><em>人们</em></span>决定这样使用它，只要没有人提交这个目录，它永远是一个快照，但如果人们开始提交，它就变成了分支。</p>
				<p>如果你管理一个版本库，你有两种方式管理标签，第一种方法是禁止命令：作为项目的政策，我们要决定标签所在的位置，确定所有用户知道如何处理拷贝的目录（也就是确保他们不会提交他们），第二种方法看来很过分：使用访问控制脚本来阻止任何想对标签目录做的非拷贝的操作（见<a title="第&amp;nbsp;6&amp;nbsp;章&amp;nbsp;配置服务器" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-6.html">第 6 章 <i>配置服务器</i></a>）这种方法通常是不必要的，如果一个人不小心提交了到标签目录一个修改，你可以简单的取消，毕竟这是版本控制啊。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-4-sect-6.2">
												</a>建立复杂的标签</h3>
								</div>
						</div>
				</div>
				<p>有时候你希望你的“<span class="quote">快照</span>”能够很复杂，而不只是一个单独修订版本的一个单独目录。</p>
				<p>举个例子，假定你的项目比我们的的例子<code class="filename">calc</code>大的多：假设它保存了一组子目录和许多文件，在你工作时，你或许决定创建一个包括特定特性和Bug修正的工作拷贝，你可以通过选择性的回溯文件和目录到特定修订版本（使用<span><strong class="command">svn update -r</strong></span>）来实现，或者转换文件和目录到特定分支（使用<span><strong class="command">svn switch</strong></span>），这样做之后，你的工作拷贝成为版本库不同版本和分支的司令部，但是经过测试，你会知道这是你需要的一种精确数据组合。</p>
				<p>是时候进行快照了，拷贝URL在这里不能工作，在这个例子里，你希望把本地拷贝的布局做镜像并且保存到版本库中，幸运的是，<span><strong class="command">svn copy</strong></span>包括四种不同的使用方式（在第9章可以详细阅读），包括拷贝工作拷贝到版本库：</p>
				<pre class="screen">$ ls
my-working-copy/

$ svn copy my-working-copy http://svn.example.com/repos/calc/tags/mytag

Committed revision 352.
</pre>
				<p>现在在版本库有一个新的目录<code class="filename">/calc/tags/mytag</code>，这是你的本地拷贝的一个快照—混合了修订版本，URL等等。</p>
				<p>一些人也发现这一特性一些有趣的使用方式，有些时候本地拷贝有一组本地修改，你希望你的协作者看到这些，不使用<span><strong class="command">svn diff</strong></span>并发送一个不定文件（不会捕捉到目录修改），而是使用<span><strong class="command">svn copy</strong></span>来“<span class="quote">上传</span>”你的工作拷贝到一个版本库的私有区域，你的协作者可以选择完整的取出你的工作拷贝，或使用<span><strong class="command">svn merge</strong></span>来接受你的精确修改。</p>
		</div><img src ="http://www.cnitblog.com/tilan/aggbug/21815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-12 14:39 <a href="http://www.cnitblog.com/tilan/articles/21815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>subversion 常见用例  并一条分支到另一支</title><link>http://www.cnitblog.com/tilan/articles/21814.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 12 Jan 2007 06:37:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21814.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21814.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21814.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21814.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21814.html</trackback:ping><description><![CDATA[<p>为了完成这个例子，我们将时间往前推进，假定已经过了几天，在主干和你的分支上都有许多更改，假定你完成了分支上的工作，已经完成了特性或bug修正，你想合并所有分支的修改到主干上，让别人也可以使用。</p>
		<p>这种情况下如何使用<span><strong class="command">svn merge</strong></span>？记住这个命令比较两个目录树，然后应用比较结果到工作拷贝，所以要接受这种变化，你需要主干的工作拷贝，我们假设你有一个最初的主干工作拷贝（完全更新），或者是你最近取出了<code class="filename">/calc/trunk</code>的一个干净的工作拷贝。</p>
		<p>但是要哪两个树进行比较呢？乍一看，回答很明确，只要比较最新的主干与分支。但是你要意识到—这个想法是<span class="emphasis"><em>错误的</em></span>，伤害了许多新用户！因为<span><strong class="command">svn merge</strong></span>的操作很像<span><strong class="command">svn diff</strong></span>，比较最新的主干和分支树不仅仅会描述你在分支上所作的修改，这样的比较会展示太多的不同，不仅包括分支上的增加，也包括了主干上的删除操作，而这些删除根本就没有在分支上发生过。</p>
		<p>为了表示你的分支上的修改，你只需要比较分支的初始状态与最终状态，在你的分支上使用<span><strong class="command">svn log</strong></span>命令，你可以看到你的分支在341版本建立，你的分支最终的状态用<code class="literal">HEAD</code>版本表示，这意味着你希望能够比较版本341和<code class="literal">HEAD</code>的分支目录，然后应用这些分支的修改到主干目录的工作拷贝。</p>
		<div class="tip" style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
				<h3 class="title">提示</h3>
				<p>查找分支产生的版本（分支的“<span class="quote">基准</span>”）的最好方法是在<span><strong class="command">svn log</strong></span>中使用<code class="option">--stop-on-copy</code>选项，log子命令通常会显示所有关于分支的变化，包括 创建分支的过程，就好像你在主干上一样，<code class="option">--stop-on-copy</code>会在<span><strong class="command">svn log</strong></span>检测到目标拷贝或者改名时中止日志输出。</p>
				<p>所以，在我们的例子里，</p>
				<pre class="screen">$ svn log --verbose --stop-on-copy \
          http://svn.example.com/repos/calc/branches/my-calc-branch
…
------------------------------------------------------------------------
r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   A /calc/branches/my-calc-branch (from /calc/trunk:340)

$
</pre>
				<p>正如所料，最后的打印出的版本正是<code class="filename">my-calc-branch</code>生成的版本。 </p>
		</div>
		<p>如下是最终的合并过程，然后：</p>
		<pre class="screen">$ cd calc/trunk
$ svn update
At revision 405.

$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svn status
M   integer.c
M   button.c
M   Makefile

# ...examine the diffs, compile, test, etc...

$ svn commit -m "Merged my-calc-branch changes r341:405 into the trunk."
Sending        integer.c
Sending        button.c
Sending        Makefile
Transmitting file data ...
Committed revision 406.
</pre>
		<p>再次说明，日志信息中详细描述了合并到主干的的修改范围，记住一定要这么做，这是你以后需要的重要信息。</p>
		<p>举个例子，你希望在分支上继续工作一周，来进一步加强你的修正，这时版本库的<code class="literal">HEAD</code>版本是480，你准备好了另一次合并，但是我们在<a title="合并的最佳实践" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-4-sect-3.html#svn-ch-4-sect-3.3">“合并的最佳实践”一节</a>提到过，你不想合并已经合并的内容，你只想合并新的东西，技巧就是指出什么是“<span class="quote">新</span>”的。</p>
		<p>第一步是在主干上运行<span><strong class="command">svn log</strong></span>察看最后一次与分支合并的日志信息：</p>
		<pre class="screen">$ cd calc/trunk
$ svn log
…
------------------------------------------------------------------------
r406 | user | 2004-02-08 11:17:26 -0600 (Sun, 08 Feb 2004) | 1 line

Merged my-calc-branch changes r341:405 into the trunk.
------------------------------------------------------------------------
…
</pre>
		<p>阿哈！因为分支上341到405之间的所有修改已经在版本406合并了，现在你只需要合并分支在此之后的修改—通过比较406和<code class="literal">HEAD</code>。</p>
		<pre class="screen">$ cd calc/trunk
$ svn update
At revision 480.

# We notice that HEAD is currently 480, so we use it to do the merge:

$ svn merge -r 406:480 http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svn commit -m "Merged my-calc-branch changes r406:480 into the trunk."
Sending        integer.c
Sending        button.c
Sending        Makefile
Transmitting file data ...
Committed revision 481.
</pre>
		<p>现在主干有了分支上第二波修改的完全结果，此刻，你可以删除你的分支（我们会在以后讨论），或是继续在你分支上工作，重复这个步骤。</p>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-4-sect-4.2">
												</a>取消修改</h3>
								</div>
						</div>
				</div>
				<p>
						<span>
								<strong class="command">svn merge</strong>
						</span>另一个常用的做法是取消已经做得提交，假设你愉快的在<code class="filename">/calc/trunk</code>工作，你发现303版本对<code class="filename">integer.c</code>的修改完全错了，它不应该被提交，你可以使用<span><strong class="command">svn merge</strong></span>来“<span class="quote">取消</span>”这个工作拷贝上所作的操作，然后提交本地修改到版本库，你要做得只是指定一个相反的区别：</p>
				<pre class="screen">$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
U  integer.c

$ svn status
M  integer.c

$ svn diff
…
# verify that the change is removed
…

$ svn commit -m "Undoing change committed in r303."
Sending        integer.c
Transmitting file data .
Committed revision 350.
</pre>
				<p>我们可以把版本库修订版本想象成一组修改（一些版本控制系统叫做<em class="firstterm">修改集</em>），通过<code class="option">-r</code>选项，你可以告诉<span><strong class="command">svn merge</strong></span>来应用修改集或是一个修改集范围到你的工作拷贝，在我们的情况例子里，我们使用<span><strong class="command">svn merge</strong></span>合并修改集#303到工作拷贝。</p>
				<p>记住回滚修改和任何一个<span><strong class="command">svn merge</strong></span>命令都一样，所以你应该使用<span><strong class="command">svn status</strong></span>或是<span><strong class="command">svn diff</strong></span>来确定你的工作处于期望的状态中，然后使用<span><strong class="command">svn commit</strong></span>来提交，提交之后，这个特定修改集不会反映到<code class="literal">HEAD</code>版本了。</p>
				<p>继续，你也许会想：好吧，这不是真的取消提交吧！是吧？版本303还依然存在着修改，如果任何人取出<code class="filename">calc</code>的303-349版本，他还会得到错误的修改，对吧？</p>
				<p>是的，这是对的。当我们说“<span class="quote">删除</span>”一个修改时，我们只是说从<code class="literal">HEAD</code>删除，原始的修改还保存在版本库历史中，在多数情况下，这是足够好的。大多数人只是对追踪<code class="literal">HEAD</code>版本感兴趣，在一些特定情况下，你也许希望毁掉所有提交的证据（或许某个人提交了一个秘密文件），这不是很容易的，因为Subversion设计用来不丢失任何信息，每个修订版本都是不可变的目录树 ，从历史删除一个版本会导致多米诺效应，会在后面的版本导致混乱甚至会影响所有的工作拷贝。 <sup>[<a id="id456353" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-4-sect-4.html#ftn.id456353">9</a>]</sup></p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-4-sect-4.3">
												</a>找回删除的项目</h3>
								</div>
						</div>
				</div>
				<p>版本控制系统非常重要的一个特性就是它的信息从不丢失，即使当你删除了文件或目录，它也许从HEAD版本消失了 ，但这个对象依然存在于历史的早期版本 ，一个新手经常问到的问题是“<span class="quote">怎样找回我的文件和目录？</span>”</p>
				<p>第一步首先要知道需要拯救的项目是<span class="bold"><strong>什么</strong></span>，这里有个很有用的比喻：你可以认为任何存在于版本库的对象生活在一个二维的坐标系统里，第一维是一个特定的版本树，第二维是在树中的路径，所以你的文件或目录的任何版本可以有这样一对坐标定义。</p>
				<p>Subversion没有向CVS一样的<code class="filename">古典</code>目录， <sup>[<a id="id456429" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-4-sect-4.html#ftn.id456429">10</a>]</sup> 所以你需要<span><strong class="command">svn log</strong></span>来察看你需要找回的坐标对，一个好的策略是使用<span><strong class="command">svn log --verbose</strong></span>来察看你删除的项目，--verbose选项显示所有改变的项目的每一个版本 ，你只需要找出你删除文件或目录的那一个版本。你可以通过目测找出这个版本，也可以使用另一种工具来检查日志的输出 （通过<span><strong class="command">grep</strong></span>或是在编辑器里增量查找）。</p>
				<pre class="screen">$ cd parent-dir
$ svn log --verbose
…
------------------------------------------------------------------------
r808 | joe | 2003-12-26 14:29:40 -0600 (Fri, 26 Dec 2003) | 3 lines
Changed paths:
   D /calc/trunk/real.c
   M /calc/trunk/integer.c

Added fast fourier transform functions to integer.c.
Removed real.c because code now in double.c.
…
</pre>
				<p>在这个例子里，你可以假定你正在找已经删除了的文件<code class="filename">real.c</code>，通过查找父目录的历史 ，你知道这个文件在808版本被删除，所以存在这个对象的版本在此之前 。结论：你想从版本807找回<code class="filename">/calc/trunk/real.c</code>。</p>
				<p>以上是最重要的部分—重新找到你需要恢复的对象。现在你已经知道该恢复的文件，而你有两种选择。</p>
				<p>一种是对版本反向使用<span><strong class="command">svn merge</strong></span>到808（我们已经学会了如何取消修改，见<a title="取消修改" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-4-sect-4.html#svn-ch-4-sect-4.2">“取消修改”一节</a>），这样会重新添加<code class="filename">real.c</code>，这个文件会列入增加的计划，经过一次提交，这个文件重新回到<code class="literal">HEAD</code>。</p>
				<p>在这个例子里，这不是一个好的策略，这样做不仅把<code class="filename">real.c</code>加入添加到计划，也取消了对<code class="filename">integer.c</code>的修改，而这不是你期望的。确实，你可以恢复到版本808，然后对<code class="filename">integer.c</code>执行取消<span><strong class="command">svn revert</strong></span>操作，但这样的操作无法扩大使用，因为如果从版本808修改了90个文件怎么办？</p>
				<p>所以第二个方法不是使用<span><strong class="command">svn merge</strong></span>，而是使用<span><strong class="command">svn copy</strong></span>命令，精确的拷贝版本和路径“<span class="quote">坐标对</span>”到你的工作拷贝：</p>
				<pre class="screen">$ svn copy --revision 807 \
           http://svn.example.com/repos/calc/trunk/real.c ./real.c

$ svn status
A  +   real.c

$ svn commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
Adding         real.c
Transmitting file data .
Committed revision 1390.
</pre>
				<p>加号标志表明这个项目不仅仅是计划增加中，而且还包含了历史，Subversion记住了它是从哪个拷贝过来的。在将来，对这个文件运行<span><strong class="command">svn log</strong></span>会看到这个文件在版本807之前的历史，换句话说，<code class="filename">real.c</code>不是新的，而是原先删除的那一个的后代。</p>
				<p>尽管我们的例子告诉我们如何找回文件，对于恢复删除的目录也是一样的。</p>
		</div>
		<div class="sect2" lang="zh-cn" xml:lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h3 class="title">
												<a id="svn-ch-4-sect-4.4">
												</a>常用分支模式</h3>
								</div>
						</div>
				</div>
				<p>版本控制在软件开发中广泛使用，这里是团队里程序员最常用的两种分支/合并模式的介绍，如果你不是使用Subversion软件开发，可随意跳过本小节，如果你是第一次使用版本控制的软件开发者，请更加注意，以下模式被许多老兵当作最佳实践，这个过程并不只是针对Subversion，在任何版本控制系统中都一样，但是在这里使用Subversion术语会感觉更方便一点。</p>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-4-sect-4.4.1">
														</a>发布分支</h4>
										</div>
								</div>
						</div>
						<p>大多数软件存在这样一个生命周期：编码、测试、发布，然后重复。这样有两个问题，第一，开发者需要在质量保证小组测试假定稳定版本时继续开发新特性，新工作在软件测试时不可以中断，第二，小组必须一直支持老的发布版本和软件；如果一个bug在最新的代码中发现，它一定也存在已发布的版本中，客户希望立刻得到错误修正而不必等到新版本发布。</p>
						<p>这是版本控制可以做的帮助，典型的过程如下：</p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>
														<span class="emphasis">
																<em>开发者提交所有的新特性到主干。</em>
														</span> 每日的修改提交到<code class="filename">/trunk</code>：新特性，bug修正和其他。</p>
										</li>
										<li>
												<p>
														<span class="emphasis">
																<em>这个主干被拷贝到“<span class="quote">发布</span>”分支。</em>
														</span> 当小组认为软件已经做好发布的准备（如，版本1.0）然后<code class="filename">/trunk</code>会被拷贝到<code class="filename">/branches/1.0</code>。</p>
										</li>
										<li>
												<p>
														<span class="emphasis">
																<em>项目组继续并行工作，</em>
														</span>一个小组开始对分支进行严酷的测试，同时另一个小组在<code class="filename">/trunk</code>继续新的工作（如，准备2.0），如果一个bug在任何一个位置被发现，错误修正需要来回运送。然而这个过程有时候也会结束，例如分支已经为发布前的最终测试“<span class="quote">停滞</span>”了。</p>
										</li>
										<li>
												<p>
														<span class="emphasis">
																<em>分支已经作了标签并且发布，</em>
														</span>当测试结束，<code class="filename">/branches/1.0</code>作为引用快照已经拷贝到<code class="filename">/tags/1.0.0</code>，这个标签被打包发布给客户。</p>
										</li>
										<li>
												<p>
														<span class="emphasis">
																<em>分支多次维护。</em>
														</span>当继续在<code class="filename">/trunk</code>上为版本2.0工作，bug修正继续从<code class="filename">/trunk</code>运送到<code class="filename">/branches/1.0</code>，如果积累了足够的bug修正，管理部门决定发布1.0.1版本：拷贝<code class="filename">/branches/1.0</code>到<code class="filename">/tags/1.0.1</code>，标签被打包发布。</p>
										</li>
								</ul>
						</div>
						<p>整个过程随着软件的成熟不断重复：当2.0完成，一个新的2.0分支被创建，测试、打标签和最终发布，经过许多年，版本库结束了许多版本发布，进入了“<span class="quote">维护</span>”模式，许多标签代表了最终的发布版本。</p>
				</div>
				<div class="sect3" lang="zh-cn" xml:lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h4 class="title">
														<a id="svn-ch-4-sect-4.4.2">
														</a>特性分支</h4>
										</div>
								</div>
						</div>
						<p>一个<em class="firstterm">特性分支</em>是本章中那个重要例子中的分支，你正在那个分支上工作，而Sally还在<code class="filename">/trunk</code>继续工作，这是一个临时分支，用来作复杂的修改而不会干扰<code class="filename">/trunk</code>的稳定性，不象发布分支（也许要永远支持），特性分支出生，使用了一段时间，合并到主干，然后最终被删除掉，它们在有限的时间里有用。</p>
						<p>还有，关于是否创建特性分支的项目政策也变化广泛，一些项目永远不使用特性分支：大家都可以提交到<code class="filename">/trunk</code>，好处是系统的简单—没有人需要知道分支和合并，坏处是主干会经常不稳定或者不可用，另外一些项目使用分支达到极限：没有修改<span class="emphasis"><em>曾经</em></span>直接提交到主干，即使最细小的修改都要创建短暂的分支，然后小心的审核合并到主干，然后删除分支，这样系统保持主干一直稳定和可用，但是造成了巨大的负担。</p>
						<p>许多项目采用折中的方式，坚持每次编译<code class="filename">/trunk</code>并进行回归测试，只有需要多次不稳定提交时才需要一个特性分支，这个规则可以用这样一个问题检验：如果开发者在好几天里独立工作，一次提交大量修改（这样<code class="filename">/trunk</code>就不会不稳定。），是否会有太多的修改要来回顾？如果答案是“<span class="quote">是</span>”，这些修改应该在特性分支上进行，因为开发者增量的提交修改，你可以容易的回头检查。</p>
						<p>最终，有一个问题就是怎样保持一个特性分支“<span class="quote">同步</span>”于工作中的主干，在前面提到过，在一个分支上工作数周或几个月是很有风险的，主干的修改也许会持续涌入，因为这一点，两条线的开发会区别巨大，合并分支回到主干会成为一个噩梦。</p>
						<p>这种情况最好通过有规律的将主干合并到分支来避免，制定这样一个政策：每周将上周的修改合并到分支，注意这样做时需要小心，需要手工记录合并的过程，以避免重复的合并（在<a title="手工追踪合并" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-4-sect-3.html#svn-ch-4-sect-3.3.1">“手工追踪合并”一节</a>描述过），你需要小心的撰写合并的日志信息，精确的描述合并包括的范围（在<a title="合并一条分支到另一支" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-4-sect-4.html#svn-ch-4-sect-4.1">“合并一条分支到另一支”一节</a>中描述过），这看起来像是胁迫，可是实际上是容易做到的。</p>
						<p>在一些时候，你已经准备好了将“<span class="quote">同步的</span>”特性分支合并回到主干，为此，开始做一次将主干最新修改和分支的最终合并，这样以后，除了你的分支修改的部分，最新的分支和主干将会绝对一致，所以在这个特别的例子里，你会通过直接比较分支和主干来进行合并：</p>
						<pre class="screen">$ cd trunk-working-copy

$ svn update
At revision 1910.

$ svn merge http://svn.example.com/repos/calc/trunk@1910 \
            http://svn.example.com/repos/calc/branches/mybranch@1910
U  real.c
U  integer.c
A  newdirectory
A  newdirectory/newfile
…
</pre>
						<p>通过比较<code class="literal">HEAD</code>修订版本的主干和<code class="literal">HEAD</code>修订版本的分支，你确定了只在分支上的增量信息，两条开发线都有了分枝的修改。</p>
						<p>可以用另一种考虑这种模式，你每周按时同步分支到主干，类似于在工作拷贝执行<span><strong class="command">svn update</strong></span>的命令，最终的合并操作类似于在工作拷贝运行<span><strong class="command">svn commit</strong></span>，毕竟，工作拷贝不就是一个非常浅的分支吗？只是它一次只可以保存一个修改。</p>
				</div>
		</div><img src ="http://www.cnitblog.com/tilan/aggbug/21814.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-12 14:37 <a href="http://www.cnitblog.com/tilan/articles/21814.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Subversion__钩子脚本</title><link>http://www.cnitblog.com/tilan/articles/21813.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 12 Jan 2007 06:35:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21813.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21813.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21813.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21813.html</trackback:ping><description><![CDATA[<p>所谓<em class="firstterm">钩子</em>就是与一些版本库事件触发的程序，例如新修订版本的创建，或是未版本化属性的修改。每个钩子都会被告知足够多的信息，包括那是什么事件，所操作的对象，和触发事件的用户名。通过钩子的输出或返回状态，钩子程序能让工作继续、停止或是以某种方式挂起。</p>
		<p>
				<em class="firstterm">默认情况下，钩子的子目录中包含各种版本库钩子模板。</em>
		</p>
		<pre class="screen">$ ls repos/hooks/
post-commit.tmpl          pre-revprop-change.tmpl
post-revprop-change.tmpl  start-commit.tmpl
pre-commit.tmpl           
</pre>
		<p>对每种Subversion版本库支持的钩子的都有一个模板，通过查看这些脚本的内容，你能看到是什么事件触发了脚本及如何给传脚本传递数据。同时，这些模版也是如何使用这些脚本，结合Subversion支持的工具来完成有用任务的例子。要实际安装一个可用的钩子，你需要在<code class="filename">repos/hooks</code>目录下安装一些与钩子同名（如 <span><strong class="command">start-commit</strong></span>或者<span><strong class="command">post-commit</strong></span>）的可执行程序或脚本。</p>
		<p>在Unix平台上，这意味着要提供一个与钩子同名的脚本或程序（可能是shell 脚本，Python 程序，编译过的c语言二进制文件或其他东西）。当然，脚本模板文件不仅仅是展示了一些信息—在Unix下安装钩子最简单的办法就是拷贝这些模板，并且去掉.tmpl扩展名，然后自定义钩子的内容，确定脚本是可运行的。Windows用文件的扩展名来决定一个程序是否可运行，所以你要使程序的基本名与钩子同名，同时，它的扩展名是Windows系统所能辨认的，例如<code class="filename">exe</code>、<code class="filename">com</code>和批处理的<code class="filename">bat</code>。</p>
		<div class="tip" style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
				<h3 class="title">提示</h3>
				<p>由于安全原因，Subversion版本库在一个空环境中执行钩子脚本—就是没有任何环境变量，甚至没有<code class="literal">$PATH</code>或<code class="literal">%PATH%</code>。由于这个原因，许多管理员会感到很困惑，它们的钩子脚本手工运行时正常，可在Subversion中却不能运行。要注意，必须在你的钩子中设置好环境变量或为你的程序指定好绝对路径。</p>
		</div>
		<p>目前Subversion有已实现了五种钩子：</p>
		<div class="variablelist">
				<dl>
						<dt>
								<span class="term">
										<code class="filename">start-commit</code>
								</span>
						</dt>
						<dd>
								<p>它在提交事务产生前已运行，通常用来判定一个用户是否有权提交。版本库传给该程序两个参数：到版本库的路径，和要进行提交的用户名。如果程序返回一个非零值，会在事务产生前停止该提交操作。如果钩子程序要在stderr中写入数据，它将排队送至客户端。</p>
						</dd>
						<dt>
								<span class="term">
										<code class="filename">pre-commit</code>
								</span>
						</dt>
						<dd>
								<p>在事务完成提交之前运行，通常这个钩子是用来保护因为内容或位置（例如，你要求所有到一个特定分支的提交必须包括一个bug追踪的ticket号，或者是要求日志信息不为空）而不允许的提交。版本库传递两个参数到程序：版本库的路径和正在提交的事务名称，如果程序返回非零值，提交会失败，事务也会删除。如果钩子程序在stderr中写入了数据，也会传递到客户端。</p>
								<p>Subversion的分发版本包括了一些访问控制脚本（在Subversion源文件目录树的<code class="filename">tools/hook-scripts</code>目录），可以用来被<span><strong class="command">pre-commit</strong></span>调用来实现精密的写访问控制。另一个选择是使用Apache的httpd模块<span><strong class="command">mod_authz_svn</strong></span>，可以对单个目录进行读写访问控制（见<a title="每目录访问控制" href="http://www.iusesvn.com/subversion/svnbook/1.1/svn-ch-6-sect-4.html#svn-ch-6-sect-4.4.2">“每目录访问控制”一节</a>）。在未来的Subversion版本中,我们计划直接在文件系统中实现访问控制列表（ACLs）。</p>
						</dd>
						<dt>
								<span class="term">
										<code class="filename">post-commit</code>
								</span>
						</dt>
						<dd>
								<p>它在事务完成后运行，创建一个新的修订版本。大多数人用这个钩子来发送关于提交的描述性电子邮件，或者作为版本库的备份。版本库传给程序两个参数：到版本库的路径和被创建的新的修订版本号。退出程序会被忽略。</p>
								<p>Subversion分发版本中包括<span><strong class="command">mailer.py</strong></span>和<span><strong class="command">commit-email.pl</strong></span>脚本（存于Subversion源代码树中的<code class="filename">tools/hook-scripts/</code>目录中）可以用来发送描述给定提交的email（并且或只是追加到一个日志文件），这个mail包含变化的路径清单，提交的日志信息、日期和作者以及修改文件的GNU区别样式输出。</p>
								<p>Subversion提供的另一个有用的工具是<span><strong class="command">hot-backup.py</strong></span>脚本（在Subversion源代码树中的tools/backup/目录中）。这个脚本可以为Subversion版本库进行热备份（Berkeley DB数据库后端支持的一种特性），可以制作版本库每次提交的快照作为归档和紧急情况的备份。</p>
						</dd>
						<dt>
								<span class="term">
										<code class="filename">pre-revprop-change</code>
								</span>
						</dt>
						<dd>
								<p>因为Subversion的修订版本属性不是版本化的，对这类属性的修改（例如提交日志属性<code class="literal">svn:log</code>）将会永久覆盖以前的属性值。因为数据在此可能丢失，所以Subversion提供了这种钩子（及与之对应的<code class="filename">post-revprop-change</code>），因此版本库管理员可用一些外部方法记录变化。作为对丢失未版本化属性数据的防范，Subversion客户端不能远程修改修订版本属性，除非为你的版本库实现这个钩子。</p>
								<p>这个钩子在对版本库进行这种修改时才会运行，版本库给钩子传递四个参数：到版本库的路径，要修改属性的修订版本，经过认证的用户名和属性自身的名字。</p>
						</dd>
						<dt>
								<span class="term">
										<code class="filename">post-revprop-change</code>
								</span>
						</dt>
						<dd>
								<p>我们在前面提到过，这个钩子与<code class="filename">pre-revprop-change</code>对应。事实上，因为多疑的原因，只有存在<code class="filename">pre-revprop-change</code>时这个脚本才会执行。当这两个钩子都存在时，<code class="filename">post-revprop-change</code>在修订版本属性被改变之后运行，通常用来发送包含新属性的email。版本库传递四个参数给该钩子：到版本库的路径，属性存在的修订版本，经过校验的产生变化的用户名，和属性自身的名字。</p>
								<p>Subversion分发版本中包含<span><strong class="command">propchange-email.pl</strong></span>脚本（在Subversion源代码树中的<code class="filename">tools/hook-scripts/</code>目录中），可以用来发送修订版本属性修改细节的email（并且或只是追加到一个日志文件）。这个email包含修订版本和发生变化的属性名，作出修改的用户和新属性值。 </p>
						</dd>
				</dl>
		</div>
		<div class="warning" style="MARGIN-LEFT: 0.5in; MARGIN-RIGHT: 0.5in">
				<h3 class="title">
						<font color="#ff3333">警告</font>
				</h3>
				<p>
						<font color="#ff3333">
						</font>
				</p>
				<p>
						<font color="#ff3333">不要尝试用钩子脚本修改事务。一个常见的例子就是在提交时自动设置<code class="literal">svn:eol-style</code>或<code class="literal">svn:mime-type</code>这类属性。这看起来是个好主意，但它会引起问题。主要的问题是客户并不知道由钩子脚本进行的修改，同时没有办法通告客户它的数据是过时的，这种矛盾会导致出人意料和不能预测的行为。</font>
				</p>
				<p>
						<font color="#ff3333">作为尝试修改事务的替代，我们通过检查<code class="filename">pre-commit</code>钩子的事务，在不满足要求时拒绝提交。</font>
				</p>
		</div>
		<p>Subversion会试图以当前访问版本库的用户身份执行钩子。通常，对版本库的访问总是通过Apache HTTP服务器和mod_dav_svn进行，因此，执行钩子的用户就是运行Apache的用户。钩子本身需要具有操作系统级的访问许可，用户可以运行它。另外，其它被钩子直接或间接使用的文件或程序（包括Subversion版本库本身）也要被同一个用户访问。换句话说，要注意潜在的访问控制问题，它可能会让你的钩子无法按照你的目的顺利执行。</p><img src ="http://www.cnitblog.com/tilan/aggbug/21813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-12 14:35 <a href="http://www.cnitblog.com/tilan/articles/21813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux为例安装cvs</title><link>http://www.cnitblog.com/tilan/articles/21484.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Thu, 04 Jan 2007 03:03:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21484.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21484.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21484.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21484.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21484.html</trackback:ping><description><![CDATA[<p>一、CVS服务器的安装</p>
		<p>首先确认系统中是否安装CVS服务：<br />[root@localhost /]# rpm -qa|grep cvs<br />cvs-1.11.2-cvshome.7x.1<br />如果命令输出类似于上面的输出则说明系统已经安装有cvs，否则就需要从安装光盘中安装cvs的rpm包，或者到<a href="http://www.cvshome.org/">http://www.cvshome.org</a>下载。</p>
		<p>1、建立 CVSROOT </p>
		<p>目录，因为这里涉及到用户对CVSROOT里的文件读写的权限问题，所以比较简单的方法是建立一个组，然后再建立一个属于该组的帐户，而且以后有读写权限的用户都要属于该组。假设我们建一个组叫cvs，用户名是cvsroot。建组和用户的命令如下</p>
		<p>#groupadd cvs <br />#useradd -g cvs -G cvs -d /home/cvsroot cvsroot</p>
		<p>生成的用户宿主目录在/home/cvsroot（根据自己的系统调整）</p>
		<p>2、建立CVS仓库，用cvsroot 用户登陆，用下面命令：</p>
		<p>$cvs -d /home/cvsroot init</p>
		<p>3、仍然是 cvsroot 用户，修改 /home/cvsroot （CVSROOT）的权限，赋与同组人有读写的权限：　 </p>
		<p>$chmod 775 -R /home/cvsroot</p>
		<p>4、用root登录，加入cvs服务(我的redhath7.3缺省就有cvs服务,所以不用加)</p>
		<p>vi /etc/services<br />cvspserver 2401/tcp #pserver cvs service<br />cvspserver 2401/udp #pserver cvs service </p>
		<p>cvs服务由inted来唤起,因此需要改动inetd提供的服务,如果你的redhat使用的是inetd 方式则在文件/etc/inetd.conf中加入如下的内容:cvspserver stream tcp nowait root /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver</p>
		<p>我的redhat7.3使用的是xinetd方式,所以在xinetd.d目录下添加需要启动的服务:<br />cd /etc/xinetd.d<br />vi cvspserver<br />文件内容:<br />service cvspserver<br />{<br />  disable = no<br />  flags = REUSE<br />  socket_type = stream<br />  wait = no<br />  user = cvsroot<br />  server = /usr/bin/cvs<br />  server_args = -f --allow-root=/home/cvsroot pserver<br />  log_on_failure += USERID<br />}</p>
		<p>重新启动inetd或者xinetd:<br /> /etc/rc.d/init.d/xinetd restart</p>
		<p>检查cvspserver服务是否已经启动<br />[root@localhost /]# netstat -lnp|grep 2401<br />tcp        0      0 0.0.0.0:2401            0.0.0.0:*               LISTEN      1041/xinetd  <br />则说明cvs服务器已经运行。</p>
		<p>二、管理CVS服务器</p>
		<p>服务器可以用了，现在大家最关心的就是如何管理服务器，比如，我想让一些人有读和/或写 CVS 仓库的权限，但是不想给它系统权限怎么办呢？</p>
		<p>不难，在 cvs 管理员用户（在我这里是 cvsroot 用户）的家目录里有一个 CVSROOT 目录，这个目录里有三个配置文件，passwd, readers, writers，我们可以通过设置这三个文件来配置 CVS 服务器，下面分别介绍这几个文件的作用： </p>
		<p>passwd：cvs 用户的用户列表文件，它的格式很象 shadow 文件： </p>
		<p>{cvs 用户名}:[加密的口令]:[等效系统用户名] </p>
		<p>readers：有 cvs 读权限的用户列表文件。就是一个一维列表。在这个文件中的用户对 cvs只有读权限。 </p>
		<p>writers：有 cvs 写权限的用户的列表文件。和 readers 一样，是一个一维列表。在这个文件中的用户对 cvs 有写权限。 </p>
		<p>上面三个文件在缺省安装的时候可能都不存在，需要我们自己创建，好吧，现在还是让我们用一个例子来教学吧。假设我们有下面几个用户需要使用 cvs： </p>
		<p>laser, gumpwu, henry, betty, anonymous。 </p>
		<p>其中 laser 和 gumpwu 是系统用户，而 henry, betty, anonymous 我们都不想给系统用户权限，并且 betty 和 anonymous 都是只读用户，而且 anonymous 更是连口令都没有。</p>
		<p>然后编辑 cvs 管理员家目录里 CVSROOT/passwd 文件（cvsroot用户），加入下面几行： </p>
		<p>laser:$xxefajfka;faffa33:cvsroot<br />gumpwu:$ajfaal;323r0ofeeanv:cvsroot <br />henry:$fajkdpaieje:cvsroot<br />betty:fjkal;ffjieinfn/:cvsroot <br />anonymous::cvsroot</p>
		<p>注意：上面的第二个字段（分隔符为 :）是密文口令。 </p>
		<p>密码可以有以下方法生成<br />vi /home/cvsroot/passwdgen.pl<br />文件内容:<br />#!/usr/bin/perl<br />srand (time());<br />my $randletter = "(int (rand (26)) + (int (rand (1) + .5) % 2 ? 65 : 97))";<br />my $salt = sprintf ("%c%c", eval $randletter, eval $randletter);<br />my $plaintext = shift;<br />my $crypttext = crypt ($plaintext, $salt);<br />print "${crypttext}\n";</p>
		<p>如果需要密码为:some,则敲入:<br />./passwdgen.pl some<br />（注意passwdgen.pl要先设为可执行）<br />回车即可得到加密密码,用其替换passwd文件中的passwd部分就可以了</p>
		<p>
				<br />编辑 readers 文件，加入下面几行： <br />anonymous <br />betty </p>
		<p>编辑 writers 文件，加入下面几行： </p>
		<p>laser <br />gumpwu <br />henry </p>
		<p>注意：writers中的用户不能在readers中，要不然不能上传更新文件。</p>
		<p>
				<br />对于使用CVS的用户要修改它的环境变量，例如laser用户的环境变量，打开/home/laser（laser的宿主目录）下的.bash_profile文件，加入</p>
		<p>CVSROOT=/home/cvsroot<br />export CVSROOT</p>
		<p>用laser登陆就可以建立CVS项目，如果要root使用，可以修改/etc/profile文件。</p>
		<p>
				<br />现在我们各项都设置好了，那么怎么用呢，我在这里写一个最简单的（估计也是最常用的）命令介绍： </p>
		<p>首先，建立一个新的CVS项目，一般我们都已经有一些项目文件了，这样我们可以用下面步骤生成一个新的CVS项目： </p>
		<p>进入到你的已有项目的目录，比如叫 cvstest： </p>
		<p>$cd  cvstest<br />运行命令： <br />$cvs import -m "this is a cvstest project" cvstest     v_0_0_1     start </p>
		<p>说明：import 是cvs的命令之一，表示向cvs仓库输入项目文件。 -m参数后面的字串是描述文本，随便写些有意义的东西，如果不加 -m 参数，那么cvs会自动运行一个编辑器（一般是vi，但是可以通过修改环境变量EDITOR来改成你喜欢用的编辑器。）让你输入信息，cvstest 是项目名称（实际上是仓库名，在CVS服务器上会存储在以这个名字命名的仓库里。） <br />v_0_0_1是这个分支的总标记。没啥用（或曰不常用。） <br />start 是每次 import 标识文件的输入层次的标记，没啥用。<br />这样我们就建立了一个CVS仓库了。</p>
		<p>　　建立CVS仓库的文件夹应该是“干净”的文件夹，即只包括源码文件和描述的文件加，而不应该包括编译过的文件代码等！</p><img src ="http://www.cnitblog.com/tilan/aggbug/21484.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-04 11:03 <a href="http://www.cnitblog.com/tilan/articles/21484.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CVS使用手册</title><link>http://www.cnitblog.com/tilan/articles/21483.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Thu, 04 Jan 2007 03:02:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21483.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21483.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21483.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21483.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21483.html</trackback:ping><description><![CDATA[<p>关键词：CVS CVSWeb CVSTrac WinCVS CVSROOT </p>
		<p>内容摘要： </p>
		<p>CVS是一个C/S系统，多个开发人员通过一个中心版本控制系统来记录文件版本，从而达到保证文件同步的目的。工作模式如下： </p>
		<pre>       CVS服务器（文件版本库）<br />     /     |       \<br />     （版 本 同 步）<br />   /       |         \<br />开发者1  开发者2   开发者3<br /></pre>
		<p>作为一般开发人员挑选2,6看就可以了，CVS的管理员则更需要懂的更多一些，最后还简单介绍了一些Windows下的cvs客户端使用，CVS远程用户认证的选择及与BUG跟踪系统等开发环境的集成问题。</p>
		<ol>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#init">CVS环境初始化</a>：CVS环境的搭建 管理员 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#daily">CVS的日常使用</a>：日常开发中最常用的CVS命令， 开发人员 管理员 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#branch">CVS的分支开发</a>：项目按照不同进度和目标并发进行 管理员 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#ssh">CVS的用户认证</a>：通过SSH的远程用户认证，安全，简单 管理员 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#cvsweb">CVSWEB</a>：CVS的WEB访问界面大大提高代码版本比较的效率 管理员 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#tag">CVS TAG</a>：将$<span style="FONT-WEIGHT: bold">Id</span>$ 加入代码注释中，方便开发过程的跟踪开发人员 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#vss">CVS vs VSS</a>: CVS和Virsual SourceSafe的比较 开发人员 管理员 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#wincvs">WinCVS:</a> 通过SSH认证的WinCVS认证设置 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#cvstrac">基于CVSTrac的小组开发环境搭建</a>：通过CVSTrac实现web界面的CVS用户管理,集成的BUG跟踪和WIKI交流 
</li>
				<li>
						<a href="http://www.chedong.com/tech/cvs_card.html#auth">CVS中的用户权限管理</a>：基于系统用户的CVS权限管理和基于CVSROOT/passwd的虚拟用户管理<br /></li>
		</ol>
		<p>一个系统20%的功能往往能够满足80%的需求，CVS也不例外，以下是CVS最常用的功能，可能还不到它全部命令选项的20%，作为一般开发人员平时会用cvs update和cvs commit就够了，更多的需求在实际应用过程中自然会出现，不时回头看看相关文档经常有意外的收获。</p>
		<p>
				<br />
		</p>
		<h2>
				<a name="init">CVS环境初始化</a>
		</h2>环境设置：指定CVS库的路径CVSROOT 
<p>tcsh<br />setenv CVSROOT /path/to/cvsroot<br />bash<br />CVSROOT=/path/to/cvsroot ; export CVSROOT</p><p>后面还提到远程CVS服务器的设置：<br />CVSROOT=:ext:$USER@test.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH<br /><br />初始化：CVS版本库的初始化。<br />cvs init</p><p>一个项目的首次导入<br />cvs import -m "write some comments here" project_name vendor_tag release_tag<br />执行后：会将所有源文件及目录导入到/path/to/cvsroot/project_name目录下<br /><i>vender_tag: 开发商标记<br />release_tag: 版本发布标记</i></p><p>项目导出：将代码从CVS库里导出<br />cvs checkout project_name<br /><i>cvs 将创建project_name目录，并将最新版本的源代码导出到相应目录中。这个checkout和Virvual SourceSafe中的check out不是一个概念，相对于Virvual SourceSafe的check out是cvs update， check in是cvs commit。</i><br /><br /></p><h2><a style="FONT-WEIGHT: normal" name="daily">CVS的日常使用</a><b></b></h2><p></p><p><b>注意：第一次导出以后，就不是通过cvs checkout来同步文件了，而是要进入刚才cvs checkout project_name导出的project_name目录下进行具体文件的版本同步（添加，修改，删除）操作。</b></p><p><u>将文件同步到最新的版本<br /></u>cvs update<br /><i>不制定文件名，cvs将同步所有子目录下的文件，也可以制定某个文件名/目录进行同步<br /></i>cvs update file_name<br /><i>最好每天开始工作前或将自己的工作导入到CVS库里前都要做一次，并养成“先同步 后修改”的习惯，和Virvual SourceSafe不同，CVS里没有文件锁定的概念，所有的冲突是在commit之前解决，如果你修改过程中，有其他人修改并commit到了CVS 库中，CVS会通知你文件冲突，并自动将冲突部分用<br />&gt;&gt;&gt;&gt;&gt;&gt;<br />content on cvs server<br />&lt;&lt;&lt;&lt;&lt;&lt;<br />content in your file<br />&gt;&gt;&gt;&gt;&gt;&gt;<br />标记出来，由你确认冲突内容的取舍。<br />版本冲突一般是在多个人修改一个文件造成的，但这种项目管理上的问题不应该指望由CVS来解决。</i></p><p><u>确认修改写入到CVS库里</u><br />cvs commit -m "write some comments here" file_name</p><p><i>注意：CVS的很多动作都是通过cvs commit进行最后确认并修改的，最好每次只修改一个文件。在确认的前，还需要用户填写修改注释，以帮助其他开发人员了解修改的原因。如果不用写-m "comments"而直接确认`cvs commit file_name` 的话，cvs会自动调用系统缺省的文字编辑器(一般是vi)要求你写入注释。<br />注释的质量很重要：所以不仅必须要写，而且必须写一些比较有意义的内容：以方便其他开发人员能够很好的理解<br />不好的注释，很难让其他的开发人员快速的理解：比如： -m "bug fixed" 甚至 -m ""<br />好的注释，甚至可以用中文: -m "在用户注册过程中加入了Email地址校验"</i><br /><br />修改某个版本注释：每次只确认一个文件到CVS库里是一个很好的习惯，但难免有时候忘了指定文件名，把多个文件以同样注释commit到CVS库里了，以下命令可以允许你修改某个文件某个版本的注释：<br />cvs admin -m 1.3:"write some comments here" file_name<br /><br /><u>添加文件</u><br />创建好新文件后，比如：touch new_file<br />cvs add new_file<br /><i>注意：对于图片，Word文档等非纯文本的项目，需要使用cvs add -kb选项按2进制文件方式导入(k表示扩展选项，b表示binary)，否则有可能出现文件被破坏的情况<br />比如：<br />cvs add -kb new_file.gif<br />cvs add -kb readme.doc</i></p><p><i>如果关键词替换属性在首次导入时设置错了怎么办？<br /></i>cvs admin -kkv new_file.css <br /><i><br /></i><span style="TEXT-DECORATION: underline">然后确认修改并注释</span><br />cvs ci -m "write some comments here"</p><p><u>删除文件</u><br />将某个源文件物理删除后，比如：rm file_name<br />cvs rm file_name<br />然后确认修改并注释<br />cvs ci -m "write some comments here"<br />以上面前2步合并的方法为：<br />cvs rm -f file_name<br />cvs ci -m "why delete file"<br /><i>注意：很多cvs命令都有缩写形式：commit=&gt;ci; update=&gt;up; checkout=&gt;co/get; remove=&gt;rm;</i></p><p><u>添加目录</u><br />cvs add dir_name<br /><br /><u>查看修改历史</u><br />cvs log file_name<br />cvs history file_name<br /><br /><u>查看当前文件不同版本的区别</u><br />cvs diff -r1.3 -r1.5 file_name<br />查看当前文件（可能已经修改了）和库中相应文件的区别<br />cvs diff file_name<br />cvs的web界面提供了更方便的定位文件修改和比较版本区别的方法，具体安装设置请看后面的cvsweb使用</p><p><u>正确的通过CVS恢复旧版本的方法</u>：<br />如果用cvs update -r1.2 file.name<br />这个命令是给file.name加一个STICK TAG： "1.2" ，虽然你的本意只是想将它恢复到1.2版本<br />正确的恢复版本的方法是：cvs update -p -r1.2 file_name &gt;file_name<br />如果不小心已经加成STICK TAG的话：用cvs update -A 解决</p><p><u>移动文件/文件重命名</u><br />cvs里没有cvs move或cvs rename，因为这两个操作是可以由先cvs remove old_file_name，然后cvs add new_file_name实现的。</p><p><u>删除/移动目录</u><br />最方便的方法是让管理员直接移动，删除CVSROOT里相应目录（因为CVS一个项目下的子目录都是独立的，移动到$CVSROOT目录下都可以作为新的独立项目：好比一颗树，其实砍下任意一枝都能独立存活），对目录进行了修改后，要求其开发人员重新导出项目cvs checkout project_name 或者用cvs update -dP同步。</p><p><u>项目发布导出不带CVS目录的源文件</u><br />做开发的时候你可能注意到了，每个开发目录下，CVS都创建了一个CVS/目录。里面有文件用于记录当前目录和CVS库之间的对应信息。但项目发布的时候你一般不希望把文件目录还带着含有CVS信息的CVS目录吧，这个一次性的导出过程使用cvs export命令，不过export只能针对一个TAG或者日期导出，比如：<br />cvs export -r release1 project_name <br />cvs export -D 20021023 project_name<br />cvs export -D now project_name</p><h2><a name="branch">CVS Branch：项目多分支同步开发</a></h2>确认版本里程碑：多个文件各自版本号不一样，项目到一定阶段，可以给所有文件统一指定一个阶段里程碑版本号，方便以后按照这个阶段里程碑版本号导出项目，同时也是项目的多个分支开发的基础。<br /><p>cvs tag release_1_0</p><p><u>开始一个新的里程碑</u>：<br />cvs commit -r 2 标记所有文件开始进入2.x的开发</p><p><i>注意：CVS里的revsion和软件包的发布版本可以没有直接的关系。但所有文件使用和发布版本一致的版本号比较有助于维护。</i></p><p><u>版本分支的建立</u><br />在开发项目的2.x版本的时候发现1.x有问题，但2.x又不敢用，则从先前标记的里程碑：release_1_0导出一个分支 release_1_0_patch<br />cvs rtag -b -r release_1_0 release_1_0_patch proj_dir</p><p>一些人先在另外一个目录下导出release_1_0_patch这个分支：解决1.0中的紧急问题，<br />cvs checkout -r release_1_0_patch<br />而其他人员仍旧在项目的主干分支2.x上开发</p><p>在release_1_0_patch上修正错误后，标记一个1.0的错误修正版本号<br />cvs tag release_1_0_patch_1</p><p>如果2.0认为这些错误修改在2.0里也需要，也可以在2.0的开发目录下合并release_1_0_patch_1中的修改到当前代码中：<br />cvs update -j release_1_0_patch_1</p><h2><a name="ssh">CVS的远程认证通过SSH远程访问CVS</a></h2>使用cvs本身基于pserver的远程认证很麻烦,需要定义服务器和用户组，用户名，设置密码等，<br /><p>常见的登陆格式如下：<br />cvs -d :pserver:cvs_user_name@cvs.server.address:/path/to/cvsroot login<br />例子：<br />cvs -d :pserver:cvs@samba.org:/cvsroot login</p><p>不是很安全，因此一般是作为匿名只读CVS访问的方式。从安全考虑，通过系统本地帐号认证并通过SSH传输是比较好的办法，通过在客户机的 /etc/profile里设置一下内容：<br />CVSROOT=:ext:$USER@cvs.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH<br />所有客户机所有本地用户都可以映射到CVS服务器相应同名帐号了。</p><p>比如:</p><p>CVS服务器是192.168.0.3，上面CVSROOT路径是/home/cvsroot，另外一台开发客户机是192.168.0.4，如果 tom在2台机器上都有同名的帐号，那么从192.168.0.4上设置了：<br />export CVSROOT=:ext:tom@192.168.0.3:/home/cvsroot<br />export CVS_RSH=ssh<br />tom就可以直接在192.168.0.4上对192.168.0.3的cvsroot进行访问了（如果有权限的话）<br />cvs checkout project_name<br />cd project_name<br />cvs update<br />...<br />cvs commit <br /></p><p>如果CVS所在服务器的SSH端口不在缺省的22，或者和客户端与CVS服务器端SSH缺省端口不一致，有时候设置了：<br />:ext:$USER@test.server.address#port:/path/to/cvsroot <br /><br />仍然不行，比如有以下错误信息：<br />ssh: test.server.address#port: Name or service not known<br />cvs [checkout aborted]: end of file from server (consult above messages if any)<br /><br />解决的方法是做一个脚本指定端口转向（不能使用alias，会出找不到文件错误）：<br />创建一个/usr/bin/ssh_cvs文件，假设远程服务器的SSH端口是非缺省端口：34567<br />#!/bin/sh<br />/usr/bin/ssh -p 34567 "$@"<br />然后：chmod +x /usr/bin/ssh_cvs<br />并CVS_RSH=ssh_cvs; export CVS_RSH</p><p>注意：port是指相应服务器SSH的端口，不是指cvs专用的pserver的端口<br /><br /></p><h2><a name="cvsweb">CVSWEB：提高文件浏览效率</a></h2>CVSWEB就是CVS的WEB界面，可以大大提高程序员定位修改的效率:<br /><p>使用的样例可以看：<a href="http://www.freebsd.org/cgi/cvsweb.cgi">http://www.freebsd.org/cgi/cvsweb.cgi</a></p><p>CVSWEB的下载：CVSWEB从最初的版本已经演化出很多功能界面更丰富的版本，这个是我个人感觉安装设置比较方便的：<br />原先在：<s>http://www.spaghetti-code.de/software/linux/cvsweb/</s>，但目前已经删除，<a href="http://www.chedong.com/tech/cvsweb.tgz">目前仍可以在本站下载CVSWEB</a>，其实最近2年<a href="http://www.freebsd.org/projects/cvsweb.html">FreeBSD的CVSWeb项目</a>已经有了更好的发展吧，而当初没有用FreeBSD那个版本主要就是因为没有彩色的文件Diff功能。 <br />下载解包：<br />tar zxf cvsweb.tgz<br />把配置文件cvsweb.conf放到安全的地方（比如和apache的配置放在同一个目录下），<br />修改：cvsweb.cgi让CGI找到配置文件：<br />$config = $ENV{'CVSWEB_CONFIG'} || '/path/to/apache/conf/cvsweb.conf';<br /><br />转到/path/to/apache/conf下并修改cvsweb.conf：</p><ol><li>修改CVSROOT路径设置：<br />%CVSROOT = (<br />'Development' =&gt; '/path/to/cvsroot', #&lt;==修改指向本地的CVSROOT<br />); 
</li><li>缺省不显示已经删除的文档：<br />"hideattic" =&gt; "1",#&lt;==缺省不显示已经删除的文档 
</li><li>在配置文件cvsweb.conf中还可以定制页头的描述信息，你可以修改$long_intro成你需要的文字 </li></ol><p>CVSWEB可不能随便开放给所有用户，因此需要使用WEB用户认证：<br />先生成 passwd:<br />/path/to/apache/bin/htpasswd -c cvsweb.passwd user<br /><br />修改httpd.conf: 增加<br />&lt;Directory "/path/to/apache/cgi-bin/cvsweb/"&gt;<br />AuthName "CVS Authorization"<br />AuthType Basic<br />AuthUserFile /path/to/cvsweb.passwd<br />require valid-user<br />&lt;/Directory&gt;<br /><br /></p><h2><a name="tag">CVS TAGS: $Id: cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $</a></h2>将$Id: cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $ 加在程序文件开头的注释里是一个很好的习惯，cvs能够自动解释更新其中的内容成：file_name version time user_name 的格式，比如：cvs_card.txt,v 1.1 2002/04/05 04:24:12 chedong Exp，可以这些信息了解文件的最后修改人和修改时间<br /><p><br /></p><pre>几个常用的缺省文件：<br />default.php<br />&lt;?php<br />/*<br /> * Copyright (c) 2002 Company Name.<br /> * $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $<br /> */<br /><br />?&gt;<br />====================================<br />Default.java: 注意文件头一般注释用 /* 开始 JAVADOC注释用 /** 开始的区别<br />/*<br /> * Copyright (c) 2002 MyCompany Name.<br /> * $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $<br /> */<br /><br />package com.mycompany;<br /><br />import java.;<br /><br />/**<br /> * comments here<br /> */<br />public class Default {<br />    /**<br />     * Comments here<br />     * @param<br />     * @return<br />     */<br />    public toString() {<br /><br />    }<br />}<br />====================================<br />default.pl:<br />#!/usr/bin/perl -w<br /># Copyright (c) 2002 Company Name.<br /># $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $<br /><br /># file comments here<br /><br />use strict;<br /><br /></pre><h2><a name="vss">CVS vs VSS</a></h2><p>CVS没有文件锁定模式，VSS在check out同时，同时记录了文件被导出者锁定。 </p><p>CVS的update和commit， VSS是get_lastest_version和check in </p><p>对应VSS的check out/undo check out的CVS里是edit和unedit </p><p>在CVS中，标记自动更新功能缺省是打开的，这样也带来一个潜在的问题，就是不用-kb方式添加binary文件的话在cvs自动更新时可能会导致文件失效。</p><p>$Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $ $Date: 2003/11/09 07:57:11 $这样的标记在Virsual SourceSafe中称之为Keyword Explaination，缺省是关闭的，需要通过OPITION打开，并指定需要进行源文件关键词扫描的文件类型：*.txt,*.java, *.html...</p><p>对于Virsual SourceSafe和CVS都通用的TAG有：<br />$Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $<br />$Author: chedong $<br />$Date: 2003/11/09 07:57:11 $ <br />$Revision: 1.9 $ </p><p>我建议尽量使用通用的关键词保证代码在CVS和VSS都能方便的跟踪。 </p><h2><a name="wincvs">WinCVS</a></h2>下载：<br /><p>cvs Windows客户端：目前稳定版本为1.2<br /><a href="http://cvsgui.sourceforge.net/">http://cvsgui.sourceforge.net</a><br />ssh Windows客户端<br /><a href="http://www.networksimplicity.com/openssh/">http://www.networksimplicity.com/openssh/</a><br /><br />安装好以上2个软件以后：<br />WinCVS客户端的admin==&gt;preference设置<br />1 在general选单里<br />设置CVSROOT： username@192.168.0.123:/home/cvsroot<br />设置Authorization: 选择SSH server<br /><br />2 Port选单里<br />钩上：check for alternate rsh name<br />并设置ssh.exe的路径，缺省是装在 C:\Program Files\NetworkSimplicity\ssh\ssh.exe </p><p>然后就可以使用WinCVS进行cvs操作了，所有操作都会跳出命令行窗口要求你输入服务器端的认证密码。 </p><p>当然，如果你觉得这样很烦的话，还有一个办法就是生成一个没有密码的公钥/私钥对，并设置CVS使用基于公钥/私钥的SSH认证（在general 选单里）。</p><p>可以选择的diff工具：examdiff<br />下载：<br /><a href="http://www.prestosoft.com/examdiff/examdiff.htm">http://www.prestosoft.com/examdiff/examdiff.htm</a><br />还是在WinCVS菜单admin==&gt;preference的WinCVS选单里<br />选上：Externel diff program<br />并设置diff工具的路径，比如：C:\Program Files\ed16i\ExamDiff.exe<br />在对文件进行版本diff时，第一次需要将窗口右下角的use externel diff选上。 </p><h2><a name="cvstrac">基于CVSTrac的小组开发环境搭建</a></h2>作为一个小组级的开发环境，版本控制系统和BUG跟踪系统等都涉及到用户认证部分。如何方便的将这些系统集成起来是一个非常困难的事情，毕竟我们不能指望 Linux下有像Source Offsite那样集成度很高的版本控制/BUG跟踪集成系统。<br /><br />我个人是很反对使用pserver模式的远程用户认证的，但如果大部分组员使用WINDOWS客户端进行开发的话，总体来说使用 CVSROOT/passwd认证还是很难避免的，但CVS本身用户的管理比较麻烦。本来我打算自己用perl写一个管理界面的，直到我发现了 CVSTrac：一个基于WEB界面的BUG跟踪系统，它外挂在CVS系统上的BUG跟踪系统，其中就包括了WEB界面的CVSROOT/passwd文件的管理，甚至还集成了WIKIWIKI讨论组功能。 
<p>这里首先说一下CVS的pserver模式下的用户认证，CVS的用户认证服务是基于inetd中的：<br />cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver<br />一般在2401端口（这个端口号很好记：49的平方）<br /><br />CVS用户数据库是基于CVSROOT/passwd文件，文件格式：<br />[username]:[crypt_password]:[mapping_system_user]<br />由于密码都用的是UNIX标准的CRYPT加密，这个passwd文件的格式基本上是apache的htpasswd格式的扩展（比APACHE的 PASSWD文件多一个系统用户映射字段），所以这个文件最简单的方法可以用<br />apache/bin/htpasswd -b myname mypassword <br />创建。注意：通过htpasswd创建出来的文件会没有映射系统用户的字段<br />例如：<br />new:geBvosup/zKl2<br />setup:aISQuNAAoY3qw<br />test:hwEpz/BX.rEDU </p><p>映射系统用户的目的在于：你可以创建一个专门的CVS服务帐号，比如用apache的运行用户apache，并将/home/cvsroot目录下的所有权限赋予这个用户，然后在passwd文件里创建不同的开发用户帐号，但开发用户帐号最后的文件读写权限都映射为apache用户，在SSH模式下多个系统开发用户需要在同一个组中才可以相互读写CVS库中的文件。</p><p>进一步的，你可以将用户分别映射到apache这个系统用户上。<br />new:geBvosup/zKl2:apache<br />setup:aISQuNAAoY3qw:apache<br />test:hwEpz/BX.rEDU:apache </p><p>CVSTrac很好的解决了CVSROOT/passwd的管理问题，而且包含了BUG跟踪报告系统和集成WIKIWIKI交流功能等，使用的 CGI方式的安装，并且基于<a href="http://www.gnu.org/copyleft/gpl.html">GNU Public License</a>：<br /></p><p align="left">在inetd里加入cvspserver服务：<br />cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver</p><p align="left">xietd的配置文件：%cat cvspserver <br />service cvspserver<br />{<br />disable = no<br />socket_type = stream<br />wait = no<br />user = apache<br />server = /usr/bin/cvs<br />server_args = -f --allow-root=/home/cvsroot pserver<br />log_on_failure += USERID<br />}</p><p>注意：这里的用户设置成apache目的是和/home/cvsroot的所有用户一致，并且必须让这个这个用户对/home/cvsroot/下的 CVSROOT/passwd和cvstrac初始化生成的myproj.db有读取权限。</p><p></p><p>安装过程 </p><ol><li>下载：可以从<a href="http://www.cvstrac.org/">http://www.cvstrac.org</a> 下载<br />我用的是已经在Linux上编译好的应用程序包：cvstrac-1.1.2.bin.gz，<br />%gzip -d cvstrac-1.1.2.bin.gz<br />%chmod +x cvstrac-1.1.2.bin<br />#mv cvstarc-1.1.1.bin /usr/bin/cvstrac <br />如果是从源代码编译：<br />从 http://www.sqlite.org/download.html 下载SQLITE的rpm包：<br />rpm -i sqlite-devel-2.8.6-1.i386.rpm<br />从 ftp://ftp.cvstrac.org/cvstrac/ 下载软件包<br />解包，假设解包到/home/chedong/cvstrac-1.1.2下，并规划将cvstrac安装到/usr/local/bin目录下， cd /home/chedong/cvstrac-1.1.2 编辑linux-gcc.mk:<br />修改：<br />SRCDIR = /home/chedong/cvstrac-1.1.2<br />INSTALLDIR = /usr/local/bin<br />然后<br />mv linux-gcc.mk Makefile<br />make<br />#make install<br /><br /></li><li>初始化cvstrac数据库：假设数据库名是 myproj<br />在已经装好的CVS服务器上（CVS库这时候应该已经是初始化好了，比如：cvs init初始化在/home/cvsroot里），运行一下<br />%cvstrac init /home/cvsroot myproj<br />运行后，/home/cvsroot里会有一个的myproj.db库，使用CVSTRAC服务，/home/cvsroot/myproj.db /home/cvsroot/CVSROOT/readers /home/cvsroot/CVSROOT/writers /home/cvsroot/CVSROOT/passwd这几个文件对于web服务的运行用户应该是可写的，在RedHat8上，缺省就有一个叫 apache用户和一个apache组，所以在httpd.conf文件中设置了用apache用户运行web服务：<br />User apache<br />Group apache，<br />然后设置属于apache用户和apache组<br />#chown -R apache:apache /home/cvsroot<br />-rw-r--r-- 1 apache apache 55296 Jan 5 19:40 myproj.db<br />drwxrwxr-x 3 apache apache 4096 Oct 24 13:04 CVSROOT/<br />drwxrwxr-x 2 apache apache 4096 Aug 30 19:47 some_proj/<br />此外还在/home/cvsroot/CVSROOT中设置了：<br />chmod 664 readers writers passwd<br /></li><li>在apche/cgi-bin目录中创建脚本cvstrac:<br />#!/bin/sh<br />/usr/bin/cvstrac cgi /home/cvsroot<br />设置脚本可执行：<br />chmod +x /home/apache/cgi-bin/cvstrac<br /></li><li>从 http://cvs.server.address/cgi-bin/cvstrac/myproj 进入管理界面<br />缺省登录名：setup 密码 setup<br />对于一般用户可以从：<br />http://cvs.server.address/cgi-bin/cvstrac/myproj 
</li><li>在setup中重新设置了CVSROOT的路径后，/home/cvsroot<br />如果是初次使用需要在/home/cvsroot/CVSROOT下创建passwd, readers, writers文件<br />touch passwd readers writers<br />然后设置属于apache用户，<br />chown apache.apache passwd readers writers<br />这样使用setup用户创建新用户后会同步更新CVSROOT/passwd下的帐号<br /></li></ol><p align="left">修改登录密码，进行BUG报告等，<br />更多使用细节可以在使用中慢慢了解。<br /></p><p align="left">对于前面提到的WinCVS在perference里设置：<br />CVSROOT栏输入：username@ip.address.of.cvs:/home/cvsroot<br />Authenitication选择：use passwd file on server side <br />就可以了从服务器上进行CVS操作了。<br /></p><h2><a name="auth">CVS的用户权限管理</a></h2><p align="left">CVS的权限管理分2种策略：<br /></p><ul><li>基于系统文件权限的系统用户管理：适合多个在Linux上使用系统帐号的开发人员进行开发。 
</li><li>基于CVSROOT/passwd的虚拟用户管理：适合多个在Windows平台上的开发人员将帐号映射成系统帐号使用。 </li></ul>为什么使用apache/apache用户？首先RedHat8中缺省就有了，而且使用这个用户可以方便通过cvstrac进行WEB管理。<br />chown -R apache.apache /home/cvsroot<br />chmod 775 /home/cvsroot<br /><p align="left">Linux上通过ssh连接CVS服务器的多个开发人员：通过都属于apache组实现文件的共享读写<br />开发人员有开发服务器上的系统帐号：sysuser1 sysuser2，设置让他们都属于apache组，因为通过cvs新导入的项目都是对组开放的：664权限的，这样无论那个系统用户导入的项目文件，只要文件的组宿主是apache，所有其他同组系统开发用户就都可以读写；基于ssh远程认证的也是一样。<br /></p><p align="left">   apache(system group)<br />/            |           \<br />sysuser1   sysuser2     sysuser3<br /></p><p align="left">Windows上通过cvspserver连接CVS服务器的多个开发人员：通过在passwd文件种映射成 apache用户实现文件的共享读写<br />他们的帐号通过CVSROOT/passwd和readers writers这几个文件管理；通过cvstrac设置所有虚拟用户都映射到apache用户上即可。<br /></p><p align="left">   apache(system user)<br />/            |            \<br />windev1     windev2      windev3             </p><p align="left"></p><p></p><p>利用CVS WinCVS/CVSWeb/CVSTrac 构成了一个相对完善的跨平台工作组开发版本控制环境。</p><p>相关资源： </p><p>CVS HOME：<br /><a href="http://www.cvshome.org/">http://www.cvshome.org</a></p><p>CVS FAQ：<br /><a href="http://www.loria.fr/%7Emolli/cvs-index.html">http://www.loria.fr/~molli/cvs-index.html</a><br /><br />相关网站:<br /><a href="http://directory.google.com/Top/Computers/Software/Configuration_Management/Tools/Concurrent_Versions_System/">http://directory.google.com/Top/Computers/Software/Configuration_Management/Tools/Concurrent_Versions_System/</a><br /></p><p>CVS--并行版本系统<br /><a href="http://www.soforge.com/cvsdoc/zh_CN/book1.html">http://www.soforge.com/cvsdoc/zh_CN/book1.html</a></p><p>CVS 免费书:<br /><a href="http://cvsbook.red-bean.com/">http://cvsbook.red-bean.com/</a></p><p><a href="http://refcards.com/refcards/cvs/index.html">CVS命令的速查卡片 refcards.com/refcards/cvs/</a></p><p>WinCVS:<br /><a href="http://cvsgui.sourceforge.net/">http://cvsgui.sourceforge.net/</a></p><p>CVSTrac: A Web-Based Bug And Patch-Set Tracking System For CVS<br /><a href="http://www.cvstrac.org/">http://www.cvstrac.org</a></p><p>StatCVS：基于CVS的代码统计工具：按代码量，按开发者的统计表等<br /><a href="http://sourceforge.net/projects/statcvs">http://sourceforge.net/projects/statcvs<br /></a></p>如何在WEB开发中规划CVS上：在Google上查 "cvs web development"<br /><a href="http://ccm.redhat.com/bboard-archive/cvs_for_web_development/index.html">http://ccm.redhat.com/bboard-archive/cvs_for_web_development/index.html</a><br /><br />一些集成了CVS的IDE环境： <br /><a href="http://www.eclipse.org/">Eclipse</a><br /><a href="http://www.magicunix.com/product_ch.html">Magic C++</a><img src ="http://www.cnitblog.com/tilan/aggbug/21483.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-04 11:02 <a href="http://www.cnitblog.com/tilan/articles/21483.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache与JBOSS的整合,并支持SSL,整理 </title><link>http://www.cnitblog.com/tilan/articles/21121.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Tue, 26 Dec 2006 05:55:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21121.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21121.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21121.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21121.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21121.html</trackback:ping><description><![CDATA[系统:Red Hat Enterprise AS 4<br />用到的软件:<br />      &lt;1&gt;.httpd-2.2.3.tar.gz<br />      &lt;2&gt;.jboss-4.0.5.GA.zip<br />      &lt;3&gt;.openssl-0.9.8d.tar.gz<br />      &lt;4&gt;.sign.sh(mod_ssl-2.8.28-1.3.37.tar.gz里面)<br />      &lt;5&gt;.java_app_platform_sdk-5_01-linux.bin<br /><br />下载地址:<br />        <a href="http://httpd.apache.org/download.cgi" target="_blank"><font color="#666666">http://httpd.apache.org/download.cgi</font></a><br />        <a href="http://prdownloads.sourceforge.net/jboss/jboss-4.0.5.GA.zip?download" target="_blank"><font color="#666666">http://prdownloads.sourceforge.net/jboss/jboss-4.0.5.GA.zip?download</font></a><br />        <a href="http://www.openssl.org/source/openssl-0.9.8d.tar.gz" target="_blank"><font color="#666666">http://www.openssl.org/source/openssl-0.9.8d.tar.gz</font></a><br />        <a href="http://www.modssl.org/source/" target="_blank"><font color="#666666">http://www.modssl.org/source/</font></a><br />      <a href="https://sdlc3b.sun.com/ECom/EComActionServlet/DownloadPage:~:com.sun.sunit.sdlc.content.DownloadPageInfo;jsessionid=B26C97DB223331C1592519069677284D;jsessionid=B26C97DB223331C1592519069677284D" target="_blank"><font color="#666666">https://sdlc3b.sun.com/ECom/EComActionServlet/DownloadPage:~:com.sun.sunit.sdlc.content.DownloadPageInfo;jsessionid=B26C97DB223331C1592519069677284D;jsessionid=B26C97DB223331C1592519069677284D</font></a><br /><br />(一)安装openssl 2.8.28-2.3.37<br />  #tar -zxvf openssl-0.9.8d.tar.gz -C openssl<br />  #cd openssl<br />  #./config –-prefix=/usr/local/openssl<br />  #make<br />  #make install<br /><br />(二)安装apaphe2.2.3<br />  #tar -zxvf httpd-2.2.3.tar.gz<br />  #cd httpd-2.2.3<br />  #./configure --prefix=/usr/local/apache --enable-proxy=share --enable-proxy-ajp=share --enable-ssl=static --with-ssl=/usr/local/openssl <br />  #make<br />  #make install<br />  <br />(三)配置apache,支持SSL<br />  #cd /usr/local/apache/conf<br />  #vi httpd.conf<br />  <br />  #添加<br />  ProxyPass / ajp://127.0.0.1:8009/<br />  ProxyPassReverse / ajp://127.0.0.1:8009/<br />  #这就实现了最简单的apache＋jboss整合。<br /><br />  #加入SSL支持部分，这里指定使用SSL v2协议<br /><br />  SSLProtocol -all +SSLv2<br />  SSLCipherSuite SSLv2:+HIGH:+MEDIUM:+LOW:+EXP<br />  Include conf/extra/httpd-ssl.conf<br />  <br />  #保存退出<br />  <br />  生成认证证书<br />先建立一个 CA 的证书， <br />首先为 CA 创建一个 RSA 私用密钥， <br />[S-1] <br />openssl genrsa -des3 -out ca.key 1024 <br />系统提示输入 PEM pass phrase，也就是密码，输入后牢记它。 <br />生成 ca.key 文件，将文件属性改为400，并放在安全的地方。 <br />[S-2] <br />chmod 400 ca.key <br />你可以用下列命令查看它的内容， <br />[S-3] <br />openssl rsa -noout -text -in ca.key <br />利用 CA 的 RSA 密钥创建一个自签署的 CA 证书（X.509结构） <br />[S-4] <br />openssl req -new -x509 -days 3650 -key ca.key -out ca.crt <br />然后需要输入下列信息： <br />Country Name: cn 两个字母的国家代号 <br />State or Province Name: An Hui 省份名称 <br />Locality Name: Bengbu 城市名称 <br />Organization Name: Family Network 公司名称 <br />Organizational Unit Name: Home 部门名称 <br />Common Name: Chen Yang 你的姓名 <br />Email Address: <a href="mailto:yemeiqiang@gmail.com"><font color="#666666">yemeiqiang@gmail.com</font></a> Email地址 <br />生成 ca.crt 文件，将文件属性改为400，并放在安全的地方。 <br />[S-5] <br />chmod 400 ca.crt <br />你可以用下列命令查看它的内容， <br />[S-6] <br />openssl x509 -noout -text -in ca.crt <br />下面要创建服务器证书签署请求， <br />首先为你的 Apache 创建一个 RSA 私用密钥： <br />[S-7] <br />openssl genrsa -des3 -out server.key 1024 <br />这里也要设定pass phrase。 <br />生成 server.key 文件，将文件属性改为400，并放在安全的地方。 <br />[S-8] <br />chmod 400 server.key <br />你可以用下列命令查看它的内容， <br />[S-9] <br />openssl rsa -noout -text -in server.key <br />用 server.key 生成证书签署请求 CSR. <br />[S-10] <br />openssl req -new -key server.key -out server.csr <br />这里也要输入一些信息，和[S-4]中的内容类似。 <br />至于 extra attributes 不用输入。 <br />你可以查看 CSR 的细节 <br />[S-11] <br />openssl req -noout -text -in server.csr <br />下面可以签署证书了，需要用到脚本 sign.sh <br />[S-12] <br />sign.sh server.csr <br />就可以得到server.crt。 <br />将文件属性改为400，并放在安全的地方。 <br />[S-13] <br />chmod 400 server.crt <br />删除CSR <br />[S-14] <br />rm server.csr<br />Sign.sh在openssl目录中没有。我是在mod_ssl第三方模块中提取的。<br />把生成好的文件放在/usr/local/apache/conf目录下。<br />启动apache<br />/usr/local/apache/bin/apachectl start<br />有可能不能访问,原因可能是jboss没有开启.<br /><br />(四)安装JBOSS4.0.5<br />  先安装java环境<br />  #./java_app_platform_sdk-5_01-linux.bin<br />  #rpm -ivh java_app_platform_sdk-5_01-linux.rpm<br />  配置环境变量<br />  #vi /etc/profile<br />  #添加<br />  JAVA_HOME=/usr/local/java/SDK/jdk<br />JRE=/usr/local/java/SDK/jdk/jre<br />CLASSPATH=/usr/local/java/SDK/jdk/lib/tools.jar:/usr/local/java/SDK/jdk/lib/dt.jar:/usr/local/java/SDK/jdk/jre/lib/rt.jar<br />PATH=$PATH:$JAVA_HOME/bin:$JRE/bin<br />export PATH JAVA_HOME JRE CLASSPATH<br />#保存退出<br /><br />把系统重启一下,让环境变量生效<br />#reboot<br />现在开始安装jboss<br />#unzip jboss-4.0.5.GA.zip<br />#cd jboss-4.0.5.GA<br />#cp -r jboss-4.0.5GA /usr/local/jboss<br />#cd /usr/local/jboss/bin<br />#./run.sh 启动jboss<br /><br />打开Firefox ,输入<a href="https://localhost/" target="_blank"><font color="#666666">https://localhost</font></a>看看,是不是可以了,呵呵<br /><img src ="http://www.cnitblog.com/tilan/aggbug/21121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-12-26 13:55 <a href="http://www.cnitblog.com/tilan/articles/21121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse下使用Subversion （补）</title><link>http://www.cnitblog.com/tilan/articles/20102.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Tue, 05 Dec 2006 07:50:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/20102.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/20102.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/20102.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/20102.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/20102.html</trackback:ping><description><![CDATA[<div class="left">
				<span class="span">作者：朱先忠编译 转自天极<a href="http://dev.yesky.com/356/2578856.shtml">http://dev.yesky.com/356/2578856.shtml</a></span>
		</div>
		<div class="left">
				<span class="span">
				</span>
		</div>
		<div class="left">
				<span class="span">
				</span>
		</div>
		<div class="fontclear">
		</div>
		<div class="left fontsize3">CVS很酷，但Subversion更酷。然而，如果你在使用Eclipse进行开发，那么你可能直到近来才能利用Subversion带来的优点</div>
		<div class="left fontsize3">
		</div>
		<div class="left fontsize3">
				<strong>摘要</strong> CVS很酷，但Subversion更酷。然而，如果你在使用Eclipse进行开发，那么你可能直到近来才能利用Subversion带来的优点。随着Subclipse的发行，Subversion可能会最终在你的Eclipse IDE环境充分发挥其威力而压倒CVS。</div>
		<strong>一、SCM和Subversion简介<br /><br /></strong>　　软件配置管理(SCM)是管理源码并保持其安全的良好艺术，它能实现源码与其他团队成员之间保持共享，并且能够对之加以保护。良好地利用SCM，你能够容易地跟踪软件的发行和新的开发分支；这样以来，可以更为容易地标识和修正发行产品中的错误。<br /><br />　　其实，有大量的SCM工具可用，既有开源的和也有商业化的，例如StarTeam，Perforce，BitKeeper和ClearCase。在开源世界里，事实上的SCM标准是并发版本管理系统（CVS），它被广泛应用于世界范围内的成百上千的开源和商业工程。然而，CVS也存在下列许多固有的缺陷，这使得它无法非常完美地适合于现代工程开发：<br /><br />　　· 实质上针对文本文件的设计使得CVS处理二进制文件能力比较差。在每一次提交时，二进制文件被以整体形式传输和存储，这将带来带宽和磁盘空间的浪费。<br /><br />　　· 在CVS中，你不能移动文件和目录。你唯一的选择基本上就是删除并且重新添加它们，从而失去了整个过程中的所有的文件历史信息。<br /><br />　　· CVS中没有实现原子提交的概念。比方说，你要把10个文件提交到服务器，而该提交操作往往在整个过程的中途停了下来。(这很可能会发生，如果某人同时提交一个文件，或甚至如果你的网络失败或你的PC重新启动的话。)在这种情况下，服务器将仅记录下你的修正的一半信息，这可能会使代码基部分处于一种潜在地不稳定的状态。<br /><br />　　Subversion是一种比较新的开源SCM工具，其设计目的是力图从根本上克服原CVS所具有的限制。它是一种良好设计的工具，具有适合于现代开发的许多新特征：<br /><br />　　· 提交是原子化的。提交的文件都能够被正确加入到一个新的修订当中，否则仓库不会被更新；并且每一个新的修订仅由一次提交中的变化部分组成。<br /><br />　　· Subversion对文本和二进制文件使用一种巧妙的二进制技术，这既优化了网络流量也优化了仓库磁盘空间。<br /><br />　　· 在Subversion中，每一次修订都代表了一个特定时间内完整的目录树拷贝。文件和目录可以不加限制地进行移动。<br /><br />　　· Subversion仅存储两个版本之间的修改内容，这不仅节约了磁盘空间，并且意味着标识一个新版本或创建一种新的子内容几乎可以立即实现。<br /><br />　　· 你可以以多种途径来存取一个Subversion仓库，具体则依赖于你的需要：使用HTTP或HTTPS（与WebDAV一起使用），使用快速的专利性svn:协议，或直接经由本地文件，等等。 <br /><br />　　<b>二、Subclipse插件与Eclipse的集成</b><br /><br />　　一种良好的SCM应该与你的工作环境紧密地集成到一起。没有谁真正喜欢转到命令行以把文件添加到仓库。Eclipse很早就实现了CVS集成，但是直到最近Subversion用户仍没有被引起重视。现在，新的Subclipse插件提供了在Eclipse中的一种平滑的Subversion集成。<br /><br />　　(一) 安装Subclipse插件<br /><br />　　下面，你以通常的方法从更新站点下安装Subclipse：<br /><br />　　1. 打开"Find and install"窗口（"Help&gt;Software Updates&gt;Find and Install"）。<br /><br />　　2. 选择"Search for new features to install"选项并点击Next。<br /><br />　　3. 点击"New Remote Site"并且创建一远程站点，使用名字Subclipse和URL http://subclipse.tigris.org/update_1.0.x(参考图1)。<br /><br />　　4. 在结果安装窗口中，把"Subeclipse in the Features"选择到安装列表中，并且通过向导来开始安装插件。<br /><br />　　5. 完成这些之后，重新启动Eclipse。现在，你可以继续往下进行！<br /><br /><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="297" hspace="0" src="http://www.subversion.org.cn/images/stories//edu/t1.jpg" width="335" border="1" /><br />图1.安装Subclipse插件</div></td></tr></tbody></table><br />(二) 建立Repository定义<br /><br />　　现在，既然你已经安装完插件；那么，接下来，你需要告诉它你的工程仓库位于何处。你是在SVN Repository视图中实现的。打开这个视图（"Windows&gt;Show View&gt;Other&gt;SVN Repository"）并且在上下文菜单中选择"New&gt;Repository Location"以显示一个如图2所示的对话框。输入适当的URL并且点击"Finish"。<br /><br /><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="279" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t2.jpg" width="300" border="1" /><br />图2.添加一个仓库定义</div></td></tr></tbody></table><p><br />　　(三) 检出（Check Out）一个工程<br /><br />　　一旦建立一个仓库，你就可以在SVN Repository视图中浏览所有的内容(见图3)。我们后面将会看到，这个视图是一种与Subversion进行交互的非常方便的方式。</p><p align="center"><br /><br /><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="186" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t3.jpg" width="276" border="1" /><br />图3.SVN Repository视图。</p><p><br /><br />　　现在，让我们把一个工程检出到你的Eclipse工作区中。这只需选择你需要的Subversion仓库，打开上下文菜单，并且选择"Checkout"即可。这将打开一个具有两个选项的向导：<br /><br />　　· Check out as a Project configured using the New Project Wizard-这个选项打开新工程向导，这可以让你使用内建的Eclipse工程类型配置工程。这个选项通常是最好用的，因为它让你使用相同的工程模板和配置屏幕，而当你创建一个常规工程时你经常使用它们。<br /><br />　　· Check out as a Project in the Workspace-这个选项简单地在你的包含检出源码的工作区中创建一个Eclipse工程。<br /><br />　　在以上两种情况下，你仍然需要更新工程的构建路径，因为在检出该工程源码之前，Eclipse不能确定这些<a class="bluekey" href="http://dev.yesky.com/devjava/" target="_blank"><u><font color="#0000ff">Java</font></u></a>源码所在的位置。<br /><br />　　(四) 把一个新工程导入到仓库中<br /><br />　　如果你只是启动了一个新的工程，那么你需要把它导入到Subversion仓库。Subclipse提供了一种方便的方式来直接从你的IDE内部实现这一点。为此，只需要从Package Explorer视图下选择你的工程，并且在上下文菜单中选择"Team&gt;Share Project"。你可以使用现有仓库之一或创建一新的仓库定义。在你指定仓库和工程名之后，你能指定你想放到仓库中的文件和目录并且提供一个初始注释(见图4)。这种方法特别有用，因为它让你有选择地导入仅由Subversion管理的文件，即使该工程还包含其它文件（例如生成的类，临时文件或其它不是必需的内容等）。 <br /><br /></p><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="355" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t4.jpg" width="372" border="0" /><br />图4.把一个工程导入到一个Subversion仓库中</div></td></tr></tbody></table><br /><strong>三、在Eclipse中使用Subversion<br /><br /></strong>　　现在，既然你的支持Subversion的工程已经启动并且运行起来，那么大多数必要的Subversion命令就可经由"Team"上下文菜单存取(参考图5)。你可以在Package Explorer中看到你的本地文件的状态(参考图6)，其中，任何修改了的文件都被标记上一个星号。存储在仓库中的文件都显示一个小黄桶图标(代表了一个数据库)；还没有被添加到仓库中的文件以一个问号显示。<br /><br /><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="243" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t5.jpg" width="324" border="1" /><br />图5.大多数Subversion命令能被经由Team菜单存取<br /><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="279" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t6.jpg" width="407" border="1" /><br />图6.你可以在Package Explorer中看到本地文件的状态</div></td></tr></tbody></table><br />　　(一) 与Repository保持同步<br /><br />　　从仓库中更新你的文件并且把你的变化提交到仓库是相当直接的过程，这可以使用"Team&gt;Update and Team&gt;Commit"菜单选项来实现。在提交你的变化之前，你可能想看一下自从你的上次更新以来是否服务器上有任何文件被修改。为此，你可以使用"Team &gt;Synchronize with Repository"。这个命令让你看到有哪些内容已经被局部地修改，有哪些内容在服务器上修改，以及这两种修改之间的任何冲突（参考图7)。你还可以以可视化方式看到冲突的版本，并且在提交你的变化之前纠正任何比较突出的冲突。<br /><br /><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="247" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t7.jpg" width="324" border="1" /><br />图7.与仓库保持同步</div></td></tr></tbody></table><br />　　(二) 使用属性<br /><br />　　属性是Subversion具有创新性的特征之一。在Subversion中，你可以把元数据（"properties"）关联到任何文件或目录。你可以定义任何你喜欢的属性，但是Subversion也提供了一些有用的内置属性，例如下面图8中所提供的这些属性：<br /><br />　　· svn:executable属性，允许你在支持这种能力的操作系统上设置一个文件的可执行标志。<br /><br />　　· svn:need-lock属性，可以用来在文件（例如，对二进制文件非常有用）上强加排斥锁。一个定义了svn:need-lock属性的文件一次只能被一个人修改。当该文件被检出时，它是只读的。如果你想修改该文件，你需要首先使用"Team&gt;Lock"菜单选项。之后，使用"Team&gt;Unlock"释放该文件，或仅提交你的变化。这一行为将释放该锁并且让其它的用户也得到该文件上的一把锁。 <br /><br /><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="206" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t8.jpg" width="288" border="1" /><br />图8.把一个Subversion属性添加到一个文件中</div></td></tr></tbody></table><br />三) Tag和Branch<br /><br />　　在Subversion中，很容易创建新的tag和branch。你可以使用tag来标识一个特定的版本（使用一种可读的名字，例如"Release 1.0"）。；而一个branch用于新的开发工作而不影响主源码基(称作trunk)。在一个branch上的开发仍会继续进行，直到开发者已经为把变化集成回主trunk作好准备。<br /><br />　　在Subversion中，branch和tag都是通过制作给定修订的一个虚拟副本（以另一个名字和/或另一个目录）创建的。在常规情况下，branch存储在branches目录下，tag位于tags目录下，尽管在实践中为了满足你的工程你可以使用自己的任何定制。<br /><br />　　从Eclipse中，"Team&gt;Branch/Tag"菜单能够使你创建branch和tag(参考图9)。其中，Browse按钮提供了一种方便的方法来查看有哪些branch和tag存在于仓库中。<br /><br />　　当你使用"Team&gt;Switch"创建成功一个新的branch或tag时，你可以非常容易地在branches之间进行切换。无论何时你切换到一个不同的branch(或返回到trunk)，Subversion将仅更新文件（它需要保持你的当前工作的副本与目的branch之间的同步）。<br /><br /><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="291" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t9.jpg" width="311" border="1" /><br />图9.创建一个新的branch或tag</div></td></tr></tbody></table><br />　　(四) 修订历史<br /><br />　　象大多数SCM系统一样，Subversion让你跟踪你的源码的变化。"Team&gt;Show in Resource History"菜单选项能够使你查询这些变化的列表（包括对一个文件，目录或甚至整个工程的改变）(见图10)。<br /><br />　　记住，在Subversion中，提交是原子性的-一次提交由一组文件变化和一个全局注释组成。"SVN Resource History"视图向你显示每一次提交的一个简明视图，包括修改的文件和相关注释。<br /><br /><table width="90%" align="center"><tbody><tr><td><div align="center"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height="134" hspace="0" src="http://www.subversion.org.cn/images/stories/edu/t10.jpg" width="407" border="1" /><br />图10.历史资源</div></td></tr></tbody></table><br />　　<b>四、结论</b><br /><br />　　Subversion是一种强有力的和非常灵活的SCM工具，也是CVS的一个成功的后继者。结合Subclipse，Subversion能最终在你的Eclipse IDE环境中得到全面的发挥。<img src ="http://www.cnitblog.com/tilan/aggbug/20102.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-12-05 15:50 <a href="http://www.cnitblog.com/tilan/articles/20102.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用SUBCLIPSE——针对ECLIPSE的SUBVERSION插件</title><link>http://www.cnitblog.com/tilan/articles/19814.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Fri, 01 Dec 2006 08:15:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/19814.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19814.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/19814.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19814.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19814.html</trackback:ping><description><![CDATA[<h3>摘要</h3>
		<p>　　<a href="http://subversion.tigris.org/" target="_blank">Subversion </a>(SVN)是一个版本控制系统，是CVS的极具竞争力的替代品。它支持CVS所缺少的一些重要特性，比如版本化的重命名、目录和元数据；还支持原子提交和通过HTTP/HTTPS的远程访问。许多开源项目使用Subversion作为版本控制系统，其中包括BEA的dev2dev <a href="http://www.projects.dev2dev.bea.com/" target="_blank">CodeShare </a>站点上的项目。 有一个简短的指南介绍了如何为CodeShare建立支持Windows的命令行SVN客户端和Tortiose SVN。然而，使用自己的IDE中的Subversion库才有意义。</p>
		<p>　　 本文描述如何在Eclipse IDE中使用Subversion，具体来说，<a href="http://subclipse.tigris.org/" target="_blank">介绍了Subclipse插件</a>的安装和使用。顺着这个思路，我还将展示如何使用产生的配置来修改或扩展Subclipse插件本身。</p>
		<h3>安装Subclipse</h3>
		<p>　　安装Subclipse的最好方法是使用Eclipse Update Manager。在Eclipse 3.1中，它位于Help -&gt; Software Updates -&gt; Find and Install...菜单下。请选择Search，查找要安装的新特性，并以<a href="http://subclipse.tigris.org/update" target="_blank">http://subclipse.tigris.org/update</a>作为URL添加New Remote Site。</p>
		<p align="center">
				<img height="144" alt="图1" src="http://dev2dev.bea.com.cn/images/image4060620001.gif" width="354" border="0" />
				<br />图1：使用Eclipse Update Manager安装Subclipse</p>
		<p>　　 扫描完更新后，您会看到一个可用特性的列表。我写这篇文章时，Subclipse 0.9.33是最新的更新版本。</p>
		<p align="center">
				<img height="426" alt="图2" src="http://dev2dev.bea.com.cn/images/image4060620002.gif" width="490" border="0" />
				<br />图2：选择最新的Subclipse更新版本</p>
		<p>　　 在接下来的界面中，会请求用户接受许可证并选择安装位置。建议不要将新插件（包括Subclipse）安装在默认的Eclipse安装目录下，最好将其放在一个外部扩展位置中。这会使手动卸载这些特性更加容易，如果需要的话；同时也使插件可以在多个版本的Eclipse安装之间共享，比如发行版、尝鲜(early access)稳定版（M1、M2等等）和集成IDE版本。</p>
		<p align="center">
				<img height="300" alt="图3" src="http://dev2dev.bea.com.cn/images/image4060620003.gif" width="397" border="0" />
				<br />图3：选择安装位置</p>
		<p>　　 此时，Update Manager已下载并安装了所选特性，然后请求重启Eclipse。</p>
		<p>　　 一旦重启Eclipse，用户就会在Preference对话框中看到一个新的SVN区域，并且还会看到有关Subversion活动的其他视图。可以使用Window -&gt; Show View -&gt; Other...菜单将这些视图添加到Java Perspective中。</p>
		<p align="center">
				<img height="294" alt="图4" src="http://dev2dev.bea.com.cn/images/image4060620004.gif" width="291" border="0" />
				<br />图4：添加关于Subversion活动的视图</p>
		<p>　　 我通常将SVN Repository视图添加到Quick Views中，而将SVN Resource History添加到位于Java Perspective工作区底部的一个标签组中。这样，在开发过程中，这两个视图就近便可用了，同时也便于利用拖放来运行某些任务，比如“获得资源历史”（从诸如Navigator、Package Explorer、SVN Repository和Synchronize之类的面向资源的视图到SVN Resource History视图）。</p>
		<h3>在Subclipse中配置SVN接口</h3>
		<p>　　可以配置Subversion服务器来使用下列协议之一：</p>
		<ul>
				<li>SVN协议，一种轻量级的有状态协议，由独立的Subversion服务器（svnserve）所使用。安全版本svn+ssh使用基于ssh的隧道。 
</li>
				<li>http协议，基于WebDAV扩展，通常被作为模块部署在Apache HTTP服务器上。安全版本使用https，dev2dev CodeShare上的Subclipse安装使用的就是该协议。 
</li>
				<li>file协议，用于访问本地可用的Subversion库（例如，共享驱动器上的Subversion库），它是最少选择的库。 </li>
		</ul>
		<p>　　Subclipse使用专门的适配器抽象化来利用上述协议。可以在Window -&gt; Preferences -&gt; Team -&gt; SVN对话框的插件属性中选择下列适配器中的一种。</p>
		<p align="center">
				<img height="418" alt="图5" src="http://dev2dev.bea.com.cn/images/image4060620005.gif" width="478" border="0" />
				<br />图5：选择适配器</p>
		<p>　　 每一种适配器都有其自身的优点：</p>
		<ul>
				<li>
						<a href="http://tmate.org/svn/" target="_blank">JavaSVN</a>是惟一完全基于Java的Subclipse客户端，是默认支持的。注意，JavaSVN不支持file:///协议。 
</li>
				<li>JavaHL是包装本地Subclipse API的瘦包装器。该适配器是为Win32平台预构建的，但是在其他所有的平台上必须手动构建（除非Unix发行版中包含它）。 
</li>
				<li>命令行适配器，只有在不能安装JavaHL并且Subclipse库使用file:///协议时才可以使用。 </li>
		</ul>
		<p>　　大多数情况下都可以使用JavaSVN；只有需要时才选择JavaHL或命令行适配器。<a href="http://dev2dev.bea.com/pub/a/2005/11/?page=3#resources" target="_blank">参考资料</a>小节中的链接可以帮助解决特定用例，如配置HTTP代理、SSL客户端证书，等等。</p>
		<h3>连接到CodeShare上的SVN库</h3>
		<p>　　现在就可以连接到Subversion库了。对于dev2dev CodeShare上的项目，可以在访问选项页面中看到一个库的URL，可以从Version控制项目菜单中找到该页面。 <a href="https://xjms-ra.projects.dev2dev.bea.com/servlets/ProjectSource" target="_blank">这里是一个例子 </a>。CodeShare SVN服务器要求用户使用的用户名和口令与其在dev2dev网站上所使用的相同。</p>
		<p align="center">
				<img height="406" alt="图6" src="http://dev2dev.bea.com.cn/images/image4060620006.gif" width="438" border="0" />
				<br />图6：连接到Subversion库</p>
		<p>　　 如果连接参数设置正确，就可以看到一个SSL证书确认对话框。</p>
		<p align="center">
				<img height="130" alt="图7" src="http://dev2dev.bea.com.cn/images/image4060620007.gif" width="429" border="0" />
				<br />图7：接受SSL证书</p>
		<p>　　 接受证书后，应该就可以浏览库并查看现有项目。</p>
		<p align="center">
				<img height="403" alt="图8" src="http://dev2dev.bea.com.cn/images/image4060620008.gif" width="340" border="0" />
				<br />图8：查看SVN库中的现有项目</p>
		<p>　　 现在已经准备好，要开始使用Subversion和Subclipse插件了！</p>
		<h3>查看SVN中的现有项目</h3>
		<p>　　在SVN Repository视图中可以看到，在许多CodeShare项目以及使用Subversion的其他项目中都可以看到一种共同的布局，通常如下所示：</p>
		<pre>  https://xjms-ra.projects.dev2dev.bea.com/svn/xjms-ra
   +-- branches
       +-- www
       +-- xjms-ra
           +-- mqseries (work in progress)
           +-- activemq
   +-- tags
       +-- xjms-ra
           +-- 0.0.1 (stable versions or releases)
           +-- 0.0.2
   +-- trunk
       +-- www     (project web site)
       +-- xjms-ra (project source)
</pre>
		<p>　　trunk文件夹中包含主线开发源代码；tags文件夹中包含稳定版或发行版；branches文件夹中包含来自替代开发线上的代码。在Subversion中，标签和分支仅仅是选中的源代码快照的版本化副本。若想获得更多详细内容，请参阅<a href="http://svnbook.red-bean.com/en/1.1/ch04.html" target="_blank">Subversion book</a>。</p>
		<p>　　 可以在SVN Repository视图中选择当前项目的主线或者特定的标签或分支，并从弹出菜单中选择Check Out As...动作。接着就会出现一个指导性的标准New Project Wizard，它允许用户选择项目类型（例如，Java或Simple Project）、项目名称和位置，并在需要时配置Java build路径。</p>
		<h3>为新的CodeShare项目配置SVN库</h3>
		<p>　　版本控制库是任何项目的基础架构的重要部分，对于开源项目（包括CodeShare上的项目）而言，它还在开发人员与其他社区成员之间的交流中起着重要作用。例如，它允许终端用户为最新的代码捐献补丁，并为重要的修复提供早期更新机制。由于它的重要作用，为一个新项目配置SVN库并从一开始就将所有的项目代码置于版本控制之下就显得非常重要了。</p>
		<p>　　 创建了新CodeShare项目之后，SVN库就包含了trunk、tags和branches文件夹，以及trunk下的www模块，它包含项目Web首页的index.html文件。可以在SVN Repository视图中验证这些，并使用该视图中的弹出菜单上的动作创建缺少的文件夹。</p>
		<p>　　 我们假设所有的源代码、build脚本、文档和其他项目资源被组织为一个Eclipse项目，那么就可以在Package Explorer或Navigator视图中使用弹出菜单中的Team -&gt; Share Project...动作。Share Project Wizard会要求用户选择SVN库类型，然后在下一个页面中，可以选择一个现有库或配置一个新库。</p>
		<p align="center">
				<img height="406" alt="图9" src="http://dev2dev.bea.com.cn/images/image4060620009.gif" width="461" border="0" />
				<br />图9：在Share Project Wizard中选择SVN库类型</p>
		<p>　　 在接下来的界面中指定模块名。为了与CodeShare项目布局相匹配，我们应该在trunk文件夹下创建模块，因此，指定trunk/&lt;project name&gt;作为模块名，比如trunk/xjms-ra。</p>
		<p align="center">
				<img height="276" alt="图10" src="http://dev2dev.bea.com.cn/images/image4060620010.gif" width="461" border="0" />
				<br />图10：指定模块名</p>
		<p>　　 经过确认后，Subclipse会创建模块，并将所有的项目文件导入SVN库。</p>
		<h3>使用SVN库</h3>
		<p>　　当项目连接到SVN库以后，在Package Explorer和Navigator视图中会弹出一个Team菜单，显示特定于Subversion的全部动作。可以直接运行Commit、Update、Add to svn:ignore，以及<a href="http://svnbook.red-bean.com/" target="_blank">Version Control with Subversion</a>一书中所描述的其他动作。该书中的内容也可以在Help -&gt; Help Contents -&gt; Version Control with Subversion下的Eclipse帮助系统中找到。</p>
		<p>　　 Subclipse插件还允许使用Eclipse的Team Synchronize视图，它可以使用户从库中清楚地观察到哪些项将要提交、哪些项已经被其他开发人员更改并需要更新。从这个Synchronize视图中还可以执行大多数的SVN命令。</p>
		<p>　　 可以使用弹出的Team -&gt; Synchronize with Repository菜单或位于主工具栏上的Synchronize...向导按钮将项目或工作集添加到Synchronize视图中。如果看不到该按钮，那么请将Team命令添加到当前视图中；可以使用Customize Perspective对话框添加，该对话框可从主工具栏上的弹出菜单中获得（单击任意空白处），然后，使用Window -&gt; Save Perspective As...菜单以相同的名称保存透视图。</p>
		<p align="center">
				<img height="335" alt="图11" src="http://dev2dev.bea.com.cn/images/image4060620011.gif" width="479" border="0" />
				<br />图11：将命令组添加到当前透视图中</p>
		<p>　　 在工具栏下拉菜单中选择Synchronize...动作来启动向导。在第一个界面中，它又让用户选择SVN版本跟踪系统，然后会显示标准资源选择面板，用户可以选择同步整个工作区，也可以选择某组项目或者一个指定的工作集。</p>
		<p align="center">
				<img height="409" alt="图12" src="http://dev2dev.bea.com.cn/images/image4060620012.gif" width="412" border="0" />
				<br />图12：同步工作区、工作集或选中的资源</p>
		<p>　　 一旦完成创建，Synchronize视图就可以使用版本控制系统安排自动刷新的时间。可以通过Synchronize视图菜单中的Schedule...菜单对其进行配置。这将有助于用户保持最新状态，还可以看到其他开发人员所做的所有改动。</p>
		<p align="center">
				<img height="193" alt="图13" src="http://dev2dev.bea.com.cn/images/image4060620013.gif" width="369" border="0" />
				<br />图13：安排自动刷新的时间</p>
		<p>　　 由于Subclipse仍在发展，所以用户可能会遇到bug或者无法找到真正希望获得的一些特性。这带我们进入下一个话题。</p>
		<h3>修补Subclipse</h3>
		<p>　　当在Subclipse中遇到问题时，可以有多种选择。如果是瑕疵问题，那么可以简单地选择不使用该产品或等待下一个版本。还可以搜索问题跟踪系统以及邮件列表档案<a href="mailto:user@subclipse.tigris.org?subject=">user@subclipse.tigris.org</a>和<a href="mailto:dev@subclipse.tigris.org?subject=">dev@subclipse.tigris.org</a>，有可能找到当前问题的应对措施或解释。如果这样没有帮助，那么可以在邮件列表中咨询此问题；如果有兴趣试着自己解决，那么，下面的段落将简要介绍如何开始调试和修补Eclipse。但是，如果非常希望有所捐助，那么一种好的方法是订阅<a href="mailto:dev@subclipse.tigris.org?subject=">dev@subclipse.tigris.org</a>邮件列表，从而使您所做的努力与其他开发人员相协调，根据项目路线图调整您的想法。</p>
		<p>　　 着手开始真的非常容易，即使您以前从没有使用过Eclipse插件。需要将Subclipse项目放入Eclipse工作区中。Subclipse项目的Subversion库位于<a href="http://subclipse.tigris.org/svn/subclipse/" target="_blank">http://subclipse.tigris.org/svn/subclipse/</a>，可以使用以前安装的Subclipse插件或者诸如命令行Subversion客户端或TortoiseSVN之类的外部工具来查看代码。还有一种非常好的办法是在<a href="http://tigris.org/" target="_blank">tigris.org</a> Web站点上注册，并请求Subclipse项目的Observer角色。然后，就可以使用相同的用户名连接到Subversion库了（也可以用“guest”/“guest”进行只读访问），还可以在问题跟踪器（一个集成的Bugzilla库）上发表评论，并附上对问题的补丁（如果有的话）。</p>
		<p>　　 一旦连接到版本控制库，就需要在自己的工作区中检查下述项目。对每一个模块选择Check Out As...，选择一个位置和项目名（建议使用下表所列出的实际的插件名），并单击Finish。</p>
		<table class="tabel-general" cellspacing="0" cellpadding="0" width="100%">
				<tbody>
						<tr>
								<th class="left" width="30%">库路径</th>
								<th class="center" width="40%">Jar或Eclipse插件名</th>
								<th class="right" width="30%">描述</th>
						</tr>
						<tr>
								<td class="left">trunk/svnClientAdapter</td>
								<td class="center">svnClientAdapter.jar</td>
								<td class="right">用于非Windows系统，或者当用户需要构建svnClientAdapter或JavaHL时</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/core</td>
								<td class="center">org.tigris.subversion.subclipse.core</td>
								<td class="right">特定于Eclipse的插件后端</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/javahl-win32</td>
								<td class="center">org.tigris.subversion.javahl.win32</td>
								<td class="right">为svnClientAdapter和JavaHL预构建本地Windows二进制文件</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/ui</td>
								<td class="center">org.tigris.subversion.subclipse.ui</td>
								<td class="right">特定于Eclipse的UI</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/feature-plugin</td>
								<td class="center">org.tigris.subversion.subclipse</td>
								<td class="right">介绍，无代码</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/feature</td>
								<td class="center">org.tigris.subversion.subclipse (feature)</td>
								<td class="right">Subclipse特性</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/book</td>
								<td class="center">org.tigris.subversion.book</td>
								<td class="right">Eclipse帮助小节，包括“Version Control with Subversion”这本书</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/book-feature</td>
								<td class="center">org.tigris.subversion.book (feature)</td>
								<td class="right">“Version Control with Subversion”这本书的特写</td>
						</tr>
						<tr>
								<td class="left">trunk/subclipse/update-site</td>
								<td class="center">-</td>
								<td class="right">Subclipse和“Version Control with Subversion”一书的特写的更新站点</td>
						</tr>
				</tbody>
		</table>
		<p>　　对于开发和测试，只需要org.tigris.subversion.subclipse.core, org.tigris.subversion.subclipse.ui以及org.tigris.subversion.javahl.win32或svnClientAdapter;其他的模块仅在打包整个插件特性或构建更新站点时需要。</p>
		<p>　　 当所有的项目都在Eclipse工作区中之后，就可以试着运行了。使用Run -&gt; Run...菜单（或Debug，在调试器下运行），启动新的Eclipse Application类型，并在Workspace Plug-Ins列表中选择Subclipse插件。如果使用已安装的Subclipse运行IDE，那么应该在External Plug-Ins列表中取消对Subclipse插件的选择，但是要使其他插件均保持选中状态。</p>
		<p align="center">
				<img height="415" alt="图14" src="http://dev2dev.bea.com.cn/images/image4060620014.gif" width="478" border="0" />
				<br />图14：运行Eclipse应用程序</p>
		<p>　　 单击Run（或Debug），如果一切都配置正确，那么就会出现第二个Eclipse Workbench窗口；应该可以打开Subclipse视图，并像Eclipse本身的实例一样连接到库。此时，如果是在调试器下运行，就可以开始将断点放到Subclipse类、或Subclipse所使用的Eclipse核心类中，调试器会停在这些断点上。一个非常好的起点是org.tigris.subversion.subclipse.ui插件中的org.tigris.subversion.subclipse.ui.actions包，它包括菜单或工具栏中特定于Subclipse的UI动作。注意，可以使用UI注册这些动作，可以在plugin.xml中声明式地注册（通常是action元素），或者是在Java代码中编程式地注册，因此，这两个地方都要查看。</p>
		<p>　　 假定已经完成了最棘手的部分，并且已经设法实现了更改，那么现在就该创建补丁并将其附在Subclipse 问题跟踪库中的原始问题上了。在创建补丁以前，请确保从版本控制库中选择最新的更改（如果有的话），并最后一次测试更改。如果一切都没有问题，那么就使用Team -&gt; Create Patch...菜单来启动向导。选择Save To Clipboard或Save In File System，并指定是否需要对子目录进行循环扫描来查看更改。</p>
		<p align="center">
				<img height="409" alt="图15" src="http://dev2dev.bea.com.cn/images/image4060620015.gif" width="418" border="0" />
				<br />图15：创建补丁</p>
		<p>　　 创建了补丁之后，就可以将其发送至dev@subclipse.tigris.org邮件列表了，或者也可以在问题跟踪器中创建问题并将其附上。</p>
		<h3>结束语</h3>
		<p>　　诸如Subclipse插件之类的Eclipse平台开源扩展可以提高开发人员的生产力，降低出错的可能性，并增强开发团队内部的交流。本文演示了如何安装、配置和使用Subclipse插件来从Eclipse IDE内部与Subversion版本控制系统进行交互。</p>
		<p>　　以Subclipse插件为例，本文还演示了如何设置一个环境以进行Eclipse插件开发、如何调试现有插件、如何创建补丁。事实上，任何Eclipse用户都可以为该开源扩展以及Eclipse平台本身捐献想法和补丁。</p>
		<h3>参考资料</h3>
		<ul>
				<li>
						<a href="http://subversion.tigris.org/" target="_blank">Subversion</a>——Subversion主页 
</li>
				<li>
						<a href="http://svnbook.red-bean.com/" target="_blank">Version Control with Subversion</a>——一本非常不错的Subversion方面的书 
</li>
				<li>
						<a href="http://subclipse.tigris.org/" target="_blank">Subclipse - Subversion Plug-in for Eclipse IDE</a>
				</li>
				<li>
						<a href="http://metissian.com/projects/macosx/subversion/" target="_blank">JavaHL for Mac OS X</a>
				</li>
				<li>
						<a href="http://subclipse.tigris.org/faq.html#build-javahl" target="_blank">Building JavaHL from sources</a>
				</li>
				<li>
						<a href="http://svnbook.red-bean.com/en/1.1/ch07.html#svn-ch-7-sect-1" target="_blank">Configuring an HTTP proxy connection for JavaHL and command-line adapters</a>
				</li>
				<li>
						<a href="http://tmate.org/svn/kb/plugin.html" target="_blank">Configuring an HTTP proxy connection for JavaSVN</a>
				</li>
				<li>
						<a href="http://subclipse.tigris.org/faq.html#http-ssl" target="_blank">Configuring SSL client certificates</a>
				</li>
				<li>
						<a href="http://svnbook.red-bean.com/en/1.1/ch07.html#svn-ch-7-sect-1" target="_blank">Configuring an svn+ssh:// connection for JavaHL and command-line adapter on Unix</a>
				</li>
				<li>
						<a href="http://subclipse.tigris.org/servlets/ReadMsg?list=users&amp;msgNo=3334" target="_blank">Configuring an svn+ssh:// connection for JavaHL and command-line adapter on Windows</a>
				</li>
				<li>
						<a href="http://tmate.org/svn/kb/plugin.html" target="_blank">Configuring an svn+ssh:// connection for JavaSVN adapter</a>
				</li>
				<li>
						<a href="http://subclipse.tigris.org/faq.html" target="_blank">Subclipse FAQ</a>
				</li>
				<li>dev2dev <a href="http://dev2dev.bea.com/eclipse/" target="_blank">Eclipse Technology Center</a></li>
		</ul>
		<p>
				<b>原文出处:</b>
				<a href="http://dev2dev.bea.com/pub/a/2005/11/subclipse.html" target="_blank">http://dev2dev.bea.com/pub/a/2005/11/subclipse.html</a>
		</p>
		<!--文章其他信息--><img src ="http://www.cnitblog.com/tilan/aggbug/19814.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-12-01 16:15 <a href="http://www.cnitblog.com/tilan/articles/19814.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows安装基于Apache的Subversion服务器(包括SSL配置) </title><link>http://www.cnitblog.com/tilan/articles/19363.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 20 Nov 2006 08:16:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/19363.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19363.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/19363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19363.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19363.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 关键词：								subversion 								安装																								服务器																								配置																				apache ssl-----------------------------1. 								引言												...&nbsp;&nbsp;<a href='http://www.cnitblog.com/tilan/articles/19363.html'>阅读全文</a><img src ="http://www.cnitblog.com/tilan/aggbug/19363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-11-20 16:16 <a href="http://www.cnitblog.com/tilan/articles/19363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>