3.9 冲突解决
如果两个人同时编辑同一个文件会怎么样呢?这里有两种情形。第一种是修改的代码互不重叠。因为模拟这种情况比较容易,让我们先考虑这种情况。
首先编辑 Number.txt 文件在 sesame 目录中的副本。把第一行变成大写。
文件 Number.txt ( 在 sesame 目录中 ) :
ZERO
one
two
three
four
five
six
现在编辑 Number.txt 文件在 aladdin 目录中的副本。把最后一行变成大写。
文件 Number.txt ( 在 aladdin 目录中 ) :
zero
one
two
three
four
five
SIX
我们刚才模拟两个开发者修改了同一个文件在本地的副本。现在,这些修改都是独立的,而且 CVS 仓库还不知道这些修改。通过投掷硬币,决定 Aladdin 先签入被修改的文件版本。
work/aladdin> cvs commit -m "Make 'six' important"
cvs commit: Examining .
Checking in Number.txt;
/Users/dave/sandbox/sesame/Number.txt,v <-- Number.txt
new revision: 1.3; previous revision: 1.2
done
不久之后, sesame 开发者也要签入这个文件。(记住,这个文件版本的第一行是大写的。)
work/sesame> cvs commit -m "Zero needs emphasizing"
cvs commit: Examining .
cvs commit: Up-to-date check failed for 'Number.txt'
cvs [commit aborted]: correct above errors first!
CVS 使用了“ errors ”这样的词语,甚至用了一个感叹号来结束提示消息。
让我们按照 CVS (间接)的建议,先用仓库的最新版本更新本地文件。记住我们的文件有大写的“ zero ”,而仓库中的版本有大写的“ six ”。
work/sesame> cvs update
cvs update: Updating .
RCS file: /Users/dave/sandbox/sesame/Number.txt,v
retrieving revision 1.2
retrieving revision 1.3
Merging differences between 1.2 and 1.3 into Number.txt
M Number.txt
注意那些附加的消息。它说明 CVS 并没有简单地更新本地文件,而是将修改的文件与仓库中的版本进行合并。让我们查看本地的文件版本:
文件 Number.txt :
ZERO
one
two
three
four
five
SIX
不可思议!现在的版本既包含我们修改的部分,也包含 Aladdin 修改的部分。两个人同时修改了一个文件,而 CVS 可以解决这个冲突问题。
记住我们在本地的修改还没有保存回仓库。因此我们请求 CVS 提交修改的文件,而且这次提交成功了,因为我们的本地版本已经包含了仓库中最新版本的内容。
work/sesame> cvs commit -m "Zero needs emphasizing"
cvs commit: Examining .
Checking in Number.txt;
/Users/dave/sandbox/sesame/Number.txt,v <-- Number.txt
new revision: 1.4; previous revision: 1.3
done
当 Aladdin 下次更新时也会得到我们修改的部分。
work/sesame> cd ../aladdin
work/aladdin> cvs update
cvs update: Updating .
U Number.txt
■ 遭遇变更冲突
在前一个示例中,两个(虚拟的)开发者所做的修改不存在重叠的部分。如果两个开发者同时编辑同一个文件的同一行会怎么样呢?让我们继续寻找答案。
进入 sesame 目录并且将 Number.txt 文件的第二行从“ one ”改成“ ichi ”。先不要签入这个文件。现在转到 aladdin 目录,并且将同一行从“ one ”修改成“ uno ”;再次假定 Aladdin 先签入他修改的文件。
work/aladdin> cvs commit -m "User likes Italian one"
cvs commit: Examining .
Checking in Number.txt;
/Users/dave/sandbox/sesame/Number.txt,v <-- Number.txt
new revision: 1.5; previous revision: 1.4
done
现在回到 sesame 目录中。记住我们在模拟两个不同的用户,假装此时不知道 Aladdin 修改的部分,并且试图签入修改的文件。
work/sesame> cvs commit -m "One should be Japanese"
cvs commit: Examining .
cvs commit: Up-to-date check failed for 'Number.txt'
cvs [commit aborted]: correct above errors first!
以前我们曾经看到过这个消息:需要进行更新以得到仓库中修改的代码。
work/sesame> cvs update
cvs update: Updating .
RCS file: /Users/dave/sandbox/sesame/Number.txt,v
retrieving revision 1.4
retrieving revision 1.5
Merging differences between 1.4 and 1.5 into Number.txt
rcsmerge: warning: conflicts during merge
cvs update: conflicts found in Number.txt
C Number.txt
现在看起来似乎不妙: CVS 告诉我们当将仓库中的版本与我们在本地修改的文件进行合并时发现了冲突。我们努力工作的成果会全白费吗?不。
当发生冲突时,主要是由于两个开发者有一些误会。对于本例,一个开发者想把第一行修改成意大利文,而另一个想用日文。想一下你就会明白这里存在交流上的问题,这是一个团队中的问题。不管什么原因,我们要解决的问题是,“这一行实际上应该是什么?” CVS 没有为用户提供一条热线,所以它不能解决这个问题,而只能给这个文件添加特殊的注释来显示发生了哪些冲突。
本例中,如果我们查看文件 Number.txt ,会发现它看起来像下面的样子:
文件 Number.txt:
ZERO
<<<<<<< Number.txt
ichi
=======
uno
>>>>>>> 1.5
two
three
four
five
SIX
带有 <<<<<< 和 >>>>>>> 的行显示了冲突发生的位置。在这两行之间 , 可以看到我们修改的部分以及仓库中存在冲突的修改部分。接下来,我们需要做一些检查工作。第一件需要做的事情是找出仓库中修改的部分是谁做的。 cvs log 命令用于显示一个或多个文件的历史,所以它可以帮助发现这里所发生的一切。
work/sesame> cvs log -r1.5 Number.txt
RCS file: /Users/dave/sandbox/sesame/Number.txt,v
Working file: Number.txt
head: 1.5
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 5; selected revisions: 1
description:
----------------------------
revision 1.5
date: 2003/04/22 18:22:07; author: dave; state: Exp; lines: +1 -1
User likes Italian one
===============================================
在最后两行,可以看到这次修改的作者的名称连同签入时的注释,我们可以向他询问这样修改的原因。给客户打一个电话之后,这个问题就解决了:客户希望单词“ one ”用日文而“ two ”用意大利文。 Aladdin 一定是搞错了。在这个新信息的帮助下,现在就可以解决这个冲突。在 sesame 目录中编辑 Number.txt 文件,移走 CVS 的冲突记号,并且按照客户的要求进行修改。
文件 Number.txt ( sesame ) :
ZERO
ichi
due
three
four
five
SIX
因为已经移走了冲突记号,现在可以提交这个文件。
work/sesame> cvs commit -m "One is Japanese, two Italian"
cvs commit: Examining .
Checking in Number.txt;
/Users/dave/sandbox/sesame/Number.txt,v <-- Number.txt
new revision: 1.6; previous revision: 1.5
done
CVS 实际上已帮我们发现了一个误解之处。冲突解决了,并且每个人都很高兴。乐观锁确实名副其实。需要强调的是,在实际项目中这种冲突极少发生。
另外一点要指出的是, CVS 并不能猜出人们的想法。两个人可能以两种不同的方式修复同一个错误。如果这些修改在源代码级没有冲突,那么这两者都会被 CVS 接受,即使是对同样的代码,同时使用这两种修复方式是没有任何意义的。因此,没有冲突只是意味着在文本级上你和其他人修改的地方没有重叠,但还是应该依靠单元测试来检验修改的代码能否正常工作。
以上是我们对 CVS 的一次快速预览。在此,你可以把该仓库留在原地。以后如果想在实际的项目仓库上使用一个特别的功能之前试验一下,你会发现这个仓库还是有用的。