Your Subversion repository is like a time machine. It keeps a record of every change ever committed and allows you to explore this history by examining previous versions of files and directories as well as the metadata that accompanies them. With a single Subversion command, you can check out the repository (or restore an existing working copy) exactly as it was at any date or revision number in the past. However, sometimes you just want to peer into the past instead of going into it.
Several commands can provide you with historical data from the repository:
- svn diff
Shows line-level details of a particular change
- svn log
Shows you broad information: log messages with date and author information attached to revisions and which paths changed in each revision
- svn cat
Retrieves a file as it existed in a particular revision number and displays it on your screen
- svn annotate
Retrieves a human-readable file as it existed in a particular revision number, displaying its contents in a tabular form with last-changed information added to each line of the file
- svn list
Displays the files in a directory for any given revision
We've already seen svn diff before—it displays file differences in unified diff format; we used it to show the local modifications made to our working copy before committing to the repository.
In fact, it turns out that there are three distinct uses of svn diff:
Examining local changes
Comparing your working copy to the repository
Comparing repository revisions
As we've seen, invoking
svn diff with
no options will compare your working files to the cached
“pristine” copies in
$ svn diff Index: rules.txt =================================================================== --- rules.txt (revision 3) +++ rules.txt (working copy) @@ -1,4 +1,5 @@ Be kind to others Freedom = Responsibility Everything in moderation -Chew with your mouth open +Chew with your mouth closed +Listen when others are speaking $
If a single
-r) number is passed, your
working copy is compared to the specified revision in the
$ svn diff -r 3 rules.txt Index: rules.txt =================================================================== --- rules.txt (revision 3) +++ rules.txt (working copy) @@ -1,4 +1,5 @@ Be kind to others Freedom = Responsibility Everything in moderation -Chew with your mouth open +Chew with your mouth closed +Listen when others are speaking $
If two revision numbers, separated by a colon, are
-r), the two revisions are directly
$ svn diff -r 2:3 rules.txt Index: rules.txt =================================================================== --- rules.txt (revision 2) +++ rules.txt (revision 3) @@ -1,4 +1,4 @@ Be kind to others -Freedom = Chocolate Ice Cream +Freedom = Responsibility Everything in moderation Chew with your mouth open $
A more convenient way of comparing one revision to the
previous revision is to use the
$ svn diff -c 3 rules.txt Index: rules.txt =================================================================== --- rules.txt (revision 2) +++ rules.txt (revision 3) @@ -1,4 +1,4 @@ Be kind to others -Freedom = Chocolate Ice Cream +Freedom = Responsibility Everything in moderation Chew with your mouth open $
Lastly, you can compare repository revisions even when you don't have a working copy on your local machine, just by including the appropriate URL on the command line:
$ svn diff -c 5 http://svn.example.com/repos/example/trunk/text/rules.txt … $
To find information about the history of a file or directory, use the svn log command. svn log will provide you with a record of who made changes to a file or directory, at what revision it changed, the time and date of that revision, and—if it was provided—the log message that accompanied the commit:
$ svn log ------------------------------------------------------------------------ r3 | sally | 2008-05-15 23:09:28 -0500 (Thu, 15 May 2008) | 1 line Added include lines and corrected # of cheese slices. ------------------------------------------------------------------------ r2 | harry | 2008-05-14 18:43:15 -0500 (Wed, 14 May 2008) | 1 line Added main() methods. ------------------------------------------------------------------------ r1 | sally | 2008-05-10 19:50:31 -0500 (Sat, 10 May 2008) | 1 line Initial import ------------------------------------------------------------------------
Note that the log messages are printed in
reverse chronological order by default.
If you wish to see a different range of revisions in a
particular order or just a single revision, pass the
Table 2.1. Common log requests
||Display logs for revisions 5 through 19 in chronological order|
||Display logs for revisions 5 through 19 in reverse chronological order|
||Display logs for revision 8 only|
You can also examine the log history of a single file or directory. For example:
$ svn log foo.c … $ svn log http://foo.com/svn/trunk/code/foo.c …
These will display log messages only for those revisions in which the named file (or directory) changed.
If you want even more information about a file or
directory, svn log also takes a
Because Subversion allows you to move and copy files and
directories, it is important to be able to track path changes
in the filesystem. So, in verbose mode, svn
log will include a list of changed paths in a
revision in its output:
$ svn log -r 8 -v ------------------------------------------------------------------------ r8 | sally | 2008-05-21 13:19:25 -0500 (Wed, 21 May 2008) | 1 line Changed paths: M /trunk/code/foo.c M /trunk/code/bar.h A /trunk/code/doc/README Frozzled the sub-space winch. ------------------------------------------------------------------------
svn log also takes
-q) option, which
suppresses the body of the log message. When combined
gives just the names of the changed files.
As of Subversion 1.7, users of the Subversion command-line
can also take advantage of a special output mode
for svn log which integrates a difference
report such as is generated by the svn diff
command we introduced earlier. When you invoke svn
log with the
Subversion will append to each revision log chunk in the log
report a diff-style difference report.
This is a very convenient way to see both the high-level, semantic
changes and the line-based modifications of a revision all at
the same time!
Beginning with Subversion 1.8, svn log
options. The options allow you to filter the output of
svn log based on the search pattern you
supply. When using these options, a log message is shown
only if a revision's author, date, log message text, or list
of changed paths, matches the search pattern.
Using svn cat and svn list, you can view various revisions of files and directories without changing the working revision of your working copy. In fact, you don't even need a working copy to use either one.
If you want to examine an earlier version of a file and not necessarily the differences between two files, you can use svn cat:
$ svn cat -r 2 rules.txt Be kind to others Freedom = Chocolate Ice Cream Everything in moderation Chew with your mouth open $
You can also redirect the output directly into a file:
$ svn cat -r 2 rules.txt > rules.txt.v2 $
Very similar to the svn cat command we discussed in the previous section is the svn annotate command. This command also displays the contents of a versioned file, but it does so using a tabular format. Each line of output shows not only a line of the file's content but also the username, the revision number and (optionally) the datestamp of the revision in which that line was last modified.
When used with a working copy file target, svn annotate will by default show line-by-line attribution of the file as it currently appears in the working copy.
$ svn annotate rules.txt 1 harry Be kind to others 3 sally Freedom = Responsibility 1 harry Everything in moderation - - Chew with your mouth closed - - Listen when others are speaking
Notice that for some lines, there is no attribution
provided. In this case, that's because those lines have
been modified in the working copy's version of the file. In
this way, svn annotate becomes another
way for you to see which lines in the file you have
changed. You can use the
keyword (see the section called “Revision Keywords”) to
instead see the unmodified form of the file as it resides
in your working copy.
$ svn annotate rules.txt@BASE 1 harry Be kind to others 3 sally Freedom = Responsibility 1 harry Everything in moderation 1 harry Chew with your mouth open
--verbose (-v) option causes
svn annotate to also include on each line
the datestamp associated with that line's reported revision
number. (This adds a significant amount of width to each
line of ouput, so we'll skip the demonstration here.)
As with svn cat, you can also ask svn annotate to display previous versions of the file. This can be a handy trick when, after finding out who most recently modified a particular line of interest in the file, you then wish to see who modified the same line prior to that.
$ svn blame rules.txt -r 2 1 harry Be kind to others 1 harry Freedom = Chocolate Ice Cream 1 harry Everything in moderation 1 harry Chew with your mouth open
Unlike the svn cat command, the
functionality of svn annotate is tied
heavily to the idea of “lines” of text in a
human-readable file. As such, if you attempt to run the
command on a file that Subversion has determined is
not human-readable (per the file's
svn:mime-type property—see the section called “File Content Type” for
details), you'll get an error message.
$ svn annotate images/logo.png Skipping binary file (use --force to treat as text): 'images/logo.png' $
As revealed in the error message, you can use
--force option to disable this check
and proceed with the annotation as if the file's contents
are, in fact, human-readable and line-based. Naturally, if
you force Subversion to try to perform line-based annotation
on a nontextual file, you'll get what you asked for: a
screenful of nonsense.
$ svn annotate images/logo.png --force 6 harry \211PNG 6 harry ^Z 6 harry 7 harry \274\361\MI\300\365\353^X\300…
Depending on your mood at the time you execute this
command and your reasons for doing so, you may find
svn blame …
svn praise … instead of
using the canonical svn annotate
command form. That's okay—the Subversion developers
anticipated as much, so those particular command aliases
Finally, as with many of Subversion's informational commands, you can also reference files in your svn annotate command invocations by their repository URLs, allowing access to this information even when you don't have ready access to a working copy.
The svn list command shows you what files are in a repository directory without actually downloading the files to your local machine:
$ svn list http://svn.example.com/repo/project README branches/ tags/ trunk/
If you want a more detailed listing, pass the
-v) flag to get
output like this:
$ svn list -v http://svn.example.com/repo/project 23351 sally Feb 05 13:26 ./ 20620 harry 1084 Jul 13 2006 README 23339 harry Feb 04 01:40 branches/ 23198 harry Jan 23 17:17 tags/ 23351 sally Feb 05 13:26 trunk/
The columns tell you the revision at which the file or directory was last modified, the user who modified it, the size if it is a file, the date it was last modified, and the item's name.
svn list command with no
arguments defaults to the repository
URL of the current working
directory, not the local working copy
directory. After all, if you want a listing of your local
directory, you could use just plain
ls (or any reasonable non-Unixy
In addition to all of the previous commands, you can use
with svn update to take an entire working
copy “back in time”:
# Make the current directory look like it did in r1729. $ svn update -r 1729 Updating '.': … $
Many Subversion newcomers attempt to use the preceding svn update example to “undo” committed changes, but this won't work as you can't commit changes that you obtain from backdating a working copy if the changed files have newer revisions. See the section called “Resurrecting Deleted Items” for a description of how to “undo” a commit.
If you'd prefer to create a whole new working copy from an
older snapshot, you can do so by modifying the typical
svn checkout command. As with svn
update, you can provide
But for reasons that we cover in
the section called “Peg and Operative Revisions”, you might instead want
to specify the target revision as part of Subversion's
expanded URL syntax.
# Checkout the trunk from r1729. $ svn checkout http://svn.example.com/svn/repo/trunk@1729 trunk-1729 … # Checkout the current trunk as it looked in r1729. $ svn checkout http://svn.example.com/svn/repo/trunk -r 1729 trunk-1729 … $
Lastly, if you're building a release and wish to bundle up
your versioned files and directories, you can use svn
export to create a local copy of all or part of your
repository without any
administrative directories included. The basic syntax of this
subcommand is identical to that of svn
# Export the trunk from the latest revision. $ svn export http://svn.example.com/svn/repo/trunk trunk-export … # Export the trunk from r1729. $ svn export http://svn.example.com/svn/repo/trunk@1729 trunk-1729 … # Export the current trunk as it looked in r1729. $ svn export http://svn.example.com/svn/repo/trunk -r 1729 trunk-1729 … $
 See? We told you that Subversion was a time machine.