Linux中svn的相关操作

来源:互联网 发布:查域名注册商 编辑:程序博客网 时间:2024/06/07 05:27
安装svn : sudo apt-get install subversion(或者sudo apt-get install rapidsvn)
从svn中下载代码 : svn co http://{svn repository url} /destination 
向svn数据库中提交代码 : svn commit -m path-to-commit,其中path-to-commit可以为空,成功后会提示更新后的版本号。 

更新本地代码 : svn update




http://i18n-zh.googlecode.com/svn-history/r1200/www/svnbook/zh/svn.tour.html
现在,我们将要深入到Subversion的使用细节当中,完成本章时,你将学会所有Subversion日常使用的命令,你将从把数据导入到Subversion开始,接着是初始化的检出(check out),然后是做出修改并检查,你也将会学到如何在工作副本中获取别人的修改,检查他们,并解决所有可能发生的冲突。


Note that this chapter is not meant to be an exhaustive list of all of Subversion's commands—rather, it's a conversational introduction to the most common Subversion tasks that you'll encounter. This chapter assumes that you've read and understood 第 1 章 基本概念 and are familiar with the general model of Subversion. For a complete reference of all commands, see 第 9 章 Subversion 完全参考.


2.1. 求助!


Before reading on, here is the most important command you'll ever need when using Subversion: svn help. The Subversion command-line client is self-documenting—at any time, a quick svn help subcommand will describe the syntax, options, and behavior of the subcommand.


$ svn help import
import: Commit an unversioned file or tree into the repository.
usage: import [PATH] URL


  Recursively commit a copy of PATH to URL.
  If PATH is omitted '.' is assumed.
  Parent directories are created as necessary in the repository.
  If PATH is a directory, the contents of the directory are added
  directly under URL.
  Unversionable items such as device files and pipes are ignored
  if --force is specified.


Valid options:
  -q [--quiet]             : print nothing, or only summary information
  -N [--non-recursive]     : obsolete; try --depth=files or --depth=immediates
  --depth ARG              : limit operation by depth ARG ('empty', 'files',
                             'immediates', or 'infinity')

选项(Options)、开关(Switches)和标志(Flags),天呐!


The Subversion command-line client has numerous command modifiers (which we call options), but there are two distinct kinds of options: short options are a single hyphen followed by a single letter, and long options consist of two hyphens followed by a number of letters (e.g., -s and --this-is-a-long-option, respectively). Every option has a long format, but only certain options have an additional short format (these are typically options that are frequently used). To maintain clarity, we usually use the long form in code examples, but when describing options, if there's a short form, we'll provide the long form (to improve clarity) and the short form (to make it easier to remember). You should use whichever one you're more comfortable with, but don't try to use both.


2.2. 导入数据到你的版本库


You can get new files into your Subversion repository in two ways: svn import and svn add. We'll discuss svn import now and will discuss svn add later in this chapter when we review a typical day with Subversion.


2.2.1. svn import


The svn import command is a quick way to copy an unversioned tree of files into a repository, creating intermediate directories as necessary. svn import doesn't require a working copy, and your files are immediately committed to the repository. You typically use this when you have an existing tree of files that you want to begin tracking in your Subversion repository. For example:


$ svnadmin create /var/svn/newrepos
$ svn import mytree file:///var/svn/newrepos/some/project \
             -m "Initial import"
Adding         mytree/foo.c
Adding         mytree/bar.c
Adding         mytree/subdir
Adding         mytree/subdir/quux.h


Committed revision 1.
在上一个例子里,将会拷贝目录mytree到版本库的some/project下:


$ svn list file:///var/svn/newrepos/some/project
bar.c
foo.c
subdir/
注意,在导入之后,原来的目录树并没有转化成工作副本,为了开始工作,你还是需要运行svn checkout导出一个工作副本。


2.2.2. 推荐的版本库布局


While Subversion's flexibility allows you to lay out your repository in any way that you choose, we recommend that you create a trunk directory to hold the “main line” of development, a branches directory to contain branch copies, and a tags directory to contain tag copies. For example:


$ svn list file:///var/svn/repos
/trunk
/branches
/tags
你将会在第 4 章 分支与合并看到标签和分支的详细内容,关于设置多个项目的信息,可以看第 4.7.1 节 “版本库布局”和第 5.2.1 节 “规划你的版本库结构”中关于“项目根目录”的内容。


2.3. 初始化检出


大多数时候,你会使用checkout从版本库取出一个新拷贝开始使用Subversion,这样会在本机创建一个项目的“本地拷贝”,这个拷贝包括了命令行指定版本库中的HEAD(最新的)版本:


$ svn checkout http://svn.collab.net/repos/svn/trunk
A    trunk/Makefile.in
A    trunk/ac-helpers
A    trunk/ac-helpers/install.sh
A    trunk/ac-helpers/install-sh
A    trunk/build.conf

Checked out revision 8810.
名称中有什么?


Subversion努力控制版本控制下数据的类型,文件的内容和属性值都是按照二进制数据存储和传递,并且第 3.3.1 节 “文件内容类型”给Subversion提示以说明对于特定文件“文本化的”操作是没有意义的,也有一些地方,Subversion对存放的信息有限制。


Subversion internally handles certain bits of data—for example, property names, pathnames, and log messages—as UTF-8-encoded Unicode. This is not to say that all your interactions with Subversion must involve UTF-8, though. As a general rule, Subversion clients will gracefully and transparently handle conversions between UTF-8 and the encoding system in use on your computer, if such a conversion can meaningfully be done (which is the case for most common encodings in use today).


In WebDAV exchanges and older versions of some of Subversion's administrative files, paths are used as XML attribute values, and property names in XML tag names. This means that pathnames can contain only legal XML (1.0) characters, and properties are further limited to ASCII characters. Subversion also prohibits TAB, CR, and LF characters in path names to prevent paths from being broken up in diffs or in the output of commands such as svn log or svn status.


While it may seem like a lot to remember, in practice these limitations are rarely a problem. As long as your locale settings are compatible with UTF-8 and you don't use control characters in path names, you should have no trouble communicating with Subversion. The command-line client adds an extra bit of help—to create “legally correct” versions for internal use it will automatically escape illegal path characters as needed in URLs that you type.


Although the preceding example checks out the trunk directory, you can just as easily check out any deep subdirectory of a repository by specifying the subdirectory in the checkout URL:


$ svn checkout \
      http://svn.collab.net/repos/svn/trunk/subversion/tests/cmdline/
A    cmdline/revert_tests.py
A    cmdline/diff_tests.py
A    cmdline/autoprop_tests.py
A    cmdline/xmltests
A    cmdline/xmltests/svn-test.sh

Checked out revision 8810.
Since Subversion uses a copy-modify-merge model instead of lock-modify-unlock (see 第 1.2 节 “版本模型”), you can immediately make changes to the files and directories in your working copy. Your working copy is just like any other collection of files and directories on your system. You can edit and change it, move it around, even delete the entire working copy and forget about it.


警告
因为你的工作副本“同你系统上的文件和目录没有任何区别”,你可以随意修改文件,但是你必须告诉Subversion你做的其他任何事。例如,你希望拷贝或移动工作副本的一个文件,你应该使用svn copy或者 svn move而不要使用操作系统的拷贝移动命令,我们会在本章后面详细介绍。


除非你准备好了提交一个新文件或目录,或改变了已存在的,否则没有必要通知Subversion你做了什么。


目录 .svn 中有什么?


工作副本中的任何一个目录包括一个名为.svn管理区域,通常列表操作不显示这个目录,但它仍然是一个非常重要的目录,无论你做什么?不要删除或是更改这个管理区域的任何东西,Subversion使用它来管理工作副本。


If you accidentally remove the .svn subdirectory, the easiest way to fix the problem is to remove the entire containing directory (a normal system deletion, not svn delete), then run svn update from a parent directory. The Subversion client will download the directory you've deleted, with a new .svn area as well.


因为你可以使用版本库的URL作为唯一参数取出一个工作副本,你也可以在版本库URL之后指定一个目录,这样会将你的工作目录放到你的新目录,举个例子:


$  svn checkout http://svn.collab.net/repos/svn/trunk subv
A    subv/Makefile.in
A    subv/ac-helpers
A    subv/ac-helpers/install.sh
A    subv/ac-helpers/install-sh
A    subv/build.conf

Checked out revision 8810.
这样将把你的工作副本放到subv而不是和前面那样放到trunk,如果subv不存在,将会自动创建。


2.3.1. 禁用密码缓存


When you perform a Subversion operation that requires you to authenticate, by default Subversion tries to cache your authentication credentials on disk in encrypted form. On some systems, Subversion may be unable to encrypt your authentication data. You will then be asked whether you want to cache your credentials to disk in plaintext. You can choose to do so for convenience so that you don't have to continually reenter your password for future operations. If you're concerned about caching your Subversion passwords in plaintext and do not want to be asked about it again and again, you can disable caching of plaintext passwords either permanently, or on a server-per-server basis.


To permanently disable caching of passwords in plaintext, you can add the line store-plaintext-passwords = no to the global section in the servers configuration file on the local machine. To disable caching of plaintext passwords for a particular server, use the same setting in the appropriate group section in the servers configuration file. See 第 7.1.3 节 “配置选项” in 第 7 章 定制你的 Subversion 体验 for details.


You can also disable caching of authentication credentials entirely, regardless of whether the credentials are stored in encrypted form or not.


To disable password caching entirely for a particular one-time command, pass the --no-auth-cache option on the command line. To permanently disable caching entirely, you can add the line store-passwords = no to your local machine's Subversion configuration file. See 第 3.11.2 节 “客户端凭证缓存” for details.


2.3.2. 认证为其它用户


Since Subversion caches auth credentials by default (both username and password), it conveniently remembers who you were acting as the last time you modified your working copy. But sometimes that's not helpful—particularly if you're working in a shared working copy such as a system configuration directory or a web server document root. In this case, just pass the --username option on the command line, and Subversion will attempt to authenticate as that user, prompting you for a password if necessary.


2.4. 基本的工作循环


Subversion has numerous features, options, bells, and whistles, but on a day-to-day basis, odds are that you will use only a few of them. In this section, we'll run through the most common things that you might find yourself doing with Subversion in the course of a day's work.


典型的工作周期是这样的:


更新你的工作副本。


svn update


做出修改


svn add


svn delete


svn copy


svn move


检验修改


svn status


svn diff


可能会取消一些修改


svn revert


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


svn update


svn resolve


提交你的修改


svn commit


2.4.1. 更新你的工作副本


When working on a project with a team, you'll want to update your working copy to receive any changes other developers on the project have made since your last update. Use svn update to bring your working copy into sync with the latest revision in the repository:


$ svn update
U  foo.c
U  bar.c
Updated to revision 2.
这种情况下,其他人在你上次更新之后提交了对foo.c和bar.c的修改,因此Subversion更新你的工作副本来引入这些更改。


When the server sends changes to your working copy via svn update, a letter code is displayed next to each item to let you know what actions Subversion performed to bring your working copy up to date. To find out what these letters mean, run svn help update.


2.4.2. 修改你的工作副本


Now you can get to work and make changes in your working copy. It's usually most convenient to decide on a discrete change (or set of changes) to make, such as writing a new feature, fixing a bug, and so on. The Subversion commands that you will use here are svn add, svn delete, svn copy, svn move, and svn mkdir. However, if you are merely editing files that are already in Subversion, you may not need to use any of these commands until you commit.


You can make two kinds of changes to your working copy: file changes and tree changes. You don't need to tell Subversion that you intend to change a file; just make your changes using your text editor, word processor, graphics program, or whatever tool you would normally use. Subversion automatically detects which files have been changed, and in addition, it handles binary files just as easily as it handles text files—and just as efficiently, too. For tree changes, you can ask Subversion to “mark” files and directories for scheduled removal, addition, copying, or moving. These changes may take place immediately in your working copy, but no additions or removals will happen in the repository until you commit them.


版本控制符号连接


在非Windows平台,Subversion可以将特殊类型符号链接(或是“symlink”)版本化,一个符号链接是对文件系统中其他对象的透明引用,可以通过对符合链接操作实现对引用对象的读写操作。


当符号链提交到Subversion版本库,Subversion会记住这个文件实际上是一个符号链,也会知道这个符号链指向的“对象”。当这个符号链检出到另一个支持符号链的操作系统上时,Subversion会重新构建文件系统级的符号链接。当然这样不会影响在Windows这类不支持符号链的系统上,在此类系统上,Subversion只会创建一个包含指向对象路径的文本文件,因为这个文件不能在Windows系统上作为符号链使用,所以它也会防止Windows用户作其他Subversion相关的操作。


Here is an overview of the five Subversion subcommands that you'll use most often to make tree changes:


svn add foo
预定将文件、目录或者符号链foo添加到版本库,当你下次提交后,foo会成为其父目录的一个子对象。注意,如果foo是目录,所有foo中的内容也会预定添加进去,如果你只想添加foo本身,请使用--non-recursive (-N)参数。


svn delete foo
预定将文件、目录或者符号链foo从版本库中删除,如果foo是文件,它马上从工作副本中删除,如果是目录,不会被删除,但是Subversion准备好删除了,当你提交你的修改,foo就会在你的工作副本和版本库中被删除。[3]


svn copy foo bar
Create a new item bar as a duplicate of foo and automatically schedule bar for addition. When bar is added to the repository on the next commit, its copy history is recorded (as having originally come from foo). svn copy does not create intermediate directories unless you pass the --parents option.


svn move foo bar
This command is exactly the same as running svn copy foo bar; svn delete foo. That is, bar is scheduled for addition as a copy of foo, and foo is scheduled for removal. svn move does not create intermediate directories unless you pass the --parents option.


svn mkdir blort
This command is exactly the same as running mkdir blort; svn add blort. That is, a new directory named blort is created and scheduled for addition.


不通过工作副本修改版本库


有一些情况下会立刻提交目录树的修改到版本库,这只发生在子命令直接操作URL,而不是工作副本路径时。以特定的方式使用svn mkdir、svn copy、svn move和svn delete可以针对URL操作(并且不要忘记svn import只针对URL操作)。


URL operations behave in this manner because commands that operate on a working copy can use the working copy as a sort of “staging area” to set up your changes before committing them to the repository. Commands that operate on URLs don't have this luxury, so when you operate directly on a URL, any of the aforementioned actions represents an immediate commit.


2.4.3. 检查你的修改


当你完成修改,你需要提交他们到版本库,但是在此之前,检查一下做过什么修改是个好主意,通过提交前的检查,你可以整理一份精确的日志信息,你也可以发现你不小心修改的文件,给了你一次恢复修改的机会。此外,这是一个审查和仔细察看修改的好机会,你可通过命令svn status浏览所做的修改,通过svn diff检查修改的详细信息。


看!没有网络!


You can use the commands svn status, svn diff, and svn revert without any network access even if your repository is across the network. This makes it easy to manage your changes-in-progress when you are somewhere without a network connection, such as traveling on an airplane, riding a commuter train, or hacking on the beach. [4]


Subversion does this by keeping private caches of pristine versions of each versioned file inside the .svn administrative areas. This allows Subversion to report—and revert—local modifications to those files without network access. This cache (called the “text-base”) also allows Subversion to send the user's local modifications during a commit to the server as a compressed delta (or “difference”) against the pristine version. Having this cache is a tremendous benefit—even if you have a fast Internet connection, it's much faster to send only a file's changes rather than the whole file to the server.


Subversion has been optimized to help you with this task, and it is able to do many things without communicating with the repository. In particular, your working copy contains a hidden cached “pristine” copy of each version-controlled file within the .svn area. Because of this, Subversion can quickly show you how your working files have changed or even allow you to undo your changes without contacting the repository.


2.4.3.1. 查看你的修改概况


为了浏览修改的内容,你会使用这个svn status命令,在所有Subversion命令里,svn status可能会是你用的最多的命令。


CVS 用户:控制另类的更新!


你也许使用cvs update来看你做了哪些修改,svn status会给你所有你做的改变—而不需要访问版本库,并且不会在不知情的情况下与其他用户作的更改比较。


In Subversion, svn update does just that—it updates your working copy with any changes committed to the repository since the last time you updated your working copy. You may have to break the habit of using the update command to see what local modifications you've made.


If you run svn status at the top of your working copy with no arguments, it will detect all file and tree changes you've made. Here are a few examples of the most common status codes that svn status can return. (Note that the text following # is not actually printed by svn status.)


?       scratch.c           # file is not under version control
A       stuff/loot/bloo.h   # file is scheduled for addition
C       stuff/loot/lump.c   # file has textual conflicts from an update
D       stuff/fish.c        # file is scheduled for deletion
M       bar.c               # the content in bar.c has local modifications
在这种格式下,svn status打印6列字符,紧跟一些空格,接着是文件或者目录名。第一列告诉一个文件或目录的状态或它的内容,返回代码如下:


A item
预定加入到版本库的文件、目录或符号链的item。


C item
文件item发生冲突,在从服务器更新时与工作副本(如果更新时没有解决)的本地版本发生交迭,在你提交到版本库前,必须手工的解决冲突。


D item
文件、目录或是符号链item预定从版本库中删除。


M item
文件item的内容被修改了。


如果你传递一个路径给svn status,它只给你这个项目的信息:


$ svn status stuff/fish.c
D      stuff/fish.c
svn status也有一个--verbose(-v)选项,它可以显示工作副本中的所有项目,即使没有改变过的:


$ svn status -v
M               44        23    sally     README
                44        30    sally     INSTALL
M               44        20    harry     bar.c
                44        18    ira       stuff
                44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
                44        21    sally     stuff/things
A                0         ?     ?        stuff/things/bloo.h
                44        36    harry     stuff/things/gloo.c
这是svn status的“加长形式”,第一列保持相同,第二列显示一个工作版本号,第三和第四列显示最后一次修改的版本号和修改人(这些列不会与我们刚才提到的字符混淆)。


上面所有的svn status调用并没有联系版本库,只是与.svn中的原始数据进行比较的结果,最后,是--show-updates(-u)选项,它将会联系版本库为已经过时的数据添加新信息:


$ svn status -u -v
M      *        44        23    sally     README
M               44        20    harry     bar.c
       *        44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
A                0         ?     ?        stuff/things/bloo.h
Status against revision:   46
Notice the two asterisks: if you were to run svn update at this point, you would receive changes to README and trout.c. This tells you some very useful information—you'll need to update and get the server changes on README before you commit, or the repository will reject your commit for being out of date (more on this subject later).


关于文件和目录,svn status可以比我们的展示显示更多的内容,svn status完整的描述可以看svn status。


2.4.3.2. 检查你的本地修改的详情


Another way to examine your changes is with the svn diff command. You can find out exactly how you've modified things by running svn diff with no arguments, which prints out file changes in unified diff format:


$ svn diff
Index: 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的“原始”文件来输出信息,预定要增加的文件会显示所有增加的文本,要删除的文件会显示所有要删除的文本。


输出的格式为统一区别格式(unified diff format),删除的行前面加一个-,添加的行前面有一个+,svn diff命令也打印文件名和打补丁需要的信息,所以你可以通过重定向一个区别文件来生成“补丁”:


$ svn diff > patchfile
You could, for example, email the patch file to another developer for review or testing prior to a commit.


Subversion uses its internal diff engine, which produces unified diff format, by default. If you want diff output in a different format, specify an external diff program using --diff-cmd and pass any flags you'd like to it using the --extensions (-x) option. For example, to see local differences in file foo.c in context output format while ignoring case differences, you might run svn diff --diff-cmd /usr/bin/diff --extensions '-i' foo.c.


2.4.4. 取消本地修改


假定我们在看svn diff的输出,你发现对某个文件的所有修改都是错误的,或许你根本不应该修改这个文件,或者是从开头重新修改会更加容易。


这是使用svn revert的好机会:


$ svn revert README
Reverted 'README'
Subversion把文件恢复到未修改的状态,叫做.svn目录的“原始”拷贝,应该知道svn revert可以恢复任何预定要做的操作,举个例子,你不再想添加一个文件:


$ svn status foo
?      foo


$ svn add foo
A         foo


$ svn revert foo
Reverted 'foo'


$ svn status foo
?      foo
注意
svn revert item has exactly the same effect as deleting item from your working copy and then running svn update -r BASE item. However, if you're reverting a file, svn revert has one very noticeable difference—it doesn't have to communicate with the repository to restore your file.


或许你不小心删除了一个文件:


$ svn status README


$ svn delete README
D         README


$ svn revert README
Reverted 'README'


$ svn status README
2.4.5. 解决冲突(合并别人的修改)


We've already seen how svn status -u can predict conflicts. Suppose you run svn update and some interesting things occur:


$ svn update
U  INSTALL
G  README
Conflict discovered in 'bar.c'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (h) help for more options:
U和G没必要关心,文件干净的接受了版本库的变化,文件标示为U表明本地没有修改,文件已经根据版本库更新。G标示合并,标示本地已经修改过,与版本库没有重迭的地方,已经合并。


但是下面两行是叫做交互式的冲突解决特性(Subversion 1.5最新的)的一部分,这意味着服务器的变更和你的重叠了,而你有机会解决这个冲突,最常用的选项会显示,但是你可以输入h显示全部选项:



  (p)  postpone    - mark the conflict to be resolved later
  (df) diff-full   - show all changes made to merged file
  (e)  edit        - change merged file in an editor
  (r)  resolved    - accept merged version of file
  (mf) mine-full   - accept my version of entire file (ignore their changes)
  (tf) theirs-full - accept their version of entire file (lose my changes)
  (l)  launch      - launch external tool to resolve conflict
  (h)  help        - show this list
在我们详细查看每个选项含义之前,让我们简短的回顾一下所有这些选项。


(p)ostpone
让文件在更新完成之后保持冲突状态。


(d)iff-(f)ull
使用标准区别格式显示base修订版本和冲突文件本身的区别。


(e)dit
用你喜欢的编辑器打开冲突的文件,编辑器是环境变量EDITOR设置的。


(r)esolved
完成文件编辑之后,通知svn你已经解决了文件的冲突,它必须接受当前的内容—从本质上讲就是你已经“解决了”冲突。


(m)ine-(f)ull
丢弃新从服务器接收的变更,并只使用你查看文件的本地修改。


(t)heirs-(f)ull
丢弃你对查看文件的本地修改,只使用从服务器新接收的变更。


(l)aunch
启动一个外置程序来执行冲突解决,这需要一些预先的准备。


(h)elp
显示所有在冲突解决时可能使用的命令。


我们现在会更详细的覆盖这些命令,根据关联功能对其进行分组。


2.4.5.1. 交互式的查看冲突区别


Before deciding how to attack a conflict interactively, odds are that you'd like to see exactly what is in conflict, and the diff-full command (df) is what you'll use for this:



Select: (p) postpone, (df) diff-full, (e) edit,
        (h)elp for more options : df
--- .svn/text-base/sandwich.txt.svn-base      Tue Dec 11 21:33:57 2007
+++ .svn/tmp/tempfile.32.tmp     Tue Dec 11 21:34:33 2007
@@ -1 +1,5 @@
-Just buy a sandwich.
+<<<<<<< .mine
+Go pick up a cheesesteak.
+=======
+Bring me a taco!
+>>>>>>> .r32

区别内容的第一行显示的是工作副本(BASE修订版本)以前的内容,下一行内容是你的修改,最后的一行内容是你刚从服务器(通常是HEAD修订版本)接收的。手上有了信息,你已经准备好了做下一个动作。


2.4.5.2. 交互式的解决冲突区别


交互式解决冲突有四个不同的方式—两个是允许你选择性的合并和编辑修改,两个是允许你简单的选一个文件的版本并继续。


If you wish to choose some combination of your local changes, you can use the “edit” command (e) to manually edit the file with conflict markers in a text editor (determined by the EDITOR environment variable). Editing the file by hand in your favorite text editor is a somewhat low-tech way of remedying conflicts (see 第 2.4.5.4 节 “手工合并冲突” for a walkthrough), so some people like to use fancy graphical merge tools instead.


To use a merge tool, you need to either set the SVN_MERGE environment variable or define the merge-tool-cmd option in your Subversion configuration file (see 第 7.1.3 节 “配置选项” for more details). Subversion will pass four arguments to the merge tool: the BASE revision of the file, the revision of the file received from the server as part of the update, the copy of the file containing your local edits, and the merged copy of the file (which contains conflict markers). If your merge tool is expecting arguments in a different order or format, you'll need to write a wrapper script for Subversion to invoke. After you've edited the file, if you're satisfied with the changes you've made, you can tell Subversion that the edited file is no longer in conflict by using the “resolve” command (r).


If you decide that you don't need to merge any changes, but just want to accept one version of the file or the other, you can either choose your changes (a.k.a. “mine”) by using the “mine-full” command (mf) or choose theirs by using the “theirs-full” command (tf).


2.4.5.3. 延后解决冲突


This may sound like an appropriate section for avoiding marital disagreements, but it's actually still about Subversion, so read on. If you're doing an update and encounter a conflict that you're not prepared to review or resolve, you can type p to postpone resolving a conflict on a file-by-file basis when you run svn update. If you're running an update and don't want to resolve any conflicts, you can pass the --non-interactive option to svn update, and any file in conflict will be marked with a C automatically.


但是C表示冲突,说明服务器上的改动同你的改动冲突了,你需要在更新完成自己手工去解决。当你选择延后解决冲突,svn通常会做三件事来辅助通知你解决冲突。


Subversion在更新时打印C标记,并且标记这个文件已冲突。


If Subversion considers the file to be mergeable, it places conflict markers—special strings of text that delimit the “sides” of the conflict—into the file to visibly demonstrate the overlapping areas. (Subversion uses the svn:mime-type property to decide whether a file is capable of contextual, line-based merging. See 第 3.3.1 节 “文件内容类型” to learn more.)


对于每一个冲突的文件,Subversion放置三个额外的未版本化文件到你的工作副本:


filename.mine
This is your file as it existed in your working copy before you updated your working copy—that is, without conflict markers. This file has only your latest changes in it. (If Subversion considers the file to be unmergeable, the .mine file isn't created, since it would be identical to the working file.)


filename.rOLDREV
这是你的做更新操作以前的BASE版本文件,就是你在上次更新之后未作更改的版本。


filename.rNEWREV
这是你的Subversion客户端从服务器刚刚收到的版本,这个文件对应版本库的HEAD版本。


这里OLDREV是你的.svn目录中的修订版本号,NEWREV是版本库中HEAD的版本号。


For example, Sally makes changes to the file sandwich.txt, but does not yet commit those changes. Meanwhile, Harry commits changes to that same file. Sally updates her working copy before committing and she gets a conflict, which she postpones:


$ svn update
Conflict discovered in 'sandwich.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (h)elp for more options : p
C  sandwich.txt
Updated to revision 2.
$ ls -1
sandwich.txt
sandwich.txt.mine
sandwich.txt.r1
sandwich.txt.r2
At this point, Subversion will not allow Sally to commit the file sandwich.txt until the three temporary files are removed:


$ svn commit -m "Add a few more things"
svn: Commit failed (details follow):
svn: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict
如果你延办一个冲突,你需要在Subversion允许你提交你的修改之前解决冲突,你可以通过svn resolve命令和--accept选项的多个参数的一个完成。


如果你希望选择上次检出后修改之前的文件版本,选择base参数。


如果你希望选择只包含你修改的版本,选择mine-full参数。


如果你希望选择最近从服务器更新的版本(因此会丢弃你的所以编辑),选择theirs-full参数。


然而,如果你希望


svn resolve removes the three temporary files and accepts the version of the file that you specified with the --accept option, and Subversion no longer considers the file to be in a state of conflict:


$ svn resolve --accept working sandwich.txt
Resolved conflicted state of 'sandwich.txt'
2.4.5.4. 手工合并冲突


第一次尝试解决冲突让人感觉很害怕,但经过一点训练,它简单的像是骑着车子下坡。


Here's an example. Due to a miscommunication, you and Sally, your collaborator, both edit the file sandwich.txt at the same time. Sally commits her changes, and when you go to update your working copy, you get a conflict and you're going to have to edit sandwich.txt to resolve the conflict. First, let's take a look at the file:


$ cat sandwich.txt
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Creole Mustard
Bottom piece of bread
The strings of less-than signs, equals signs, and greater-than signs are conflict markers and are not part of the actual data in conflict. You generally want to ensure that those are removed from the file before your next commit. The text between the first two sets of markers is composed of the changes you made in the conflicting area:


<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
后两组之间的是Sally提交的修改冲突:


=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Usually you won't want to just delete the conflict markers and Sally's changes—she's going to be awfully surprised when the sandwich arrives and it's not what she wanted. This is where you pick up the phone or walk across the office and explain to Sally that you can't get sauerkraut from an Italian deli. [5] Once you've agreed on the changes you will commit, edit your file and remove the conflict markers:


Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Creole Mustard
Bottom piece of bread
Now use svn resolve, and you're ready to commit your changes:


$ svn resolve --accept working sandwich.txt
Resolved conflicted state of 'sandwich.txt'
$ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."
Note that svn resolve, unlike most of the other commands we deal with in this chapter, requires that you explicitly list any filenames that you wish to resolve. In any case, you want to be careful and use svn resolve only when you're certain that you've fixed the conflict in your file—once the temporary files are removed, Subversion will let you commit the file even if it still contains conflict markers.


记住,如果你修改冲突时感到混乱,你可以参考subversion生成的三个文件—包括你未作更新的文件。你也可以使用三方交互合并工具检验这三个文件。


2.4.5.5. 丢弃你的修改而接收新获取的修订版本


If you get a conflict and decide that you want to throw out your changes, you can run svn resolve --accept theirs-full CONFLICTED-PATH and Subversion will discard your edits and remove the temporary files:


$ svn update
Conflict discovered in 'sandwich.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (h) help for more options: p
C    sandwich.txt
Updated to revision 2.
$ ls sandwich.*
sandwich.txt  sandwich.txt.mine  sandwich.txt.r2  sandwich.txt.r1
$ svn resolve --accept theirs-full sandwich.txt
Resolved conflicted state of 'sandwich.txt'
2.4.5.6. 撤销:使用 svn revert


If you decide that you want to throw out your changes and start your edits again (whether this occurs after a conflict or anytime), just revert your changes:


$ svn revert sandwich.txt
Reverted 'sandwich.txt'
$ ls sandwich.*
sandwich.txt
Note that when you revert a conflicted file, you don't have to use svn resolve.


2.4.6. 提交你的修改


最后!你的修改结束了,你合并了服务器上所有的修改,你准备好提交修改到版本库。


The svn commit command sends all of your changes to the repository. When you commit a change, you need to supply a log message describing your change. Your log message will be attached to the new revision you create. If your log message is brief, you may wish to supply it on the command line using the --message (or -m) option:


$ svn commit -m "Corrected number of cheese slices."
Sending        sandwich.txt
Transmitting file data .
Committed revision 3.
然而,如果你把写日志信息当作工作的一部分,你也许会希望告诉Subversion通过一个文件名得到日志信息,使用--file(-F)选项:


$ svn commit -F logmsg
Sending        sandwich.txt
Transmitting file data .
Committed revision 4.
If you fail to specify either the --message or --file option, Subversion will automatically launch your favorite editor (see the information on editor-cmd in 第 7.1.3.2 节 “配置”) for composing a log message.


提示
If you're in your editor writing a commit message and decide that you want to cancel your commit, you can just quit your editor without saving changes. If you've already saved your commit message, simply delete the text, save again, and then abort:


$ svn commit
Waiting for Emacs...Done


Log message unchanged or not specified
(a)bort, (c)ontinue, (e)dit
a
$
The repository doesn't know or care whether your changes make any sense as a whole; it checks only to make sure nobody else has changed any of the same files that you did when you weren't looking. If somebody has done that, the entire commit will fail with a message informing you that one or more of your files are out of date:


$ svn commit -m "Add another rule"
Sending        rules.txt
svn: Commit failed (details follow):
svn: File '/sandwich.txt' is out of date

(错误信息的精确措辞依赖于网络协议和你使用的服务器,但对于所有的情况,其思想完全一样。)


At this point, you need to run svn update, deal with any merges or conflicts that result, and attempt your commit again.


That covers the basic work cycle for using Subversion. Subversion offers many other features that you can use to manage your repository and working copy, but most of your day-to-day use of Subversion will involve only the commands that we've discussed so far in this chapter. We will, however, cover a few more commands that you'll use fairly often.


2.5. 检验历史


你的版本库就像是一台时间机器,它记录了所有提交的修改,允许你检查文件或目录以及相关元数据的历史。通过一个Subversion命令你可以根据时间或修订号取出一个过去的版本(或者恢复现在的工作副本),然而,有时候我们只是想看看历史而不想回到历史。


Several commands can provide you with historical data from the repository:


svn log
Shows you broad information: log messages with date and author information attached to revisions and which paths changed in each revision


svn diff
Shows line-level details of a particular change


svn cat
Retrieves a file as it existed in a particular revision number and displays it on your screen


svn list
Displays the files in a directory for any given revision


2.5.1. 产生历史修改列表


To find information about the history of a file or directory, use the svn log command. svn log will provide you with a record of who made changes to a file or directory, at what revision it changed, the time and date of that revision, and—if it was provided—the log message that accompanied the commit:


$ svn log
------------------------------------------------------------------------
r3 | sally | 2008-05-15 23:09:28 -0500 (Thu, 15 May 2008) | 1 line


Added include lines and corrected # of cheese slices.
------------------------------------------------------------------------
r2 | harry | 2008-05-14 18:43:15 -0500 (Wed, 14 May 2008) | 1 line


Added main() methods.
------------------------------------------------------------------------
r1 | sally | 2008-05-10 19:50:31 -0500 (Sat, 10 May 2008) | 1 line


Initial import
------------------------------------------------------------------------
注意日志信息缺省根据时间逆序排列,如果希望察看特定顺序的一段修订版本或者单一版本,使用--revision (-r)选项:


$ svn log -r 5:19    # shows logs 5 through 19 in chronological order


$ svn log -r 19:5    # shows logs 5 through 19 in reverse order


$ svn log -r 8       # shows log for revision 8
你也可以检查单个文件或目录的日志历史,举个例子:


$ svn log foo.c

$ svn log http://foo.com/svn/trunk/code/foo.c

这样只会显示这个工作文件(或者URL)做过修订的版本的日志信息。


为什么 svn log 不会显示我刚刚提交的内容?


If you make a commit and immediately type svn log with no arguments, you may notice that your most recent commit doesn't show up in the list of log messages. This is due to a combination of the behavior of svn commit and the default behavior of svn log. First, when you commit changes to the repository, svn bumps only the revision of files (and directories) that it commits, so usually the parent directory remains at the older revision (See 第 1.3.5.1 节 “更新和提交是分开的” for an explanation of why). svn log then defaults to fetching the history of the directory at its current revision, and thus you don't see the newly committed changes. The solution here is to either update your working copy or explicitly provide a revision number to svn log by using the --revision (-r) option.


如果你希望得到目录和文件更多的信息,你可以对svn log命令使用--verbose (-v)开关,因为Subversion允许移动和复制文件和目录,所以跟踪路径修改非常重要,在详细模式下,svn log 输出中会包括一个路径修改的历史:


$ svn log -r 8 -v
------------------------------------------------------------------------
r8 | sally | 2008-05-21 13:19:25 -0500 (Wed, 21 May 2008) | 1 line
Changed paths:
   M /trunk/code/foo.c
   M /trunk/code/bar.h
   A /trunk/code/doc/README


Frozzled the sub-space winch.


------------------------------------------------------------------------
svn log也有一个--quiet (-q)选项,会禁止日志信息的主要部分,当与--verbose结合使用,仅会显示修改的文件名。


为什么 svn log 给我一个空的回应?


当使用Subversion一些时间后,许多用户会遇到这种情况:


$ svn log -r 2
------------------------------------------------------------------------
$
At first glance, this seems like an error. But recall that while revisions are repository-wide, svn log operates on a path in the repository. If you supply no path, Subversion uses the current working directory as the default target. As a result, if you're operating in a subdirectory of your working copy and attempt to see the log of a revision in which neither that directory nor any of its children was changed, Subversion will show you an empty log. If you want to see what changed in that revision, try pointing svn log directly at the topmost URL of your repository, as in svn log -r 2 http://svn.collab.net/repos/svn.


2.5.2. 检查历史修改详情


We've already seen svn diff before—it displays file differences in unified diff format; we used it to show the local modifications made to our working copy before committing to the repository.


事实上,svn diff有三种不同的用法:


检查本地修改


比较工作副本与版本库


比较版本库中的版本


2.5.2.1. 检查本地修改


像我们看到的,不使用任何参数调用时,svn diff 将会比较你的工作文件与缓存在 .svn 的“原始”副本:


$ svn diff
Index: rules.txt
===================================================================
--- rules.txt (revision 3)
+++ rules.txt (working copy)
@@ -1,4 +1,5 @@
 Be kind to others
 Freedom = Responsibility
 Everything in moderation
-Chew with your mouth open
+Chew with your mouth closed
+Listen when others are speaking
$
2.5.2.2. 比较工作副本和版本库


如果传递一个 --revision (-r) 参数,你的工作副本会与版本库中的指定版本比较:


$ svn diff -r 3 rules.txt
Index: rules.txt
===================================================================
--- rules.txt (revision 3)
+++ rules.txt (working copy)
@@ -1,4 +1,5 @@
 Be kind to others
 Freedom = Responsibility
 Everything in moderation
-Chew with your mouth open
+Chew with your mouth closed
+Listen when others are speaking
$
2.5.2.3. 比较版本库中的版本


如果通过 --revision (-r) 传递两个通过冒号分开的版本号,这两个版本会直接比较:


$ svn diff -r 2:3 rules.txt
Index: rules.txt
===================================================================
--- rules.txt (revision 2)
+++ rules.txt (revision 3)
@@ -1,4 +1,4 @@
 Be kind to others
-Freedom = Chocolate Ice Cream
+Freedom = Responsibility
 Everything in moderation
 Chew with your mouth open
$
A more convenient way of comparing one revision to the previous revision is to use the --change (-c) option:


$ svn diff -c 3 rules.txt
Index: rules.txt
===================================================================
--- rules.txt (revision 2)
+++ rules.txt (revision 3)
@@ -1,4 +1,4 @@
 Be kind to others
-Freedom = Chocolate Ice Cream
+Freedom = Responsibility
 Everything in moderation
 Chew with your mouth open
$
最后,即使你在本机没有工作副本,还是可以比较版本库的修订版本,只需要在命令行中输入合适的URL:


$ svn diff -c 5 http://svn.example.com/repos/example/trunk/text/rules.txt

$
2.5.3. 浏览版本库


通过svn cat和svn list,你可以在未修改工作修订版本的情况下查看文件和目录的内容,实际上,你甚至也不需要有一个工作副本。


2.5.3.1. svn cat


如果你只是希望检查一个过去的版本而不希望察看它们的区别,使用svn cat:


$ svn cat -r 2 rules.txt
Be kind to others
Freedom = Chocolate Ice Cream
Everything in moderation
Chew with your mouth open
$
你可以重定向输出到一个文件:


$ svn cat -r 2 rules.txt > rules.txt.v2
$
2.5.3.2. svn list


svn list可以在不下载文件到本地目录的情况下来察看目录中的文件:


$ svn list http://svn.collab.net/repos/svn
README
branches/
clients/
tags/
trunk/
如果你希望察看详细信息,你可以使用--verbose(-v) 参数:


$ svn list -v http://svn.collab.net/repos/svn
  20620 harry            1084 Jul 13  2006 README
  23339 harry                 Feb 04 01:40 branches/
  21282 sally                 Aug 27 09:41 developer-resources/
  23198 harry                 Jan 23 17:17 tags/
  23351 sally                 Feb 05 13:26 trunk/
这些列告诉你文件和目录最后修改的修订版本、做出修改的用户、如果是文件还会有文件的大小,最后是修改日期和项目的名字。


警告
The svn list command with no arguments defaults to the repository URL of the current working directory, not the local working copy directory. After all, if you want a listing of your local directory, you could use just plain ls (or any reasonable non-Unixy equivalent).


2.5.4. 获得旧的版本库快照


除了以上的命令,你可以使用带参数--revision的svn update和svn checkout来使整个工作副本“回到过去”[6]:


$ svn checkout -r 1729 # Checks out a new working copy at r1729

$ svn update -r 1729 # Updates an existing working copy to r1729

提示
许多Subversion新手使用前面的svn update实例来“回退”修改,但是你不能提交修改,你获得有新修订版本的过时工作副本也是没有用的。关于如何“回退”,我们可以看第 4.3.5 节 “找回删除的项目”。


Lastly, if you're building a release and wish to bundle up your files from Subversion but don't want those pesky .svn directories in the way, you can use svn export to create a local copy of all or part of your repository sans .svn directories. As with svn update and svn checkout, you can also pass the --revision option to svn export:


$ svn export http://svn.example.com/svn/repos1 # Exports latest revision

$ svn export http://svn.example.com/svn/repos1 -r 1729
# Exports revision r1729

2.6. 有时你只需要清理


现在我们已经覆盖了使用Subversion的日常任务,我们会检阅一些工作副本相关的管理任务。


2.6.1. 处理你的工作副本


Subversion doesn't track either the state or the existence of working copies on the server, so there's no server overhead to keeping working copies around. Likewise, there's no need to let the server know that you're going to delete a working copy.


如果你还是喜欢使用工作副本,直到你再次使用它之前,把其保留在磁盘没有任何错误,任何时候一个svn update命令可以让使用的文件成为最新。


However, if you're definitely not going to use a working copy again, you can safely delete the entire thing, but you'd be well served to take a look through the working copy for unversioned files. To find these files, run svn status and review any files that are prefixed with a ? to make certain that they're not of importance. After you're done reviewing, you can safely delete your working copy.


2.6.2. 从中断中恢复


When Subversion modifies your working copy (or any information within .svn), it tries to do so as safely as possible. Before changing the working copy, Subversion writes its intentions to a logfile. Next, it executes the commands in the logfile to apply the requested change, holding a lock on the relevant part of the working copy while it works—to prevent other Subversion clients from accessing the working copy mid-change. Finally, Subversion removes the logfile. Architecturally, this is similar to a journaled filesystem. If a Subversion operation is interrupted (e.g, if the process is killed or if the machine crashes), the logfiles remain on disk. By reexecuting the logfiles, Subversion can complete the previously started operation, and your working copy can get itself back into a consistent state.


And this is exactly what svn cleanup does: it searches your working copy and runs any leftover logs, removing working copy locks in the process. If Subversion ever tells you that some part of your working copy is “locked,” this is the command that you should run. Also, svn status will display an L next to locked items:


$ svn status
  L    somedir
M      somedir/foo.c


$ svn cleanup
$ svn status
M      somedir/foo.c
Don't confuse these working copy locks with the ordinary locks that Subversion users create when using the lock-modify-unlock model of concurrent version control; see the sidebar “锁定”的三种含义 for clarification.


2.7. Dealing with Structural Conflicts


So far, we have only talked about conflicts at the level of file content. When you and your collaborators make overlapping changes within the same file, Subversion forces you to merge those changes before you can commit.[7]


But what happens if your collaborators move or delete a file that you are still working on? Maybe there was a miscommunication, and one person thinks the file should be deleted, while another person still wants to commit changes to the file. Or maybe your collaborators did some refactoring, renaming files and moving around directories in the process. If you were still working on these files, those modifications may need to be applied to the files at their new location. Such conflicts manifest themselves at the directory tree structure level rather than at the file content level, and are known as tree conflicts.


Tree conflicts prior to Subversion 1.6


Prior to Subversion 1.6, tree conflicts could yield rather unexpected results. For example, if a file was locally modified, but had been renamed in the repository, running svn update would make Subversion carry out the following steps:


Check the file to be renamed for local modifications.


Delete the file at its old location, and if it had local modifications, keep an on-disk copy of the file at the old location. This on-disk copy now appears as an unversioned file in the working copy.


Add the file, as it exists in the repository, at its new location.


When this situation arises, there is the possibility that the user makes a commit without realizing that local modifications have been left in a now-unversioned file in the working copy, and have not reached the repository. This gets more and more likely (and tedious) if the number of files affected by this problem is large.


Since Subversion 1.6, this and other similar situations are flagged as conflicts in the working copy.


As with textual conflicts, tree conflicts prevent a commit from being made from the conflicted state, giving the user the opportunity to examine the state of the working copy for potential problems arising from the tree conflict, and resolving any such problems before committing.


2.7.1. An example Tree Conflict


Suppose a software project you were working on currently looked like this:


$ svn ls -Rv svn://svn.example.com/trunk/
      4 harry                 Feb 06 14:34 ./
      4 harry              23 Feb 06 14:34 COPYING
      4 harry              41 Feb 06 14:34 Makefile
      4 harry              33 Feb 06 14:34 README
      4 harry                 Feb 06 14:34 code/
      4 harry              51 Feb 06 14:34 code/bar.c
      4 harry             124 Feb 06 14:34 code/foo.c
Your collaborator Harry has renamed the file bar.c to baz.c. You are still working on bar.c in your working copy, but you don't know yet that the file has been renamed in the repository.


The log message to Harry's commit looked like this:


$ svn log -r5 svn://svn.example.com/trunk
------------------------------------------------------------------------
r5 | harry | 2009-02-06 14:42:59 +0000 (Fri, 06 Feb 2009) | 2 lines
Changed paths:
   M /trunk/Makefile
   D /trunk/code/bar.c
   A /trunk/code/baz.c (from /trunk/code/bar.c:4)


Rename bar.c to baz.c, and adjust Makefile accordingly.
The local changes you have made look like this:


$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c  (revision 4)
+++ code/foo.c  (working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
        printf("I don't like being moved around!\n%s", bar());
-       return 0;
+       return 1;
 }
Index: code/bar.c
===================================================================
--- code/bar.c  (revision 4)
+++ code/bar.c  (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-       return "Me neither!\n";
+       return "Well, I do like being moved around!\n";
 }
Your changes are all based on revision 4. They cannot be committed because Harry has already checked in revision 5:


$ svn commit -m "Small fixes"
Sending        code/bar.c
Sending        code/foo.c
Transmitting file data ..
svn: Commit failed (details follow):
svn: File not found: transaction '5-5', path '/trunk/code/bar.c'
At this point, you need to run svn update. Besides bringing our working copy up to date so that you can see Harry's changes, this also flags a tree conflict so you have the opportunity to evaluate and properly resolve it.


$ svn update
   C code/bar.c
A    code/baz.c
U    Makefile
Updated to revision 5.
Summary of conflicts:
  Tree conflicts: 1
In its output, svn update signifies tree conflicts using a capital C in the fourth output column. svn status reveals additional details of the conflict:


$ svn status
M       code/foo.c
A  +  C code/bar.c
      >   local edit, incoming delete upon update
M       code/baz.c
Note how bar.c is automatically scheduled for re-addition in your working copy, which simplifies things in case you want to keep the file.


Because a move in Subversion is implemented as a copy operation followed by a delete operation, and these two operations cannot be easily related to one another during an update, all Subversion can warn you about is an incoming delete operation on a locally modified file. This delete operation may be part of a move, or it could be a genuine delete operation. Talking to your collaborators, or, as a last resort, svn log, is a good way to find out what has actually happened.


Both foo.c and baz.c are reported as locally modified in the output of svn status. You made the changes to foo.c yourself, so this should not be surprising. But why is baz.c reported as locally modified?


The answer is that despite the limitations of the move implementation, Subversion was smart enough to transfer your local edits in bar.c into baz.c:


$ svn diff code/baz.c
Index: code/baz.c
===================================================================
--- code/baz.c  (revision 5)
+++ code/baz.c  (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-       return "Me neither!\n";
+       return "Well, I do like being moved around!\n";
 }
警告
Local edits to the file bar.c, which is renamed during an update to baz.c, will only be applied to bar.c if your working copy of bar.c is based on the revision in which it was last modified before being moved in the repository. Otherwise, Subversion will resort to retreiving baz.c from the repository, and will not try to transfer your local modifications to it. You will have to do so manually.


bar.c is now said to be the victim of a tree conflict. It cannot be committed until the conflict is resolved:


$ svn commit -m "Small fixes" 
svn: Commit failed (details follow):
svn: Aborting commit: 'code/bar.c' remains in conflict
So how can this conflict be resolved? You can either agree or disagree with the move Harry made. In case you agree, you can delete bar.c and mark the tree conflict as resolved:


$ svn remove --force code/bar.c
D         code/bar.c
$ svn resolve --accept=working code/bar.c
Resolved conflicted state of 'code/bar.c'
$ svn status
M       code/foo.c
M       code/baz.c
$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c  (revision 5)
+++ code/foo.c  (working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
        printf("I don't like being moved around!\n%s", bar());
-       return 0;
+       return 1;
 }
Index: code/baz.c
===================================================================
--- code/baz.c  (revision 5)
+++ code/baz.c  (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-       return "Me neither!\n";
+       return "Well, I do like being moved around!\n";
 }
If you do not agree with the move, you can delete baz.c instead, after making sure any changes made to it after it was renamed are either preserved or not worth keeping. Do not forget to revert the changes Harry made to the Makefile. Since bar.c is already scheduled for re-addition, there is nothing else left to do, and the conflict can be marked resolved:


$ svn remove --force code/baz.c
D         code/baz.c
$ svn resolve --accept=working code/bar.c
Resolved conflicted state of 'code/bar.c'
$ svn status
M       code/foo.c
A  +    code/bar.c
D       code/baz.c
M       Makefile
$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c (revision 5)
+++ code/foo.c (working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
  printf("I don't like being moved around!\n%s", bar());
- return 0;
+ return 1;
 }
Index: code/bar.c
===================================================================
--- code/bar.c (revision 5)
+++ code/bar.c (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
- return "Me neither!\n";
+ return "Well, I do like being moved around!\n";
 }
Index: code/baz.c
===================================================================
--- code/baz.c (revision 5)
+++ code/baz.c (working copy)
@@ -1,4 +0,0 @@
-const char *bar(void)
-{
- return "Me neither!\n";
-}
Index: Makefile
===================================================================
--- Makefile (revision 5)
+++ Makefile (working copy)
@@ -1,2 +1,2 @@
 foo: 
- $(CC) -o $@ code/foo.c code/baz.c
+ $(CC) -o $@ code/foo.c code/bar.c
In either case, you have now resolved your first tree conflict! You can commit your changes and tell Harry during tea break about all the extra work he caused for you.


2.8. 总结


Now we've covered most of the Subversion client commands. Notable exceptions are those dealing with branching and merging (see 第 4 章 分支与合并) and properties (see 第 3.2 节 “属性”). However, you may want to take a moment to skim through 第 9 章 Subversion 完全参考 to get an idea of all the different commands that Subversion has—and how you can use them to make your work easier.




[3] 当然没有任何东西是在版本库里被删除了—只是在版本库的HEAD里消失了,你可以通过检出(或者更新你的工作副本)你做出删除操作的前一个修订版本来找回所有的东西,详细请见第 4.3.5 节 “找回删除的项目”。


[4] And you don't have a WLAN card. Thought you got us, huh?


[5] 如果你向他们询问,他们非常有理由把你带到城外的铁轨上。


[6] 看到了吧?我们说过Subversion是一个时间机器。


[7] Well, you could mark files containing conflict markers as resolved and commit them, if you really wanted to. But this is rarely done in practice.