SVN基本工作流程

来源:互联网 发布:sai2 mac中文版下载 编辑:程序博客网 时间:2024/05/01 23:23

基本工作流程

来源:SVN中文技术网[www.svn8.com] 作者:SVN技术研究中心 时间:2008-02-02 点击: 172

Subversion有大量特性,选项,丰富多样,但在日常基本工作中,更可能的是你仅仅用到很少的几个。在本节,我们浏览一下你在日常工作中使用Subversion最常会作的事。

典型的工作流程看起来像这样:

  • 更新你的工作副本

    • svn update

  • 做修改

    • svn add

    • svn delete

    • svn copy

    • svn move

  • 检查你的改动

    • svn status

    • svn diff

    • svn revert

  • 合并别人的改动

    • svn merge

    • svn resolved

  • 提交你的改动

    • svn commit

更新你的工作副本

当你在一个团队中为一个项目工作时,你会想要更新你的工作拷贝来获取那些你上次更新以来其他开放人员对项目做的新改动。使用 svn update会使你的工作副本和资料库中最新的修订版同步。

$ svn updateU  foo.cU  bar.cUpdated to revision 2.

这种情况表明在你上一次更新后,别人检入了对foo.cbar.c的修改。 Subversion已经更新了你的工作副本,加入了那些改动。

让我们更仔细的查看一下svn update的输出。当服务器发送改动到你的工作副本时,会在每项前显示一个字母代码,让你知道Subversion 在同步你的工作副本时对它作了什么动作:

U foo

文件foo被(Updated)更新了(从服务器接受修改)。

A foo

文件或目录foo被加到了(Added)你的工作副本中。

D foo

文件或目录foo被从你的工作副本删除了(Deleted)。

R foo

你工作副本中的文件或目录foo被替换了(Replaced)。就是说,foo被删除了,一个新的同名项被添加了。虽然它们名字相同,但是资料库认为他们是不同的对象并有不同的历史纪录。

G foo

文件foo从资料库收到了修改,但是你的本地副本已经被你修改了。或者是因为这些修改不交叉,或者是因为修改完全相同, Subversion已经成功地,毫无问题地把资料库中的修改合并(merGed)了到了文件中。

C foo

文件 foo从服务器接收到了冲突(Conflicting)的改动。来自服务器的改动和你对文件的改动有直接重叠。即使这样也不用急。这些交叠需要人来解决;在本章稍后我们会讨论这一点。

修改你的工作副本

现在你可以开始工作,修改你的工作副本了。通常选择做一个(或一些)特定的修改,比如写一个新的特性,解决一个Bug等比较好。这时可能用到的Subversion的命令是:svn addsvn deletesvn copy, and svn move。然而,如果你仅仅编辑那些已经在Subversion中的文件,你可能直到提交都不需要这些命令。你可以在你的工作副本中做的修改:

文件修改

这是最简单的那种的修改。你不需要告诉Subversion你打算改一个文件;只要改就行了。Subversion能自动探测哪些文件被修改过了。

树修改

你可以让Subversion把文件和目录标记为将要删除,增加,复制,或移动。虽然这些修改在你的工作副本中立即生效,但是直到你提交它们才会发生在资料库里。

修改文件时,可以使用你的文本编辑器,字处理器,图像编辑程序,或者其他任何你通常使用的工具。Subversion处理二进制文件就像处理文本文件一样容易——也同样高效。

下面是对四个Subversion子命令的一个概述。这些命令是你在修改树时最常用的。(我们将稍后谈到 svn importsvn mkdir

svn add foo

使文件,目录或者符号连接foo预定将要被添加到资料库。在你下一次提交时,foo 将会成为它父目录的子项。注意:如果foo是一个目录,所有在foo下的东西都会被预定要添加。如果你只想添加foo本身,要用--non-recursive (-N)开关。

svn delete foo

预定文件目录或者符号链接foo要从资料库删除。如果foo是一个文件或者一个连接,它马上就从你的工作副本删除。如果foo是一个目录,它不被删除,但是Subversion预定它要被删除。当你提交你的修改时,foo会被从你的工作副本和资料库删除。 [1]

svn copy foo bar

创建foo的一个名为bar的拷贝。bar自动被预定添加。当bar在下次提交中被添加时,他的复制历史被记录了(即记录它原本来自于foo)。 svn copy不会创建中间目录。

svn move foo bar

这个命令和运行svn copy foo bar; svn delete foo完全一样。就是说,bar作为 foo的一个拷贝被预定添加,同时foo被预定删除。 svn move不会创建中间目录。

检查你的修改

一旦你完成了修改,你需要把它们提交到资料库,但是在这么做之前,看一下究竟那些地方被修改了通常是个好主意。经过提交前对修改的检查,你能写出更准确的日志信息。也可能你会发现你无意中修改了一个文件,从而有机会在提交前取消这些改动。另外,这是一个在发布前回顾和细查那些改动的好机会。你可以使用svn statussvn diffsvn revert命令来仔细查看究竟做了那些修改。前两个命令用来发现你的工作副本中那些文件和目录修改了,第三个命令用来取消一些(或者全部)修改。

Subversion已经对帮助你完成这样的任务作了优化,可以在不和资料库通信的情况下完成很多工作。详细的说,对每个在.svn区域中置于版本控制下的文件,你的工作副本会秘密缓存一个“原始”的拷贝。有了这个拷贝,Subversion可以很快地显示你的工作文件被怎样修改了,甚至允许你不连接资料库而撤销这些修改。

svn status

你可能用svn status比任何别的Subversion命令都要多。

如果你在你的工作副本的顶层目录执行不带参数的svn status命令,它会检测所有文件和树的修改。下面是一些不同的 svn status命令会返回的状态码的例子。(注意,#后的文字不会被svn status打印)

  L    abc.c               # svn has a lock in its .svn directory for abc.c  M      bar.c               # the content in bar.c has local modifications M     baz.c               # baz.c has property but no content modificationsX      3rd_party           # this dir is part of an externals definition?      foo.o               # svn doesn't manage foo.o!      some_dir            # svn manages this, but it's either missing or incomplete~      qux                 # versioned as file/dir/link, but type has changedI      .screenrc           # svn doesn't manage this, and is configured to ignore itA  +   moved_dir           # added with history of where it came fromM  +   moved_dir/README    # added with history and has local modificationsD      stuff/fish.c        # this file is scheduled for deletionA      stuff/loot/bloo.h   # this file is scheduled for additionC      stuff/loot/lump.c   # this file has conflicts from an update    S  stuff/squawk        # this file or dir has been switched to a branch

在这个输出格式中,svn status打印出5列字符,跟着是几个空格符,跟着是一个文件或目录名。第一列表明了一个文件或目录和(或)它的内容的状态。会在这里打出的代码有:

A item

文件,目录或者符号连接item已经被预定要添加到资料库。

C item

文件item处在冲突状态中。就是说,更新时从服务器接收到的改动和你对工作副本作的本地改动交叠了。你必须在把你的修改提交到资料库前解决这些冲突。

D item

文件,目录或者符号连接item已经被预定要从资料库删除。

M item

文件的item的内容已经被修改了。

X item

目录item没有版本化,但和一个Subversion 外部定义相关。更多关于外部定义的知识,参见 ???.

? item

文件,目录或者符号连接item没有被置于版本控制之下。你可以传递--quiet (-q)参数给svn status命令,或者在父目录上设置svn:ignore属性,从而不显示这个问号。关于忽略文件的更多信息,参见???。

! item

文件,目录或者符号连接item在版本控制中,但是被丢失了或者有些不完整。如果这个项被非Subversion命令删除会导致丢失。如果是一个目录, 如果你打断了一次检出或者更新,它可能会不完整。只要用svn update命令就可以从资料库中重新取回这个文件或目录,或者使用 svn revert file可以恢复一个丢失的文件。

~ item

文件,目录或者符号连接item在资料库中是某种类型的对象,但是和你工作副本中的不是同一种。例如,可能Subversion资料库中有个文件, 但你没有使用svn deletesvn add 命令而在本地删除了它并创建了一个同名的目录,。

I item

文件,目录或者符号连接item没有置于版本控制之下,Subversion被配置成在执行svn addsvn importsvn status操作中忽略它。关于忽略文件的更多信息,参见???。注意,这个符号只有在你传递--no-ignore选项给svn status时才显示,否则文件会被忽略,根本不列出来。

第二列表明了一个文件或目录的属性集的状态(更多的关于属性的信息参见???)。如果M出现在第二列,表明属性集被修改了,否则会打印一个空白符。

第三列只可能显示空白符或一个L,意味着Subversion已经在.svn工作区里锁定了这个文件。如果你在一个正在执行svn commit 的目录下运行svn status,你会看到这个L——可能这时你在编辑日志文件。如果Subversion没有在运行中,那大概是Subversion进程被中断了,锁需要用svn cleanup(本章稍后会更多涉及这个命令)来解除。

第四列只可能显示空白符或者一个+,意味着这个文件或者目录被预定添加,或者被带着附加的历史修改。这通常发生在当你svn movesvn copy一个文件或目录时。如果你看到A  +,这意味着这一条目被预定带着历史纪录添加。它可能是一个文件,或者一个被复制目录的根。+意味着这个是一个预定被添加的子树的一部分,就是说,它的父目录被复制了,它只是跟着一起走。 M  +意味着这个是一个预定被带着历史纪录添加的子树的一部分,同时 它有本地改动。当你提交时,首先父目录被带着历史纪录添加(复制),这意味着这个文件将自动出现在拷贝中。然后本地修改将被上载到拷贝中。

第五列只可能显示空白符,或者是一个S。这表明这个文件或目录已经被从工作副本路径切换(使用 svn switch)到一个分支里。

如果你传递一个指定的路径给svn status,它将只给出关于这个条目的信息:

$ svn status stuff/fish.cD      stuff/fish.c

svn status也有一个--verbose (-v)选项,它将显示你工作副本中 每一个条目的状态,即使它没有被修改。

$ svn status --verboseM               44        23    sally     README                44        30    sally     INSTALLM               44        20    harry     bar.c                44        18    ira       stuff                44        35    harry     stuff/trout.cD               44        19    ira       stuff/fish.c                44        21    sally     stuff/thingsA                0         ?     ?        stuff/things/bloo.h                44        36    harry     stuff/things/gloo.c

这是svn status输出的“长形式”。第一列仍旧一样,但是第二列显示的是这个条目的工作修订版。第三和第四列分别显示了本项上次被修改的修订版和谁修改了它。

上面这些对svn status的使用都不会连接资料库,它们仅在本地工作,只要比较.svn 目录中的元数据和工作副本中的数据。最后,有一个--show-updates (-u)选项,它连接资料库来添加关于哪些东西过时了的信息。

$ svn status --show-updates --verboseM      *        44        23    sally     READMEM               44        20    harry     bar.c       *        44        35    harry     stuff/trout.cD               44        19    ira       stuff/fish.cA                0         ?     ?        stuff/things/bloo.hStatus against revision:   46

注意:这两个星号表明,如果你这时执行svn update,你将接收到READMEtrout.c的修改。这给了你一些很有用的信息——你将需要更新并得到服务器上的改动,否则资料库将拒绝你的提交,因为你的文件过时了(稍后有更多关于这个主题的信息)。

svn diff

另一个检查你的修改的办法是使用svn diff命令。你能精确的发现你修改的东西,只要执行不带参数的svn diff,这将用标准化的diff格式打印文件改动: [2]

$ svn diffIndex: bar.c===================================================================--- bar.c(revision 3)+++ bar.c(working copy)@@ -1,7 +1,12 @@+#include <sys/types.h>+#include <sys/stat.h>+#include <unistd.h>++#include <stdio.h> int main(void) {-  printf("Sixty-four slices of American Cheese.../n");+  printf("Sixty-five slices of American Cheese.../n"); return 0; }Index: README===================================================================--- README(revision 3)+++ README(working copy)@@ -193,3 +193,4 @@ +Note to self:  pick up laundry.Index: stuff/fish.c===================================================================--- stuff/fish.c(revision 1)+++ stuff/fish.c(working copy)-Welcome to the file known as 'fish'.-Information on fish will be here soon.Index: stuff/things/bloo.h===================================================================--- stuff/things/bloo.h(revision 8)+++ stuff/things/bloo.h(working copy)+Here is a new file to describe+things about bloo.

svn diff命令通过比较你的工作文件和缓存在.svn区中的“原始的” 拷贝来产生输出。预定要添加的文件被显示为所有文本都是新加的,预定要删除的文件被显示为所有文本都被删除。

输出以标准化 diff 格式输出。就是说:删除的行以-开头,添加的行以+开头。 svn diff也打印文件名和偏移量这样对patch程序有用的信息。这样使你能把diff输出重定向到一个文件中来产生“补丁(patch)”。

$ svn diff > patchfile

例如,在提交前,你可以用电子邮件把补丁文件发送给另一个开发者来检查或者测试。

svn revert

现在假设你看到了以上的diff输出,而且察觉到你对README的修改是错的;可能你不小心在你的编辑器里把文字输错了文件。

这是一个极好的使用svn revert的机会。

$ svn revert READMEReverted 'README'

Subversion用.svn区里缓存的“原始的”文件覆盖文件,从而把它恢复到修改前的样子。但是也要注意到svn revert可以撤销任何 预定操作——例如,你可以决定你不想添加某个文件了:

$ svn status foo?      foo$ svn add fooA         foo$ svn revert fooReverted 'foo'$ svn status foo?      foo

注意

svn revert ITEM和从你的工作副本中删除ITEM,然后执行svn update -r BASE ITEM效果完全一样。然而,如果你要恢复一个文件,svn revert有一个非常值得注意的特性——它恢复文件不需要和资料库通信。

或者,可能你错误的把一个文件从版本控制中拿掉了:

$ svn status README        README$ svn delete README D         README$ svn revert READMEReverted 'README'$ svn status README       README

解决冲突(合并别人的修改)

我们已经看到svn status -u怎样预报冲突。设想你执行了svn update并看到一些有趣的现象:

$ svn updateU  INSTALLG  READMEC  bar.cUpdated to revision 46.

标记UG没有什么好关心的;这些文件干净利索的吸收了来自资料库的修改。标记为U的文件没有本地修改,而是被资料库中的修改更新(Updated)了。G 代表合并(merGed),这意味着本地文件被修改了,但是来自于资料库的改动和本地修改不重叠。

但是C代表冲突,这意味着来自服务器的修改和你的修改重叠了,现在你必须手工来选择它们。

任何冲突发生时,通常会有三样东西来帮助你注意到和解决这冲突:

  • Subversion在更新时打印C,并记录这个文件是处在冲突状态。

  • 如果Subversion认为这个文件可以被合并,它会放置一个conflict markers冲突标记——用来划定“边界”的特殊的字符串—— 到这个文件中,以使重叠区域可被看到。(Subversion使用svn:mime-type属性来决定一个文件是否能在上下文中基于行来合并。参见???)

  • 对每个冲突的文件,Subversion会在你的工作副本里放三个额外地没有版本化的文件。

    filename.mine

    这是在你更新工作副本前存在于你的工作副本中的文件——就是说,没有冲突标记。这个文件只有你最后的修改。(如果Subversion认为这个文件没法被合并,那么.mine文件不会被创建,反正它将和你的工作文件一样。)

    filename.rOLDREV

    这是你更新工作副本前的BASE修订版的文件。就是说,在你做最后的编辑前检出的文件。

    filename.rNEWREV

    这个是当你更新了你的工作副本时,Subversion客户程序刚刚从服务器接收到的文件。这个文件对应与资料库中的HEAD修订版。

    这里OLDREV是在你.svn的文件的修订版号, NEWREV是资料库中HEAD的修订版号。

例如,Sally修改了资料库中的文件sandwich.txt。Harry刚修改了自己工作副本中的这个文件并且检入了它。 Sally在检入前更新她的工作副本并发现了一个冲突:

$ svn updateC  sandwich.txtUpdated to revision 2.$ ls -1sandwich.txtsandwich.txt.minesandwich.txt.r1sandwich.txt.r2

这时,Subversion 将允许你提交文件sandwich.txt,直到三个临时文件被删除。

$ svn commit --message "Add a few more things"svn: Commit failed (details follow):svn: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict

如果你发现一个冲突,你需要做下面三件事之一:

  • 手工”合并冲突的文本(检查并编辑文件中的冲突标记)。

  • 用临时文件中的某个覆盖你的工作文件。

  • 执行svn revert <filename>来扔掉你的所有本地修改。

一旦你解决了冲突,你要执行svn resolved让Subversion知道。这个命令删除那三个临时文件并让Subversion不再认为那个文件在冲突状态。 [3]

$ svn resolved sandwich.txtResolved conflicted state of 'sandwich.txt'

手动合并冲突

当你第一次尝试的时候,手动合并冲突可能很难,但在有了些实践后,它就易如反掌了。

这儿有个例子。由于沟通不好,你和你的合作者Sally,同时编辑了文件sandwich.txt。Sally 提交了它的修改,当你更新工作副本时,你发现一个冲突。我们将不得不比编辑sandwich.txt来解决冲突。首先,我们来看一下文件:

$ cat sandwich.txtTop piece of breadMayonnaiseLettuceTomatoProvolone<<<<<<< .mineSalamiMortadellaProsciutto=======SauerkrautGrilled Chicken>>>>>>> .r2Creole MustardBottom piece of bread

由小于号,等号和大于号组成的字符串就是冲突标记,他们不是真正冲突数据的一部份。你只要确认在下次提交前从文件中删除他们。在头两个标记行之间的文字是冲突区域里属于你的修改的部分:

<<<<<<< .mineSalamiMortadellaProsciutto=======

在第二和第三个标记行之间的文字来自Sally的提交:

=======SauerkrautGrilled Chicken>>>>>>> .r2

通常,你不会只是想删除冲突标记和Sally的修改——当三明治送达但不是她想要的那种时她会非常吃惊的—— 因此,这是你应该拿起电话或者走过去,向Sally解释不可能从意大利熟食店买到泡菜。[4] 一旦你们在修改上达成一致,你可以检入了,编辑你的文件并且删除冲突标记。

Top piece of breadMayonnaiseLettuceTomatoProvoloneSalamiMortadellaProsciuttoCreole MustardBottom piece of bread

现在,执行svn resolved,然后你就可以提交你的修改了:

$ svn resolved sandwich.txt$ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."

记住,如果你编辑冲突文件时一时糊涂了,你总是可以参考Subversion在工作副本中为你创建的三个文件 ——包括了你更新前的文件。你甚至能用第三方的交互式合并工具检查这三个文件。

用一个文件覆盖你的工作文件

如果你发现一个冲突并决定放弃你的修改,你可以简单的用Subversion创建的临时文件之一覆盖你工作副本中的文件。

$ svn updateC  sandwich.txtUpdated to revision 2.$ ls sandwich.*sandwich.txt  sandwich.txt.mine  sandwich.txt.r2  sandwich.txt.r1$ cp sandwich.txt.r2 sandwich.txt$ svn resolved sandwich.txt

使用svn revert

如果你发现一个冲突,检查后决定你要放弃你的修改并重新编辑文件,只要撤回你的修改:

$ svn revert sandwich.txtReverted 'sandwich.txt'$ ls sandwich.*sandwich.txt

注意,当你恢复一个冲突文件时,你不一定要执行svn resolved

现在你准备好检入你的修改了。注意svn resolved不像我们在本章介绍过的其他命令,它总是需要一个参数。在任何情况下,你都要小心,只在你确定你已经解决了冲突时才运行svn resolved,一旦临时文件被删除了,即使文件还包含冲突标记,Subversion也允许你提交它。

提交你的修改

终于!你的编辑完成了,你已经合并了所有来自服务器的修改,你已经做好把你的修改提交到资料库的准备了。

svn commit把你的所有修改发送到资料库。当你提交一个修改,你要提供一个日志消息来描述你的修改。你的日志消息会被附加到你创建的新修订版上。如果你的日志消息简短,你可以使用--message (或 -m)在命令行中提供:

$ svn commit --message "Corrected number of cheese slices."Sending        sandwich.txtTransmitting file data .Committed revision 3.

然而,如果在你工作时以已经编写了日志消息,你可以告诉Subversion从一个文件来得到消息,这要用--file选项传递文件名:

$ svn commit --file logmsg Sending        sandwich.txtTransmitting file data .Committed revision 4.

如果你既没有指定--message,也没有指定--file,Subversion会自动运行你喜好的编辑器(参见???中editor-cmd一节)来让你编写一个日志。

提示

如果你在你的编辑器中写提交消息时决定取消你的提交,你只要退出你的编辑器而不保存修改就行了。如果你已经保存了提交消息,只要删除文字再次保存。

$ svn commitWaiting for Emacs...DoneLog message unchanged or not specifieda)bort, c)ontinue, e)dita$

资料库不知道也不关心你的提交作为一个整体是否有意义;它只检查确认在你没有看资料库时,其他人没有修改过你修改了的那些文件。如果有人这么做了,整个提交会失败,并有一个消息通知你,你的某个或某些文件过时了。

$ svn commit --message "Add another rule"Sending        rules.txtsvn: Commit failed (details follow):svn: Out of date: 'rules.txt' in transaction 'g'

这时,你需要运行svn update,处理更新结果中的所有合并和冲突,然后再次尝试提交。

到这里已经探讨了使用Subversion的基本工作流程。Subversion有很多别的特性,你可用它们来管理的你的资料库和工作副本,但即时只使用我们到本章这里为止讨论过的命令,你也能很轻松的工作。



[1] 当然,没有什么会被从资料库完全删除——仅仅是从资料库的HEAD修订版删除了。你可以取回所有你删除的东西,只要检出(或更新你的工作副本)你做删除前的一个修订版就行了。

[2] Subversion使用内置的diff引擎,缺省情况下以标准化diff格式输出。如果你想让diff用不同的格式输出,可以指定一个外部的diff 程序,这需要使用--diff-cmd选项,并用--extensions来传递任何你希望的标志。例如,要检查文件foo.c本地差别,忽略空格,使用上下文输出格式,可使用这样的命令svn diff --diff-cmd /usr/bin/diff --extensions '-bc' foo.c

[3] 你可以自己删掉那些临时文件,但既然Subversion能帮你做,你何必自己做呢?我们认为不必。

[4] And if you ask them for it, they may very well ride you out of town on a rail.

原创粉丝点击