• No results found

Every Subversion command that can operate on multiple files defaults to either recursive behavior or non-recursive behavior, depending on the command. Basically, commands that can destroy data (such assvn revert) are non-recursive by default. Everything else defaults to recursive. Regardless of which default a program uses, you can override the default using--recursiveor--non-recursive. For instance, the following command will revert all local changes in the trunk directory:

$ svn revert --recursive trunk/

--revision

Many Subversion commands require you to specify a specific revision in the repository, or a range of revisions. For any command that takes a revision, you can supply it using the- -revisionoption. Single revisions can be specified by following the option with a single

5.2 Checking Out and Maintaining a Working Copy 57

numbers separated by a colon. For example, the following command will display the log messages for revisions 1 through 50.

$ svn log --revision 1:50

To make your life a little bit easier, Subversion also defines a few aliases that can be used to refer to certain revision numbers by their context, rather than their explicit number. Those aliases are HEAD, BASE, COMMITTED, and PREV. Each one can be used in any Subversion command, when a revision number is called for—although BASE, COMMIT- TED, and PREV can only be used when referencing a working copy because they require the working copy to give them context. The HEAD alias refers to the greatest numerical revision in a repository. This is the same for every file, regardless of when they were last committed. The BASE alias, on the other hand, points to the base revision for the working copy file or directory being referenced. So, for example, if you check out the trunk direc- tory at revision 3497, BASE would point to 3497. If you then commit a modified file inside the trunk directory at revision 3583, the BASE for that file will point to 3583, whereas the base for the trunk directory and the rest of its contents will still point to 3497. If you later update the trunk to 3583, its BASE will then point to 3583. The remaining two, COMMIT- TED and PREV, are then relative to the BASE revision. COMMITTED refers to the most recent commit at or before the working copy item’s BASE revision, and PREV refers to the revision prior to COMMITTED. So, for instance, if you want to show the log messages from the first revision to the most recently committed revision, you could run the following command.

$ svn log --revision 1:COMMITTED

5.1.2

Paths

In addition to options that are common across commands, the format for specifying paths in a working copy or repository are also common. For most Subversion commands, you can reference files and directories that reside locally in a working copy or in a remote repository. Working copy files/directories are referenced by giving a local path to that file (either absolute or relative to the current directory). Repositories are referenced with URLs. For instance, you might reference thetrunkdirectory in a remote repository that is served via Apache withhttp://svn.example.com/repos/trunk/. Most commands will take either local paths or URLs on the command line, and in most cases you can mix URLs and local paths in the same command—to copy from the repository to a working copy, for example.

$ svn cp http://svn.example.com/repos/trunk/foo.c ~/repos_wc/¬

trunk/bar.c

5.2

Checking Out and Maintaining a Working Copy

“svnbook” — 2005/4/14 — 14:55 — page 58 — #79

i i

58 Chapter 5 Working with a Working Copy

that should be checked out, you pass a URL that points to the desired repository along with the checkout command. The exact form that the URL takes depends on the type of server that you are contacting.

If the repository is being served by Apache, via HTTP/WebDAV, the appropriate URL prefix ishttp://, or if the connection is secured by SSL,https://. On the other hand, if the Subversion server for the repository issvnserve, you will want to usesvn://or

svn+ssh://, depending on whether the connection should be tunneled over SSH. Finally, if you are not contacting a remote server, but are instead directly accessing a repository that resides on the local machine, the prefix should befile://. The remainder of the URL follows the same standards as a URL used for any other purpose and consists of the [email protected]/path/to/repository. Of course, the username and hostname are dropped if it is a directly accessed local repository, via afile://prefix. Also, remember that a local filesystem path should have an initial/, in addition to the prefixed double slash (so you should have three slashes total). This applies even for local filesystem URLs on Windows, even though Windows doesn’t use the slash to indicate a root directory in the filesystem hierarchy.

You can also make a working copy that consists of only part of a repository by continu- ing the path in the URL out to identify the portion to check out. For example, if a repository

reposcontains a directory namedtrunkat the top level, you could check out justtrunk

by issuing the following command.

$ svn co http://svn.example.com/repos/trunk A trunk

A trunk/foo.c

Running the preceding checkout command with that URL will check out just thetrunk

directory in the repository and create a local directory namedtrunkin the directory where the checkout command was run. Thetrunkdirectory is now your working copy. It contains copies of the versioned files located inside thetrunkdirectory, as well as a directory named

.svn, where Subversion stores metadata about the local working copy.

If you want to check out a working copy into a directory other than the directory where thesvn cocommand is actually run (for instance, if you create a script to automate the checkout), you can pass a path to the checkout command, after the URL, which will tell Subversion where to place the checked out working copy. So, if you want to check out a repository into your home directory, you can run the following command from anywhere:

$ svn co http://svn.example.com/repos /home/bill/repos_wc A repos_wc A repos_wc/trunk A repos_wc/trunk/foo.c A repos_wc/branches A repos_wc/branches/branch1/foo.c A repos_wc/tags

Subversion also allows you to specify multiple URLs to check out on the same com- mand line. If you do supply multiple URLs, Subversion will check out each of the reposi-

5.2 Checking Out and Maintaining a Working Copy 59

tories (or subsets of a repository) given, and place them either in the local directory or the directory given as a path after all of the URLs.

$ svn co http://svn.example.com/repos/trunk http://svn.mycomain.com/¬ repos/branches A trunk A trunk/foo.c A branches A branches/branch1/foo.c

If for one reason or another you don’t want to check out the subdirectories of a repos- itory, you can also pass svn cothe argument--non-recursive(-N) to tell it to only check out the directory given, without checking out the contents of any directories it con- tains. If you do this though, the working copy will remember that you didn’t check out any of the subdirectories, and it won’t get them when you do an update either. If you do want to get a subdirectory that wasn’t checked out originally, you can get it by runningsvn updatewith the name of the directory you’d like to get.

$ svn co --non-recursive http://svn.example.com/repos Checked out revision 21657

$ cd repos/ $ ls -a . .. .svn $ svn update trunk A trunk A trunk/test.c $ ls -a . .. .svn trunk

There may also be times when you want to check out a revision of the repository other than the HEAD revision. You can do this by passing--revision(-r) with the revision that you want to check out. The revision can either be an explicit revision number, or it can be a date (which needs to be enclosed in brackets). For example, if you want to check out the last revision committed before July 20th, 2004 at noon, you could check out with the following command.

$ svn co --revision "{2004-07-20 12:00}" http://svn.example.com/repos

5.2.1

Keeping Up-to-Date

After you have a repository checked out, you will want to keep it up-to-date with changes made by other developers. The basic command for doing this issvn update(orsvn up). When it is run without any options, the differences between the current revision of files in your working copy and the HEAD revision of the repository are downloaded from the server and applied to your working copy. As it updates, Subversion will show you which files were updated, and what sort of update occurred.

“svnbook” 2005/4/14 14:55 page 60 #81

i i

60 Chapter 5 Working with a Working Copy

$ svn update A trunk/vid/wildflowers.mpg U trunk/src/anim.c D trunk/src/works.c G trunk/src/Makefile C trunk/README Updated to revision 1450.

As you can see here, there were five files modified by the update, and each one has a different letter in front of its name. Each of those letters tells you what Subversion did when it updated the file in your working copy. Only files that were in some way updated are shown in the output.

• TheAtells you that a file namedtrunk/vid/wildflowers.mpghas been added to the repository since your last update, so Subversion downloaded a copy of it and added it to your working copy.

• TheUtells you that the filetrunk/src/animwas updated with changes from the repository.

• TheDtells you that file was deleted from your working copy, because it no longer exists in the repository.

• TheGtells you that Subversion merged the changes received from the repository with the locally modified filetrunk/src/Makefile.

• TheCindicates that Subversion was not able to merge the changes to the file

trunk/README, and has instead declared a conflict.

If the update command is run with no path supplied, it operates on the current directory and recursively updates that directory and all of its contents. If a path is supplied, it updates the directory or file that is given, as well as anything contained within if the path points to a directory. If recursive updating is not what you want (for instance, if you want to update the properties associated with a directory without updating its contents), you can use the

--non-recursiveoption. The following command, for example, will update thetrunk

directory, but leave its contents untouched.

$ svn update --non-recursive /home/bill/repos/trunk U trunk

Updated to revision 1478.

It is important to note thatsvn updateoperates on files and directories known to the repository, regardless of whether those files have been locally removed from your working copy. The advantage of this is best illustrated by the following snippet.

5.3 Modifying and Committing Data 61 $ svn update bar.c U bar.c Updated to revision 503. $ ls foo.c bar.c

As you can see, Subversion makes it easy to recover files that were locally deleted, eliminating any worry about causing real harm to data within the working copy. Recovering a file by deleting and updating can also be handy if a file in the working copy somehow gets corrupted. In most cases, if Subversion is misbehaving on a versioned file, you can get things back to a sane state by just deleting (or moving) it and performing ansvn update. Another command that is useful for restoring a working copy to a known state issvn revert. This command works similarly tosvn update, but instead of updating to a dif- ferent revision in the repository, the revert command restores locally modified files to a pristine version of the file, corresponding to the most recent checkout, update, or commit.

Reversions that are done withsvn revertare very fast, because Subversion always keeps a pristine copy of every versioned file in the working copy.1 This allows the revert to occur without contacting the remote repository, saving not just time but also bandwidth.

As a safety feature though (because the command can destroy local changes), svn revert does not recurse into subdirectories likesvn checkout andsvn update, nor will it do anything if you run it without explicitly identifying the files to revert. If you want recursion, you have to explicitly request it with the--recursive(-R) option. Subversion also can’t revert directories that were locally deleted. To do that, you have to usesvn update.

5.3

Modifying and Committing Data

The meat of Subversion is its usefulness for tracking changes in files over time. That makes getting those changes into the system a very important part of the system. The primary tool that you will use to get data into the system is the commit command,svn commit. In general, the basic committing process will go something like this.

$ svn update At revision 3215. $ svn status M light.c

$ svn commit --message "Added a status variable." Sending light.c

Transmitting file data . Committed revision 3216.

It’s a good idea to run thesvn updatecommand first, so that you can get any changes that others have made to the repository and make sure they will be compatible with your change. If there are any other changes merged into your working copy when you run update,

“svnbook” — 2005/4/14 — 14:55 — page 62 — #83

i i

62 Chapter 5 Working with a Working Copy

it’s also a good idea to recompile and run a test suite if one is available, to ensure that everything still works as you expect. Subversion won’t let you commit changes that will result in a merge conflict without first making you resolve those changes by hand. However, it doesn’t have any context for your source, and will not in any way prevent changes that cause logical conflicts in the project. The only conflicts that it catches are instances where either two people edited the exact same lines of a file or two people edited the same binary file.

It is also a good idea to run thesvn status command before you commit, in order to get an idea of what it is that you’ll be committing. That way, you help avoid getting a stray change in an unrelated file mixed in with your commit just because you forgot that you made the change. You can also make use of the svn diffcommand if you don’t remember exactly what changes you made to individual files. To find out more information aboutsvn statusandsvn diff, take a look at Section 5.4, “Getting Information About the Repository.”

As soon as you feel that you have a good understanding of what you are committing, it’s time to perform the actual commit. In the preceding example, the command was run with no path and with a log message on the command line. Whensvn commitis run with no path telling it what to commit, it recursively commits all modified files in the current directory. Recursion can be turned off with--no-recursionif you need to commit a directory without committing its contents.

When the commit command runs, it sends the local modifications to the files being com- mitted to the remote repository. Only the differences are sent, so no bandwidth is wasted by sending redundant information. If no paths are specified bysvn commit, it recursively commits all of the modified files in the current directory. If you don’t want to commit all of the locally modified files, you can instead specify one or more files on the command line, and it will instead commit only those files. Or, you can specify directories on the com- mand line, and Subversion will commit that directory and any changed files or directories it contains (unless you specifically turned off recursion).

In addition to files to commit, svn commit also requires a log message to associate with the commit. The log message can be supplied on the command line by giving the

--message(-m) option. If you supply the log this way, the log message should follow the

--message(separated by a space), and be enclosed in quotes.

$ svn commit -m "A little inline log message. How cute."

Entering log messages on the command line can quickly become unwieldy—especially if they are long messages. To make entering long messages easier, you can leave off the

--messageoption, and Subversion will automatically open an editor for you to enter a log message (as you can see in Figure 5.1). Subversion will then block until you quit the editor. If you have entered a log message and saved the file, Subversion will use the contents of that file as the log message for the commit. If you quit without changing the file, Subversion will instead ask you if you want to use a blank log message or abort the commit. This abort

5.3 Modifying and Committing Data 63

Figure 5.1. Adding a log with a text editor.

capability can come in handy when you realize that you were a little too quick to commit and either forgot to add a file to the those that are being committed, or are accidentally committing too many files. As an aid to helping you figure out what is being committed Subversion will put a section in the commit log file, when it opens the editor, that tells you exactly which files are being committed. That section will then be removed from the file before Subversion sets the commit log.

A third method for entering log messages is to put them in a file and have Subversion read the file by using the option--file(-F)—which takes a single argument specifying the file to read. When specifying a file for the log message though, Subversion will not, by default, allow you to use a file that is already under version control. If you do want to use a file that is under version control for your log message, you can override Subversion’s limitation by passing--force-logtosvn commit.