October 25, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

A Crash Course in Subversion

  • April 22, 2005
  • By Garrett Rooney
  • Send Email »
  • More Articles »

Assuming that you're sure that this is what you want, it's time to publish the changes for everyone else to see with the svn commit command. Running svn commit is similar to using svn mkdir to create directories directly in the repository, in that both modify the repository. This means that the commit will require a log message, which again can be either specified on the command line via the -m or --file flag, or entered into a text editor before the commit will proceed. Here's an example:

$svn commit
Sending bar.c
svn:Transaction is out of date
svn:Commit failed (details follow):
svn:out of date:'/trunk/bar.c'in txn '8'
svn:Your commit message was left in a temporary file:
svn:   '/home/rooneg/work/my-project/svn-commit.tmp'
$

OK, that's definitely not what you would expect to see. It appears that someone has made a change to bar.c since you checked it out from the repository. Let's take a look at some commands that will tell you a bit more about what has happened. You've already learned that you can use svn status to see what you've changed in your local working copy, but it's also possible to pass it the -u flag, which tells svn status to contact the repository and figure out what files have been changed in more recent revisions. You can also use svn diff -rBASE:HEAD to see the difference between your BASE revision (the version you've checked out) and HEAD (the current version in the repository), and you can use svn log -r BASE:HEAD to read the log messages for the commits that may have caused the conflicts. Let's see how this works.

$svn status -u
M     *         2    bar.c
      *         2    foo.c
?                    svn-commit.tmp
Head revision:       3
$svn diff -r BASE:HEAD
Index:foo.c
===================================================================
---foo.c       (revision 3)
+++foo.c       (working copy)
@@-1, 5 +1, 5 @@
void
foo(int a, int b)
{
-printf ("a =%d, b =%d \n", a, b);
+printf ("arguments:a =%d, b =%d \n", a, b);
}
Index:bar.c
===================================================================
---bar.c        (revision 3)
+++bar.c        (working copy)
@@-1,5 +1,5 @@
void
bar (int a, int b)
{
-printf ("b =%d,a =%d \n", a, b);
+printf ("arguments:b =%d,a =%d \n", a, b);
}
$svn log -r BASE:HEAD
-------------------------------------------------------------------
r2 |rooneg |2003-06-08 09:56:24 -0400 (Sun,08 Jun 2003)|1 line
initial import of my project
-------------------------------------------------------------------
r3 |colonr |2003-06-08 10:00:42 -0400 (Sun,08 Jun 2003)|6 lines
*foo.c
(foo):changed output.
*bar.c
(bar):ditto.
-------------------------------------------------------------------
$

svn status -u shows you that both foo.c and bar.c have been changed since you checked them out (they have a *in column 8 of the status output), and svn-commit.tmp (which holds the log message from your failed commit) isn't under Subversion's control. Diffing the BASE and HEAD revisions show you that the line in bar.c that you changed had already changed in HEAD. svn log -r BASE:HEAD shows you that in revision 3 the user colonr changed the output in both foo.c and bar.c, causing the conflict.

Well, now you know why you can't commit the change in its current state, but that doesn't change the fact that you still need to get that bug fix into the repository. To do this, you'll need to run svn update, which will result in a conflict because your changes and those committed in revision 3 by the user colonr both changed the same line of bar.c. Then you'll have to manually fix the conflict and run svn resolved to tell Subversion that you're satisfied with it. Finally, you'll be able to run svn commit to get your fix into the repository.

$svn update
U foo.c
C bar.c
Updated to revision 3.
$ls
ls
bar.c          bar.c.r2      foo.c
bar.c.mine     bar.c.r3      svn-commit.tmp
$cat bar.c
cat bar.c
void
bar (int a, int b)
{
<<<<<<.mine
printf ("b =%d, a =%d \n", b, a);
=======
printf ("arguments:b =%d, a =%d \n", a, b);
>>>>>>.r3
}
$

So here you've run svn update, and it merged the change to foo.c into the version in your working copy (which isn't all that difficult, considering that you hadn't changed foo.c locally). Subversion also noticed that revision 3's change to bar.c conflicted with your local change, so it placed bar.c in a conflicted state (note the C in the output from svn update). When a file is in conflict, several things happen. First, several copies of the file are left in your working copy, one ending with .mine, which is your original modified version; one with .rOLDVERSION (r2 in this case), which holds the original version you started modifying (the BASE revision); and one ending in .rNEWVERSION (r3 in this case), which holds the new version (HEAD from the repository). These are present so that you can easily run third-party diff and merge programs on the files, and so you can refer to the various versions of the file easily while performing a merge. Second, assuming that the file in question is a textual file, and not a raw binary format, it's modified to show both your modified version of the change and the version from the repository. Third, some bookkeeping information about the conflict is recorded in the administrative directory. The next steps are to resolve the conflict manually and to run svn resolved to tell Subversion that you're satisfied with the changes.

$vi bar.c
[ ....resolve conflict manually ...]
$cat bar.c
void
bar (int a,int b)
{
   printf ("arguments:b =%d, a =%d \n", b, a);
}
$svn resolved bar.c
Resolved conflicted state of bar.c
$svn commit --file svn-commit.tmp
Sending       bar.c
Transmitting file data .
Committed revision 5.
$

Now your change has been committed to the repository. This general sequence of events—checkout, edit, update, status, diff, possibly resolve, and commit—will make up the majority of your time spent with Subversion, so be sure to become familiar with it.

More to Come
The rest of this sample chapter will appear on our Web site starting May 6th.

End Notes

1. Well, strictly speaking, you could check out a working copy, create the directories with a local svn mkdir, and then commit them all at once, but I haven't covered how to check out a working copy and commit changes yet, so let's not put the cart before the horse here.

2. Here, the "editor of choice" is determined by checking the SVN_EDITOR environment variable, then the editor-cmd option from the helpers section of ~/.subversion/config, then the VISUAL environment variable, and finally the EDITOR environment variable. As you might guess, it took a long time to get the developers to agree on that sequence of places to try to find a text editor.

About the Author

Garrett Rooney is a software engineer at FactSet Research Systems, in Stamford, Connecticut, where he works on real-time news feeds. Rooney attended Rensselaer Polytechnic Institute, where he managed to complete 3 years of a mechanical engineering degree before coming to his senses and realizing he wanted to get a job where someone would pay him to play with computers. Since then, Rooney completed a computer science degree at RPI and has spent far too much time working on a wide variety of open source projects, most notably Subversion.

About the Book

Practical Subversion By Garrett Rooney

Published: November 2004, Softbound, 336 pages
Published by Apress
ISBN 1-59059-290-5
Retail price: Price: $34.99
This material is from Chapter 2 of the book.





Page 5 of 5



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel