20 Mar 2009, 10:42 p.m.

Command-Line Subversion Tutorial, Part 1: The Basics

I'm constantly surprised by how many experienced developers are completely unfamiliar with using version control - such as Subversion or CVS - from the command line, instead preferring to rely on graphical clients such as TortoiseSVN.

Don't get me wrong - Tortoise has its uses - but I strongly recommend that any professional developer familiarise themselves with command-line version control. It's simpler, quicker and a thousand times more powerful.

In this post I'd like to help those developers out by covering the basics of command-line Subversion usage, via the svn command. I've optimistically named the post "Part 1" in the hope that I'll manage a follow-up post one day, covering more advanced issues such as merging and resolving conflicts. For now though, let's have a look at the basics.

Basic SVN Workflow

I'll use a running example here to illustrate a typical command-line SVN workflow. The example concerns itself with a simple HTML Web page, which currently displays a single image, hello.jpg. We'll assume for now that the site is already in Subversion, and that you know its Subversion URL (part two may cover how to get to this point).

The first thing you'll need to do in order to start work is to check yourself out a "working copy" of the code. I tend to cd into the directory I want the code to be in, which in this case is going to be the document root of a development version of the site. Checking out code is then achieved by use of the svn checkout command, or its terser alternative, svn co.

[simon@vps02 ~]$ cd /var/htdocs/hello/
[simon@vps02 hello]$ ls
[simon@vps02 hello]$ svn co svn://svnrepo/hellosite .
A    hello.jpg
A    index.html
Checked out revision 375.
[simon@vps02 hello]$ ls
hello.jpg  index.html

You can see there that two files have been checked out, and that we now have a copy of the latest revision, 375. That's all we need to do in order to start working.

Imagine that your task was to add a new image, mycat.jpg to the page (because there simply aren't enough cats on the Internet). This involved uploading the new image, and editing the HTML file to make it display the image.

In short, we've changed one file, and added another. To confirm our changes, we're going to use the svn status command. This is one of the most useful SVN commands, and you'll end up using this all the time.

[simon@vps02 hello]$ svn status
?      mycat.jpg
M      index.html

The "?" signifies that Subversion doesn't know anything about mycat.jpg. This is to be expected, as we've just uploaded it ourselves. The "M" by index.html stands for "modified", and tells us that Subversion knows that the file has indeed been modified.

If we want to remind ourselves what we changed, we can use svn diff to find out:

[simon@vps02 hello]$ svn diff index.html
Index: index.html
===========================================================
--- index.html  (revision 376)
+++ index.html  (working copy)
@@ -5,6 +5,7 @@
 <body>

 <img src="hello.jpg" />
+<img src="mycat.jpg" />

 </body>
 </html>

There is some slightly arcane syntax in there, but the key line is the one that says +<img src="mycat.jpg" />. The "+" signifies that Subversion knows that we added that one line of HTML code. That's pretty cool already.

So we've made our changes. If we wanted to, we could cancel everything by deleting the image file, and calling svn revert index.html, which would restore the original contents of the file. We're happy with these changes though, so the final stage in the workflow is to commit them back to Subversion. We can't just commit the new image file without telling Subversion that it exists in the first place. This is achieved by use of the svn add command:

[simon@vps02 hello]$ svn add mycat.jpg
A         mycat.jpg
[simon@vps02 hello]$ svn status
M      index.html
A      mycat.jpg

Great, it looks like that file has successfully been added, which we can see by that "A" next to its name. Now we can just commit the whole thing back, using svn commit:

[simon@vps02 hello]$ svn commit -m 'Added picture of my cat'
Sending        index.html
Adding         mycat.jpg
Transmitting file data ..
Committed revision 376.

Great news - our changes have been committed, and our work is done.

The -m option to svn commit allows us to enter a commit message - a brief description of our changes. If you omit that, you're likely to get dumped into an editor, typically vi, where you're expected to enter the message. This can be a little scary if you're not familiar with vi, so it's easiest just to put the message right there in the commit command.

Note that, unlike Tortoise, command-line SVN will not allow you to overlook adding a commit message. This is a good thing, and of course is no hardship for you: you were going to add a concise, meaningful commit message anyway, because you take a professional approach to your development work, right?

If you wish to commit only specific files, rather than everything that has been changed, you can specify the list of files which you want to commit by typing their names one after the other, after the commit message.

Keeping Your Working Copy Up-to-Date

In a team development environment, you won't be the only developer committing changes to the code. Let's skip forward a couple of weeks after adding the cat photo. You have a further change to make, but in the meantime, your colleague Bart has made some changes of his own to the site, adding a photo of his dog to the page. This means that your working copy is now out of date, and before you start work, you'll want to rectify that.

To check whether your copy is up-to-date, use svn status once again. This time, use the -u option, which causes svn to actually contact the repository and ask it for more information, rather than merely inspecting your local copy of the files. Note that svn status without the -u option reveals no changes, because we haven't worked on our local copy in the meantime.

[simon@vps02 hello]$ svn status
[simon@vps02 hello]$ svn status -u
       *      377   index.html
       *            mydog.jpg
       *      376   .

The "*" signifies that files have been changed in the repository, and in this case shows that our local copy is at revision 376 (the revision we committed when we added the cat photo). The index.html file has been modified, and mydog.jpg has been added. Both changes have been committed by Bart in revision 377. To bring our working copy up-to-date, simply run svn update:

[simon@vps02 hello]$ svn update
U    index.html
A    mydog.jpg
Updated to revision 377.

Job done: our copy of index.html has been updated ("U") to include Bart's changes, and we've also been given a copy of mydog.jpg, the photo of Bart's dog.

I'll end by just making you aware of svn move/svn mv, which is used for moving files within a working copy, and svn delete and svn copy/svn cp which you can probably figure out for yourself.

I mention these because you can't just move and delete files in a working copy and expect Subversion to know what you've done: you need to perform those operations through svn. After issuing any of these commands, you'll need to svn commit your changes in order for them to make it back into the repository.

Further Resources

So I hope I've given you a flavour of how to manage the basics of command-line Subversion. As I mentioned, I'll try to follow this up with some more advanced examples, but for now here's a couple of really useful resources.

The standard resource for Subversion is of course O'Reilly's "Version Control with Subversion" book. It's even available online, in a number of formats, all of which are completely and utterly free.

Secondly, I cannot recommend the excellent "Pragmatic Version Control with..." books highly enough. They very thoroughly cover how to perform all of these version control tasks, but that's interspersed with excellent, common sense advice on how to make your use of version control as efficient and as simple as possible.

Related Reading

Posted by Simon in Programming and Version Control
29 Jun 2009, 6:24 p.m.

Mohamed

Thank you a lot, that was very useful for me.

10 Jul 2009, 7:54 p.m.

sathakselva

Nice tutorial.. Thanks

26 Jul 2009, 1:22 a.m.

Chris

You say that using the command line is "a thousand times more powerful" than Tortoise, but I don't see any examples of this in your tutorial. Am I going to have to wait until Part 2?

26 Jul 2009, 2:03 a.m.

Simon Harris

Thanks Chris, nice to see a fellow Old Lidunian drop by :) Of course "1,000 times" was merely an artistic flourish, but I'd probably stand by it. Parts 2 and 3 are already online.

31 Aug 2009, 9:27 a.m.

bk1

Thanks for the tutorial, helped a lot...

15 Oct 2009, 7:19 p.m.

Khaled

Thanks Simon, but do I have to add every new file before making commit. I mean executing "add filename" command before commit?

20 Oct 2009, 4:32 a.m.

Yihui

I have the same question with Khaled. Withe Tortoise, I simply need to check all the new files before commits, but how can we commit all the new files with command line? Writing the file names can be time-consuming...

7 Feb 2010, 2:21 a.m.

John Nuss

when I enter the command:
svn co svn://svnrepo/hellosite
I get:svn: Unknown hostname 'svnrepo'

3 Mar 2010, 9:50 a.m.

Kishwar

Hi John Nuss, I am getting the same error. Have you solved it?

3 Mar 2010, 10:22 a.m.

Simon Harris

Guys -

In the text, the hostname 'svnrepo' is obviously just an example Subversion repository, invented for the purposes of illustration. You can't connect to it because it doesn't exist. You'd need to have access to your own repository in order to use Subversion.

4 Mar 2010, 7:31 a.m.

Kishwar

Hi Simon Haris, I am accessing the repository directly by using "file://" URL. I couldnt understand the function of "svn://" previously. Anyway, thanks for your response.

14 Jan 2011, 12:25 p.m.

Srivatsa

Damn Neat !!
Thanks a lot for the simple illustration

4 Feb 2011, 6:20 a.m.

Matthew Huckaby

Thank you, your explanation was lucid and effective.

2 Jun 2011, 7:53 p.m.

Pramod

Very nice and step by step explanation. Nice Job!

28 Oct 2011, 3:07 a.m.

d

very useful.easy to understand!

17 Apr 2013, 12:06 a.m.

Hammad

Awesome way of explanation

5 Aug 2013, 3:34 p.m.

Subrahmanyam Nilla

Good Tutorial,
Great Work, Thank you.

16 Jun 2016, 3:20 p.m.

Shaun Thomas

Well written tutorial. Good job!