SVN筆記


文件共享的問題

所有的版本控制系統都需要解決這樣一個基礎問題:怎樣讓系統允許用戶共享信息,而不會讓他們因意外而互相干擾?版本庫里意外覆蓋別人的更改非常的容易。

考慮圖 1.2 “需要避免的問題”的情景。假設我們有兩個共同工作者,Harry 和 Sally。他們想同時編輯版本庫里的同一個文件,如果 Harry 先保存它的修改,(過了一會)Sally 可能湊巧用自己的版本覆蓋了這些文件,Harry 的更改不會永遠消失(因為系統記錄了每次修改),但 Harry 所有的修改不會出現在 Sally 新版本的文件中,因為她沒有在開始的時候看到 Harry 的修改。所以 Harry 的工作還是丟失了—至少是從最新的版本中丟失了—而且可能是意外的。這就是我們要明確避免的情況!

圖 1.2. 需要避免的問題

需要避免的問題

1.3.2. “鎖定-修改-解鎖”方案

許多版本控制系統使用鎖定-修改-解鎖機制解決這種問題,在這樣的模型里,在一個時間段里版本庫的一個文件只允許被一個人修改。首先在修改之前,Harry要鎖定住這個文件,鎖定很像是從圖書館借一本書,如果Harry鎖住這個文件,Sally不能做任何修改,如果Sally想請求得到一個鎖,版本庫會拒絕這個請求。在Harry結束編輯並且放開這個鎖之前,她只可以閱讀文件。Harry解鎖后,就要換班了,Sally得到自己的輪換位置,鎖定並且開始編輯這個文件。圖 1.3 ““鎖定-修改-解鎖”方案”描述了這樣的解決方案。

圖 1.3. “鎖定-修改-解鎖”方案

“鎖定-修改-解鎖”方案


鎖定-修改-解鎖模型有一點問題就是限制太多,經常會成為用戶的障礙:

  • 鎖定可能導致管理問題。有時候 Harry 會鎖住文件然后忘了此事,這就是說 Sally 一直等待解鎖來編輯這些文件,她在這里僵住了。然后 Harry 去旅行了,現在 Sally 只好去找管理員放開鎖,這種情況會導致不必要的耽擱和時間浪費。

  • 定可能導致不必要的串行開發。如果 Harry 編輯一個文件的開始,Sally 想編輯同一個文件的結尾,這種修改不會沖突,設想修改可以正確的合並到一起,他們可以輕松的並行工作而沒有太多的壞處,沒有必要讓他們輪流工作

  • 鎖定可能導致錯誤的安全狀態。假設 Harry 鎖定和編輯一個文件 A,同時 Sally 鎖定並編輯文件 B。但是如果 A 和 B 互相依賴,修改導致它們不兼容會怎么樣呢?這樣 A 和 B 不能正確的工作了,鎖定機制對防止此類問題將無能為力—從而產生了一種處於安全狀態的假相。很容易想象 Harry 和 Sally 都以為自己鎖住了文件,而且從一個安全,孤立的情況開始工作,因而沒有盡早發現他們不匹配的修改。鎖定經常成為真正交流的替代品。

 

1.3.3. “拷貝-修改-合並”方案

Subversion, CVS, and many other version control systems use a copy-modify-merge model as an alternative to locking. In this model, each user's client contacts the project repository and creates a personal working copy. Users then work simultaneously and independently, modifying their private copies. Finally, the private copies are merged together into a new, final version. The version control system often assists with the merging, but ultimately, a human being is responsible for making it happen correctly.

這是一個例子,Harry 和 Sally 為同一個項目各自建立了一個工作副本,工作是並行的,修改了同一個文件 A,Sally 首先保存修改到版本庫,當 Harry 想去提交修改的時候,版本庫提示文件 A 已經過期,換句話說,A在他上次更新之后已經更改了,所以當他通過客戶端請求合並版本庫和他的工作副本之后,碰巧 Sally 的修改和他的不沖突,所以一旦他把所有的修改集成到一起,他可以將工作拷貝保存到版本庫,圖 1.4 ““拷貝-修改-合並”方案”圖 1.5 ““拷貝-修改-合並”方案(續)”展示了這一過程。

圖 1.4. “拷貝-修改-合並”方案

“拷貝-修改-合並”方案


圖 1.5. “拷貝-修改-合並”方案(續)

“拷貝-修改-合並”方案(續)


但是如果 Sally 和 Harry 的修改交迭了該怎么辦?這種情況叫做沖突,這通常不是個大問題,當 Harry 告訴他的客戶端去合並版本庫的最新修改到自己的工作副本時,他的文件 A 就會處於沖突狀態:他可以看到一對沖突的修改集,並手工的選擇保留一組修改。需要注意的是軟件不能自動的解決沖突,只有人可以理解並作出智能的選擇,一旦 Harry 手工的解決了沖突—也許需要與 Sally 討論—它可以安全的把合並的文件保存到版本庫。

拷貝-修改-合並模型感覺有一點混亂,但在實踐中,通常運行的很平穩,用戶可以並行的工作,不必等待別人,當工作在同一個文件上時,也很少會有交迭發生,沖突並不頻繁,處理沖突的時間遠比等待解鎖花費的時間少。

最后,一切都要歸結到一條重要的因素:用戶交流。當用戶交流貧乏,語法和語義的沖突就會增加,沒有系統可以強制用戶完美的交流,沒有系統可以檢測語義上的沖突,所以沒有任何證據能夠承諾鎖定系統可以防止沖突,實踐中,鎖定除了約束了生產力,並沒有做什么事。



Mixed Revision Working Copies

As a general principle, Subversion tries to be as flexible as possible. One special kind of flexibility is the ability to have a working copy containing files and directories with a mix of different working revision numbers. Unfortunately, this flexibility tends to confuse a number of new users. If the earlier example showing mixed revisions perplexed you, here's a primer on why the feature exists and how to make use of it.

Updates and commits are separate

One of the fundamental rules of Subversion is that a “push” action does not cause a “pull,” nor vice versa. Just because you're ready to submit new changes to the repository doesn't mean you're ready to receive changes from other people. And if you have new changes still in progress, svn update should gracefully merge repository changes into your own, rather than forcing you to publish them.(svn update會並沒有commit)

 

The main side effect of this rule is that it means a working copy has to do extra bookkeeping 記賬to track mixed revisions as well as be tolerant of the mixture. It's made more complicated by the fact that directories themselves are versioned.

這個規則的主要副作用就是,工作副本需要記錄額外的信息來追蹤混合修訂版本,並且也需要能容忍這種混合,當目錄本身也是版本化的時候情況更加復雜。

舉個例子,假定你有一個工作副本,修訂版本號是10。你修改了 foo.html,然后執行 svn commit,在版本庫里創建了修訂版本15。當成功提交之后,許多用戶希望工作副本完全變成修訂版本15,但是事實並非如此。修訂版本從10到15會發生任何修改,可是客戶端在運行 svn update 之前不知道版本庫發生了怎樣的改變,svn commit 不會拖出任何新的修改。另一方面,如果 svn commit 會自動下載最新的修改,可以使得整個工作副本成為修訂版本15—但是,那樣我們會打破完全分開的原則。因此,Subversion 客戶端最安全的方式是標記一個文件— foo.html —為修訂版本15,工作副本余下的部分還是修訂版本10。只有運行 svn update 才會下載最新的修改,整個工作副本被標記為修訂版本15。

For example, suppose you have a working copy entirely at revision 10. You edit the file foo.html and then perform an svn commit, which creates revision 15 in the repository. After the commit succeeds, many new users would expect the working copy to be entirely at revision 15, but that's not the case! Any number of changes might have happened in the repository between revisions 10 and 15. The client knows nothing of those changes in the repository, since you haven't yet run svn update, and svn commit doesn't pull down new changes. If, on the other hand, svn commit were to automatically download the newest changes, it would be possible to set the entire working copy to revision 15—but then we'd be breaking the fundamental rule of “push” and “pull” remaining separate actions. Therefore, the only safe thing the Subversion client can do is mark the one file—foo.html—as being at revision 15. The rest of the working copy remains at revision 10. Only by running svn update can the latest changes be downloaded and the whole working copy be marked as revision 15.

Mixed revisions are normal

The fact is, every time you run svn commit your working copy ends up with some mixture of revisions. The things you just committed are marked as having larger working revisions than everything else. After several commits (with no updates in between), your working copy will contain a whole mixture of revisions. Even if you're the only person using the repository, you will still see this phenomenon. To examine your mixture of working revisions, use the svn status command with the --verbose option (see the section called “See an overview of your changes” for more information).

Often, new users are completely unaware that their working copy contains mixed revisions. This can be confusing, because many client commands are sensitive to the working revision of the item they're examining. For example, the svn log command is used to display the history of changes to a file or directory (see the section called “Generating a List of Historical Changes”). When the user invokes this command on a working copy object, he expects to see the entire history of the object. But if the object's working revision is quite old (often because svn update hasn't been run in a long time), the history of the older version of the object is shown.

Mixed revisions are useful

If your project is sufficiently complex, you'll discover that it's sometimes nice to forcibly backdate (or update to a revision older than the one you already have) portions of your working copy to an earlier revision; you'll learn how to do that in Chapter 2, Basic Usage. Perhaps you'd like to test an earlier version of a submodule contained in a subdirectory, or perhaps you'd like to figure out when a bug first came into existence in a specific file. This is the “time machine” aspect of a version control system—the feature that allows you to move any portion of your working copy forward and backward in history.

Mixed revisions have limitations

However you make use of mixed revisions in your working copy, there are limitations to this flexibility.

First, you cannot commit the deletion of a file or directory that isn't fully up to date. If a newer version of the item exists in the repository, your attempt to delete will be rejected to prevent you from accidentally destroying changes you've not yet seen.

Second, you cannot commit a metadata change to a directory unless it's fully up to date. You'll learn about attaching “properties” to items in Chapter 3, Advanced Topics. A directory's working revision defines a specific set of entries and properties, and thus committing a property change to an out-of-date directory may destroy properties you've not yet seen.

Summary

We covered a number of fundamental Subversion concepts in this chapter:

  • We introduced the notions of the central repository, the client working copy, and the array of repository revision trees.

  • We saw some simple examples of how two collaborators can use Subversion to publish and receive changes from one another, using the “copy-modify-merge” model.

  • We talked a bit about the way Subversion tracks and manages information in a working copy.

At this point, you should have a good idea of how Subversion works in the most general sense. Armed with this knowledge, you should now be ready to move into the next chapter, which is a detailed tour of Subversion's commands and features.

 

Chapter 2. Basic Usage

Now we will go into the details of using Subversion. By the time you reach the end of this chapter, you will be able to perform all the tasks you need to use Subversion in a normal day's work. You'll start with getting your files into Subversion, followed by an initial checkout of your code. We'll then walk you through making changes and examining those changes. You'll also see how to bring changes made by others into your working copy, examine them, and work through any conflicts that might arise.

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 Chapter 1, Fundamental Concepts and are familiar with the general model of Subversion. For a complete reference of all commands, see Chapter 9, Subversion Complete Reference.

Help!

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')
…

Getting Data into Your Repository

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 discusssvn add later in this chapter when we review a typical day with Subversion.

svn import 不要求working copy

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:

svn import 是將未版本化文件導入版本庫的最快方法,會根據需要創建中介目錄svn import 不需要一個工作副本,你的文件會直接提交到版本庫,這通常用在你希望將一組文件加入到 Subversion 版本庫時,例如:

$ 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.

The previous example copied the contents of directory mytree under the directory some/project in the repository:

$ svn list file:///var/svn/newrepos/some/project
bar.c
foo.c
subdir/

Note that after the import is finished, the original tree is not converted into a working copy. To start working, you still need to svn checkout a fresh working copy of the tree.

Recommended Repository Layout

While Subversion's flexibility allows you to lay out your repository in any way that you choose, we recommend that you create a trunkdirectory 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

You'll learn more about tags and branches in Chapter 4, Branching and Merging. For details and how to set up multiple projects, see the section called “Repository Layout” and the section called “Planning Your Repository Organization” to read more about project roots.

Initial Checkout

Most of the time, you will start using a Subversion repository by doing a checkout of your project. Checking out a repository creates a “working copy” of it on your local machine. This copy contains the HEAD (latest revision) of the Subversion repository that you specify on the command line:

$ 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.

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 the section called “Versioning Models”), 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.

While your working copy is “just like any other collection of files and directories on your system,” you can edit files at will, but you must tell Subversion about everything else that you do. For example, if you want to copy or move an item in a working copy, you should use svn copy or svn move instead of the copy and move commands provided by your operating system. We'll talk more about them later in this chapter.

警告
因為你的工作副本“同你系統上的文件和目錄沒有任何區別”,你可以隨意修改文件,但是你必須告訴 Subversion 你做的其他任何事。例如,你希望拷貝或移動工作副本的一個文件,你應該使用 svn copy 或者 svn move,而不要使用操作系統的拷貝移動命令,我們會在本章后面詳細介紹。

Unless you're ready to commit the addition of a new file or directory or changes to existing ones, there's no need to further notify the Subversion server that you've done anything.

While you can certainly check out a working copy with the URL of the repository as the only argument, you can also specify a directory after your repository URL. This places your working copy in the new directory that you name. For example:

$  svn checkout http://svn.collab.net/repos/svn/trunk subv 新創建一個subv目錄,包含trunk文件。
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.

That will place your working copy in a directory named subv instead of a directory named trunk as we did previously. The directory subvwill be created if it doesn't already exist.

 

Basic Work Cycle

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.

基本的工作循環

Subversion 有許多特性, 選項和華而不實的高級功能,但日常的工作中你只使用其中的一小部分,在這一節里,我們會介紹許多你在日常工作中常用的命令。

典型的工作周期是這樣的:

The typical work cycle looks like this:

  1. Update your working copy.

    • svn update

  2. Make changes.

    • svn add

    • svn delete

    • svn copy

    • svn move

  3. Examine your changes.

    • svn status

    • svn diff

  4. Possibly undo some changes.

    • svn revert

  5. Resolve conflicts (merge others' changes).

    • svn update

    • svn resolve

  6. Commit your changes.

    • svn commit

     

 

Update Your Working Copy

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.

In this case, it appears that someone checked in modifications to both foo.c and bar.c since the last time you updated, and Subversion has updated your working copy to include those changes.

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.

Make Changes to Your Working Copy

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 deletesvn copysvn 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.

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

svn add foo 添加foo

Schedule file, directory, or symbolic link foo to be added to the repository. When you next commit, foo will become a child of its parent directory. Note that if foo is a directory, everything underneath foo will be scheduled for addition. If you want only to add foo itself, pass the --depth empty option.

svn delete foo 注意文件和目錄不同

Schedule file, directory, or symbolic link foo to be deleted from the repository. If foo is a file or link, it is immediately deleted from your working copy. If foo is a directory, it is not deleted, but Subversion schedules it for deletion. When you commit your changes, foo will be entirely removed from your working copy and the repository[4]

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.

 

Changing the Repository Without a Working Copy

There are some use cases that immediately commit tree changes to the repository. This happens only when a subcommand is operating directly on a URL, rather than on a working-copy path. In particular, specific uses of svn mkdirsvn copysvn move, and svn delete can work with URLs (and don't forget that svn import always makes changes to a 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.

 

Examine Your Changes

Once you've finished making changes, you need to commit them to the repository, but before you do so, it's usually a good idea to take a look at exactly what you've changed. By examining your changes before you commit, you can make a more accurate log message. You may also discover that you've inadvertently changed a file, and this gives you a chance to revert those changes before committing. Additionally, this is a good opportunity to review and scrutinize changes before publishing them. You can see an overview of the changes you've made by using svn status, and dig into the details of those changes by using svn diff.

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.

See an overview of your changes

To get an overview of your changes, you'll use the svn status command. You'll probably use svn status more than any other Subversion command.

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 bysvn 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

In this output format, svn status prints six columns of characters, followed by several whitespace characters, followed by a file or directory name. The first column tells the status of a file or directory and/or its contents. The codes we listed are:

A item

The file, directory, or symbolic link item has been scheduled for addition into the repository.

C item

The file item is in a state of conflict. That is, changes received from the server during an update overlap with local changes that you have in your working copy (and weren't resolved during the update). You must resolve this conflict before committing your changes to the repository.

D item

The file, directory, or symbolic link item has been scheduled for deletion from the repository.

M item

The contents of the file item have been modified.

If you pass a specific path to svn status, you get information about that item alone:

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

svn status also has a --verbose (-v) option, which will show you the status of every item in your working copy, even if it has not been changed:

$ 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

This is the “long form” output of svn status. The letters in the first column mean the same as before, but the second column shows the working revision of the item. The third and fourth columns show the revision in which the item last changed, and who changed it.

None of the prior invocations to svn status contact the repository—instead, they compare the metadata in the .svn directory with the working copy. Finally, there is the --show-updates (-u) option, which contacts the repository and adds information about things that are out of date:

$ 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 can display much more information about the files and directories in your working copy than we've shown here—for an exhaustive description of svn status and its output, see svn status.

如果你已經svn commit了,那么svn status沒有任何輸出

 

Examine the details of your local modifications

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 diffwith 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.

The svn diff command produces this output by comparing your working files against the cached “pristine” copies within the .svn area. Files scheduled for addition are displayed as all added text, and files scheduled for deletion are displayed as all deleted text.

Output is displayed in unified diff format. That is, removed lines are prefaced with -, and added lines are prefaced with +svn diff also prints filename and offset information useful to the patch program, so you can generate “patches” by redirecting the diff output to a file:

$ 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.

Undoing Working Changes

Suppose while viewing the output of svn diff you determine that all the changes you made to a particular file are mistakes. Maybe you shouldn't have changed the file at all, or perhaps it would be easier to make different changes starting from scratch.

This is a perfect opportunity to use svn revert:

$ svn revert README
Reverted 'README'

Subversion reverts the file to its premodified state by overwriting it with the cached “pristine” copy from the .svn area. But also note that svn revert can undo any scheduled operations—for example, you might decide that you don't want to add a new file after all:

$ 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.

Or perhaps you mistakenly removed a file from version control:

$ svn status README

$ svn delete README
D         README

$ svn revert README
Reverted 'README'

$ svn status README

Resolve Conflicts (Merging Others' Changes)

比如,我當前的版本庫已經過時,修改了一個文件后,提交:

提示信息很明顯了,Blue.java文件已經out of date。說明其他人已經修改了這個文件並且commit的了。

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:

The U and G codes are no cause for concern; those files cleanly absorbed 吸收changes from the repository. The files marked with U contained no local changes but were Updated with changes from the repository. The G stands for merGed, which means that the file had local changes to begin with, but the changes coming from the repository didn't overlap with the local changes.

But the next two lines are part of a feature (new in Subversion 1.5) called interactive conflict resolution. This means that the changes from the server overlapped with your own, and you have the opportunity to resolve this conflict. The most commonly used options are displayed, but you can see all of the options by typing 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

Let's briefly review each of these options before we go into detail on what each option means.

(p)ostpone

Leave the file in a conflicted state for you to resolve after your update is complete.

(d)iff

Display the differences between the base revision and the conflicted file itself in unified diff format.

(e)dit

Open the file in conflict with your favorite editor, as set in the environment variable EDITOR.

(r)esolved

After editing a file, tell svn that you've resolved the conflicts in the file and that it should accept the current contents—basically that you've “resolved” the conflict.

(m)ine-(f)ull

Discard the newly received changes from the server and use only your local changes for the file under review.

(t)heirs-(f)ull

Discard your local changes to the file under review and use only the newly received changes from the server.

(l)aunch

Launch an external program to perform the conflict resolution. This requires a bit of preparation beforehand.

(h)elp

Show the list of all possible commands you can use in interactive conflict resolution.

We'll cover these commands in more detail now, grouping them together by related functionality.

Viewing conflict differences interactively

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

…
Select: (p) postpone, (df) diff-full, (e) edit,
        (h)elp for more options : d
--- .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

The first line of the diff content shows the previous contents of the working copy (the BASE revision), the next content line is your change, and the last content line is the change that was just received from the server (usually the HEAD revision). With this information in hand, you're ready to move on to the next action.

Resolving conflict differences interactively

There are four different ways to resolve conflicts interactively—two of which allow you to selectively merge and edit changes, and two of which allow you to simply pick a version of the file and move along.

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 the section called “Merging conflicts by hand” for a walkthrough), so some people like to use fancy graphical merge tools instead.

(我們我們選e編輯文件,需要設定config文件中的:

### Set editor-cmd to the command used to invoke your text editor.###  

This will override the environment variables that Subversion###examines by default to find this information ($EDITOR, ###   et al).

#editor-cmd = editor (vim, emacs, notepad, etc.)

設置為vim:

editor-cmd=vim

選e時就可以打開了。我們設置cofig會重載一起設置的打開的環境變量。

 

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 the section called “Configuration Options” 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).

 

Postponing conflict resolution 延后沖突解決

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.

The C stands for conflict. This means that the changes from the server overlapped with your own, and now you have to manually choose between them after the update has completed. When you postpone a conflict resolution, svn typically does three things to assist you in noticing and resolving that conflict:

  • Subversion prints a C during the update and remembers that the file is in a state of conflict.

  • 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 the section called “File Content Type” to learn more.)

  • For every conflicted file, Subversion places three extra unversioned files in your working copy:

    • Subversion 在更新時打印 C 標記,並且標記這個文件處於沖突狀態。

    • 如果Subversion認為這個文件是可以合並的,它會置沖突標記—特殊的橫線分開沖突的兩面—在文件里可視化的描述重疊的部分(Subversion 使用 svn:mime-type 屬性來決定一個文件是否可以使用基於上下文的,以行為基礎的合並,更多信息可以參見第 4.1 節 “文件內容類型”)

    • 對於每一個沖突的文件,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  當我上次update時獲取的文件,就是當我還沒修改代碼之前的文件。

    This is the file that was the BASE revision before you updated your working copy. That is, the file that you checked out before you made your latest edits.

    filename.rNEWREV 版本庫最新的文件。

    This is the file that your Subversion client just received from the server when you updated your working copy. This file corresponds to the HEAD revision of the repository.

    Here OLDREV is the revision number of the file in your .svn directory, and NEWREV is the revision number of the repository 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

(所有,一旦沖突產生,會有4個文件,一個原來名字的文件,里面包含沖突,另外3個臨時文件)。沖突文件類似如:

 

public class Blue extends Color {

    void bepaint(String penType, String name) {
<<<<<<< .mine
        //System.out.println(penType+"藍色的"+name+"."); 
        System.out.lprintLn(penType+"藍色"+name);
        
=======
        System.out.println('這是新添加的一句');
        System.out.println(penType+"藍色的"+name+".");
>>>>>>> .r4

    }
    void addFunc()
    {
        System.out.println("addFunc");
    }

}

 

(上面的說名:我當前工作版本是r2.但是版本庫最新版是r4.我已經落后2個版本了。

<<<<.mine

和==========之間是我目前所做的修改

==========

和》》》》》》》》》》》》》》r4所做的修改

 

At this point, Subversion will not allow Sally to commit the file sandwich.txt until the three temporary files are removed:在這種情況下,Subversion 會允許 Sally 提交 sandwich.txt,直到這三個臨時文件被刪除。

$ 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

If you've postponed a conflict, you need to resolve the conflict before Subversion will allow you to commit your changes. You'll do this with the svn resolve command and one of several arguments to the --accept option.

If you want to choose the version of the file that you last checked out before making your edits, choose the base argument.

If you want to choose the version that contains only your edits, choose the mine-full argument.

If you want to choose the version that your most recent update pulled from the server (and thus discarding your edits entirely), choose the theirs-full argument.

However, if you want to pick and choose from your changes and the changes that your update fetched from the server, merge the conflicted text “by hand” (by examining and editing the conflict markers within the file) and then choose the working argument.

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:

如果你延遲解決沖突,你需要在 Subversion 允許你提交你的修改之前解決沖突。你可以通過 svn resolve 命令和 --accept 選項的多個參數之中的一個來完成。

如果你希望選擇上次檢出后修改之前的文件版本,選擇 base 參數。

如果你希望選擇只包含你修改的版本,選擇 mine-full 參數。

如果你希望選擇最近從服務器更新的版本(因此會丟棄你的所有編輯),選擇 theirs-full 參數。

然而,如果你想在自己的修改與服務器端的修改之間部分選擇的話,請手工合並沖突文本(檢查和編輯文件中的沖突標記),然后選擇參數 working 。

svn resolve 刪除這三個臨時文件,使用 --accept 選項指定的文件版本,從而 Subversion 不會再認為文件處於沖突狀態

$ svn resolve --accept working sandwich.txt
Resolved conflicted state of 'sandwich.txt'

Merging conflicts by hand

Merging conflicts by hand can be quite intimidating the first time you attempt it, but with a little practice, it can become as easy as falling off a bike.

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:

第一次嘗試解決沖突讓人感覺很害怕,但經過一點訓練,它簡單的像是騎着車子下坡。

這里一個簡單的例子。由於不良的交流,你和同事 Sally 同時編輯了 sandwich.txt 。Sally 提交了修改,當你准備更新你的工作副本時,沖突發生了,你不得不去修改sandwich.txt 來解決沖突。首先,看一下這個文件:

$ 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

小於號, 等於號和大於號字符串是沖突標記,並不是沖突的數據。你通常要確包這些內容在下次提交之前被刪除,前兩組沖突標記中間的內容是你在沖突區所做的修改:

<<<<<<< .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. [6] Once you've agreed on the changes you will commit, edit your file and remove the conflict markers:通常你並不希望只是刪除沖突標志和Sally的修改—當她收到三明治時,會非常的吃驚。所以你應該走到她的辦公室或是拿起電話告訴Sally,你沒辦法從從意大利熟食店得到想要的泡菜。[7]一旦你們確認了提交內容后,修改文件並且刪除沖突標志。

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."

現在我們准備好提交修改了,注意svn resolved不像我們本章學過的其他命令一樣需要參數,在任何你認為解決了沖突的時候,只需要小心運行svn resolved,—一旦刪除了臨時文件,Subversion會讓你提交這文件,即使文件中還存在沖突標記。

記住,如果你修改沖突時感到混亂,你可以參考subversion生成的三個文件—包括你未作更新的文件。你也可以使用三方交互合並工具檢驗這三個文件



Discarding your changes in favor of a newly fetched revision 放棄你的修改

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:

 如果你只是希望取消你的修改,你可以僅僅拷貝Subversion為你生成的文件替換你的工作拷貝:

$ 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'

使用svn revert

如果你得到沖突,經過檢查你決定取消自己的修改並且重新編輯,你可以恢復你的修改:

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

注意,當你恢復一個沖突的文件時,不需要再運行svn resolved

Commit Your Changes

Finally! Your edits are finished, you've merged all changes from the server, and you're ready to commit your changes to the repository.

The svn commit command sends all of your changes to the repository. When you commit a change, you need to supply a log messagedescribing 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選項:

$ svn commit -F logmsg
Sending        sandwich.txt
Transmitting file data .
Committed revision 4.

如果你沒有指定--message或者--file選項,Subversion會自動地啟動你最喜歡的編輯器(見“配置”一節editor-cmd部分)來編輯日志信息。

如果你使用編輯器撰寫日志信息時希望取消提交,你可以直接關掉編輯器,不要保存,如果你已經做過保存,只要簡單的刪掉所有的文本並再次保存,然后退出。

$ svn commit
Waiting for Emacs...Done

Log message unchanged or not specified
a)bort, c)ontinue, e)dit
a
$

版本庫不知道也不關心你的修改作為一個整體是否有意義,它只檢查是否有其他人修改了同一個文件,如果別人已經這樣做了,你的整個提交會失敗,並且提示你一個或多個文件已經過時了:

$ svn commit -m "Add another rule"
Sending        rules.txt
svn: Commit failed (details follow):
svn: Your file or directory 'sandwich.txt' is probably out-of-date

錯誤信息的精確措辭依賴於網絡協議和你使用的服務器,但對於所有的情況,其思想完全一樣。)

此刻,你需要運行svn update來處理所有的合並和沖突,然后再嘗試提交。

我們已經覆蓋了Subversion基本的工作周期,還有許多其它特性可以管理你得版本庫和工作拷貝,但是只使用前面介紹的命令你就可以很進行日常工作了,我們還會覆蓋更多用的還算頻繁的命令。

參考:

http://svnbook.red-bean.com/en/1.5/svn-book.html#svn.tour.cycle

 http://www.subversion.org.cn/svnbook/1.4/svn.tour.history.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM