-
Subversion has numerous features, options, bells and
whistles, but on a day-to-day basis, odds are that you will only
use 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. The typical work cycle looks like this: When working on a project with a team, you'll want to
update your working copy to receive any changes made since
your last update by other developers on the project. 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, someone else 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, see svn update. Make Changes to Your Working CopyNow 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, etc. 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. There are two kinds of changes you can make 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 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
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 only want to add
foo itself, pass the
--non-recursive (-N) 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. - 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. - 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.
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 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 changesTo 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. Below 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.)
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 itemThe file, directory, or symbolic link
item has been scheduled for
addition into the repository. C itemThe 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. You must resolve
this conflict before committing your changes to the
repository. D itemThe file, directory, or symbolic link
item has been scheduled for
deletion from the repository. M itemThe 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. Examine the details of your local modificationsAnother 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.
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 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. 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 pre-modified 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
Notesvn 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
README
$ svn delete README
D README
$ svn revert README
Reverted 'README'
$ svn status README
README
Resolve Conflicts (Merging Others' Changes)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
C bar.c
Updated to revision 46.
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 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. Whenever a conflict occurs, three things typically occur
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 which
delimit the “sides” of the
conflict–into the file to visibly demonstrate the
overlapping areas. (Subversion uses the
svn:mime-type property to decide if 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: filename.mineThis 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, then the
.mine file isn't created, since
it would be identical to the working file.) filename.rOLDREVThis 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.rNEWREVThis 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 in the repository. Harry has
just changed the file in his working copy and checked it in.
Sally updates her working copy before checking in and she gets
a conflict:
$ svn update
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 you 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
If you get a conflict, you need to do one of three
things: Merge the conflicted text “by hand” (by
examining and editing the conflict markers within the
file). Copy one of the temporary files on top of your
working file. Run svn revert <filename>
to throw away all of your local changes.
Once you've resolved the conflict, you need to let
Subversion know by running svn resolved.
This removes the three temporary files and Subversion no
longer considers the file to be in a state of
conflict.[6]
$ svn resolved sandwich.txt
Resolved conflicted state of 'sandwich.txt'
Merging Conflicts by HandMerging 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 conflicts.
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, equal 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
=======
The text between the second and third sets of conflict
markers is the text from Sally's commit:
=======
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. So 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.[7] Once you've agreed on the changes
you will check in, 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 run svn resolved, and you're
ready to commit your changes:
$ svn resolved sandwich.txt
$ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."
Note that svn resolved, unlike most
of the other commands we deal with in this chapter, requires
an argument. In any case, you want to be careful and only
run svn resolved 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. If you ever get confused while editing the conflicted
file, you can always consult the three files that Subversion
creates for you in your working copy–including your
file as it was before you updated. You can even use a
third-party interactive merging tool to examine those three
files. Copying a File Onto Your Working FileIf you get a conflict and decide that you want to throw
out your changes, you can merely copy one of the temporary
files created by Subversion over the file in your working
copy:
$ svn update
C sandwich.txt
Updated to revision 2.
$ ls sandwich.*
sandwich.txt sandwich.txt.mine sandwich.txt.r2 sandwich.txt.r1
$ cp sandwich.txt.r2 sandwich.txt
$ svn resolved sandwich.txt
Punting: Using svn revertIf you get a conflict, and upon examination decide that
you want to throw out your changes and start your edits
again, 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 run svn resolved. 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 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.
However, if you've been composing your log message as you
work, you may want to tell Subversion to get the message from
a file by passing the filename with the
--file (-F) option:
$ svn commit -F logmsg
Sending sandwich.txt
Transmitting file data .
Committed revision 4.
If you fail to specify either the
--message or --file option,
then Subversion will automatically launch your favorite editor
(see the editor-cmd section in
the section called “Config”) for composing a log
message. TipIf 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, 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 if your changes make
any sense as a whole; it only checks to make sure that 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 is out-of-date:
$ 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
…
(The exact wording of this error message depends on the
network protocol and server you're using, but the idea is the
same in all cases.) 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.
There are many other features in Subversion 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.
The Version Control with Subversion book is licensed under the Creative Commons Attribution License v2.0.
To submit comments, corrections, or other contributions to the text, please visit http://www.svnbook.com.
|