Subversion¶
This is a short description of some of the frequently used features of the versioning software subversion as described in the subversion book. The things described here should work with subversion 1.3 and subversion 1.4.
Help¶
To get help on ‹command›
(e.g. diff
):
svn help ‹command›
Similarly:
svnadmin help ‹command›
svnlook help ‹command›
Repository URLs¶
Examples:
file:///home/‹user›/svn/myproject
svn+ssh://‹user›@‹machine›/home/‹user›/svn/myproject
No things like ~
or $HOME
allowed.
If you have a working copy of some repository and would like to gain general information as e.g. the repository url then, in the directory or your working copy, type:
svn info ./
Revision numbers¶
Many commands take an argument --revision ‹r›
(or equivalently -r ‹r›
).
The revision number ‹r›
is a whole number greater than 0 or HEAD
meaning
the latest revision or BASE
meaning the revision your local copy is based
on.
Importing¶
Create somewhere a temporary file tree containing all the files the repository needs to keep. E.g:
~/temp/myproject/
|--trunk/
| |--dirA/
| |--dirB/
| | |--anotherDir/
| | |--file1.aha
| | `--file2.aha
| |--dirC/
| |--fileA.ext
| `--fileB.ext
|--branches/
`--tags/
Then use the import facility:
svn import ~/temp/myproject ‹url› -m 'Initial import'
If message (-m
) is not given then $EDITOR
or $VISUAL
will
automatically start for you to compose a message.
Peeking into a repository¶
Use the svn list
command to peek into any sub-directory. E.g:
svn list -v ‹url›
svn list -v ‹url›/trunk/dirB
Use svnlook
to gain information on the whole repository. E.g:
svnlook info ~/svn/myproject -r ‹r›
gives information on revision ‹r›
.
svnlook tree ~/svn/myproject --show_ids
lists all directories and files in the tree.
Checking out a revision / making a local copy¶
After the following, ~/somedir
will contain the directory trunk
:
cd ~/somedir
svn checkout ‹url›/trunk
After the following, ~/someother
will contain the directory dirA
:
cd ~/someother
svn checkout ‹url›/trunk/dirA
After the following, the contents of trunk
will be in the newly created
directory ~/adir/projDir
:
cd ~/adir
svn checkout ‹url›/trunk projDir
To check out revision number ‹r›
:
svn checkout ‹url›/trunk -r ‹r›
Omitting -r
checks out the latest revision.
The local copy contains .svn
directories in every directory. Inside these a
copy of the BASE
revision (the one checked out or updated the last time) is
kept.
Committing the changes made¶
(Also called “checking in” your local version.) In your local project copy:
svn commit -m "Information about the chandes made"
When executed in some sub-directory of your local copy this will only send all files and sub-directories.
Usually you should do an update before a commit to merge the changes into your local copy in case somebody else has committed a new revision.
Updating the local copy¶
In your local project copy:
svn update
In some sub-directory of your local copy this will only update all files and sub-directories.
Short command names:¶
checkout |
co |
update |
up |
commit |
ci |
status |
st |
Moving a repository (also between different subversion versions)¶
Dump whole repository (using old version of svnadmin
):
svnadmin dump ~/svn/myproject > ~/dumpfile
Load into a new repository (using new version of svnadmin
):
svnadmin create --fs-type fsfs ~/svn2/myproject
svnadmin load ~/svn2/myproject < ~/dumpfile
Or load by means of a pipe:
svnadmin create --fs-type fsfs ~/svn2/myproject
svnadmin dump ~/svn/myproject | svnadmin load ~/svn2/myproject
Dump a range of revisions:
svnadmin dump ~/svn/myproject -r 101:200 > dumpfile-101-200
Read all log messages¶
In your local project copy:
svn log
In some sub-directory this might show only the log messages of those revisions which updated something inside the directory.
Or to show verbosely the log messages concerning a single file (or sub-directory):
svn log -v fileA.ext
Make changes to your local copy¶
Use svn add
, svn delete
, svn copy
and svn move
to let subversion
know about changes made concerning files, directories and symbolic links.
Note
svn copy
will result in a “cheap” copy (no data is really
duplicated) in contrast to copying a file with cp
and adding it again
with svn add
.
Information about your working copy¶
Display all file and tree changes made since the BASE
revision
in trunk
and all sub-directories:
cd ~/somedir/trunk
svn status
Status of file1.aha
:
svn status dirB/file1.aha
List all files and directories and their status:
svn status -v
List all file differences in the current directory and all sub-directories:
svn diff
Reverting to the BASE
revision¶
Undo changes made since you last checked out a revision (your BASE
revision)
using svn revert
. This will not delete any files in your local copy which
have not been added with svn add
. Also, no deleted directories can be
restored.
To reset the status and contents of fileA.txt
to the BASE
revision:
svn revert dirB/fileA.txt
To reset the status of the directory dirB
to the BASE
revision, without
caring about files and sub-directories inside the directory:
svn revert dirB
To reset the status of dirB
and the status and contents of all directories
and files in dirB
to the BASE
revision, without caring about
sub-sub-directories:
svn revert dirB/*
To reset the status of dirB
and the status and contents of all
sub-directories and files (recursively) inside dirB
to the BASE
revision:
svn revert dirB -R
Conflicts¶
Before committing a new revision make an svn update
. Thereby subversion
lists all files in conflict with the changes you made with a ‘C’. For every file
in conflict three additional files are created (e.g. ‹file›
is in
conflict):
‹file› |
A merged file with conflict markers in it |
‹file›.mine |
The file as it was before the update |
‹file›.r‹base› |
The file as it is in the BASE revision |
‹file›.r‹head› |
The file as downloaded in the newest revision |
As long as the three additional files are around, subversion considers ‹file›
to be in conflict. Remove them with:
svn resolved ‹file›
Conflict markers (<<<<<<
and ======
and >>>>>>
) are placed in the
merged file:
<<<<<< .mine
text I have written
=======
text somebody else has written in the
meantime and commited for revision 6
>>>>>> .r6
If I cannot resolve the conflict by hand I can svn revert
the file (no svn
resolved
necessary after this) or just copy one of the three versions onto
‹file›
and use svn resolved
.
Branching¶
Consider the following possible repository layout for myproject
:
~/svn/myproject/
|--trunk/
| |--dirA/
| `--A.txt
|--branches/
`--tags/
A branch is created by copying the trunk directory into branches
:
svn copy ‹url›/trunc ‹url›/branches/mybranch -m"creating branch"
This makes a “cheap” copy (no data duplicated) in the repository. Using svn
copy
on a local working copy of the project and committing the changes has
exactly the same effect.
Merging¶
svn merge
requires two files (or directories) to compare against each other,
similar to svn diff
. These can be given as:
‹url›/path1/file1[@‹n›] ‹url›/path2/file2[@‹m›]
or:
~/pathInLocalCopy1/file1[@‹n›] ~/pathInLocalCopy2/file2[@‹m›]
Alternatively revision numbers can be specified by means of the argument -r
n:m
.
Here ‹n›
and ‹m›
are revision numbers, []
means optional with
default HEAD
. path1/file1
and path2/file2
can identify the same
files/directories.
The differences are then applied as a patch to a target (which optionally can be omitted).
Examples:
svn merge -r 12:13 ‹url›/trunk/dirA
merges all changes from revision 12 to 13 in dirA
into the current
directory.:
svn merge -r 12:13 ‹url›/trunk/A.txt
merges the changes from revision 12 to 13 in A.txt
into the same file in the
current working directory.
Merge can be used to undo changes. E.g. to undo what has been commited in revision 13:
svn merge -r 13:12 ~/pathInLocalCopy/file
or equivalently:
svn merge -c -13 ~/pathInLocalCopy/file
Preview changes by:
svn diff -r 12:13 ‹url›/trunk/A.txt
Or use svn merge
with the option --dry-run
to print status messages.
Do an svn commit
before merging. After merging you have to commit the
changes. Mention the revision number(s) in the
commit message, there is no other way to tell later what has been merged.
In case of a conflict three files will be created:
‹file›.working |
My working copy before the merge |
‹file›.left |
The two files whose differences
should have been merged with
‹file›.working |
‹file›.right |
Tags¶
Tags are created exactly the same way like branches, e.g. a tag called
release-1.2
is created by:
svn copy ‹url›/trunk ‹url›/tags/release-1.2
If you have a local working copy myproject
which is a mixup from different
revisions and would like to create a tag special
from it:
svn copy myproject ‹url›/tags/special
The svnserve
server¶
Start svnserve
as a daemon publishing all repositories found under ~/svn
as follows:
svnserve -d -r ~/svn/
If ‹user›
runs the daemon on ‹host›
, then the ‹user›
s repository
in ~/svn/myproject
is accessible by other users as follows:
svn checkout svn://‹host›/myproject
Access control for myproject
is configured in the ‹user›
s files:
~/svn/myproject/conf/svnserve.conf
~/svn/myproject/conf/passwd
If you have ssh access to ‹host›
then you might also be able to checkout as
follows:
svn checkout svn+ssh://‹user›@‹host›/path_to_svn_repos/myproject
Your access rights are then the same as if you were ‹user›@‹host›
.
If a svnserve
process is already running and you are not root and want to
start your own svnserve
server process, then you might have to choose a
different port (default is 3690, so maybe use 3680) on which your svnserve
listens for requests:
svnserve -d --listen-port ‹port› --listen-host ‹host› -r ~/svn/
Then the corresponding checkout
is:
svn checkout svn://‹host›:‹port›/myproject
Keyword substitution¶
You can tell subversion to substitute certain strings (keywords) in certain
documents of the local copy with meaningfull content each time you do a
commit
. Keywords start and end with $
and are case sensitive:
Keyword | Substitute example | Keyword aliases |
---|---|---|
$Date$ |
$Date: 2006-07-22 21:42:37
-0700 (Sat, 22 Jul 2006)$ |
$LastChangedDate$ |
$Revision$ |
$Revision: 144$ |
$LastChangedRevision$ ,
$Rev$ |
$Author$ |
$Author: harry$ |
$LastChangedBy$ |
$HeadURL$ |
$HeadURL:
http://svn.a.net/repos/README$ |
$URL$ |
$Id$ |
$Id: calc.c 148 2006-07-28
21:30:43Z sally$ |
For keyword substitution to work, this feature must be enabled on a per-file basis. Subversion handles this by means of file properties. A local modification of the properties is e.g:
svn propset svn:keywords ‹keywords› ‹file›
where ‹keywords›
contains in double quotes the keywords for
which to enable substitution (e.g. "Date Author"
). In the
next commit, subversion will perform the substitution for the first
time.
To enable keyword substitution in all files under ‹directory›
:
svn propset -R svn:keywords ‹keywords› ‹directory›
Ignoring files / directories¶
There is a mechanism to let subversion ignore certain files or directories. It
is still possible to add them with svn add
but if not versioned, they will
not show up in svn status
.
One way to do this is via file properties. E.g. to edit ignore properties of
‹directory›
:
svn propedit svn:ignore ‹directory›
An editor will open where you can add lines (e.g. *.tmp
or ‹file or
directory name›
) indicating what files / directories under ‹directory›
will be ignored.
To set the svn:ignore
property on a directory using a ‹file›
containing
the ignore patterns (one per line) use:
svn propset svn:ignore --file ‹file› ‹directory›
Refactoring a repository¶
It can happen that you have (accidentally) commited files that really should not have been commited, e.g., large binary files or files that are secret or unrelated to the project. You can of course “delete” a file with:
svn rm <file>
svn ci -m "removing unwanted file"
But the file will still be in the repository. If you want to get rid of it (almost) completely you can follow this procedure:
Identify affected nodes
I give two ways of figuring out the exact paths/files we may want to drop, in case you don’t know them upfront.
First, assume that we are particularly interested in commits that have changed or added large amounts of data. Produce a list of all revisions sorted by their size:
for r in `svn log -q | grep ^r | cut -d ' ' -f 1 | tr -d r`; do echo "revision $r is " `svn diff -c $r | wc -c` " bytes" done | sort -k 4 -nr > revsize.txt
After this, we can examine
revsize.txt
and print files affected by some revision number‹r›
as:svn log -v -r ‹r›
Second, assume that we want to get rid of all (or some) files ending with
.‹ext›
. Find these files in the log of a local copy:svn log -v | grep -ie "\.‹ext›" | sed "s/ *[ADM] \///" | sed "s/ (.*)$//" | sort -u > list.txt
Filter the repository
First we have to dump the original repository:
svnadmin dump ~/path/to/repos > ~/dump
Then we use
svndumpfilter
produce afiltered_dump
in which the file/directory‹path›
has been omitted:svndumpfilter exclude "‹path›" < ~/dump > ~/filtered_dump
The
‹path›
must be fully specified, e.g.,trunc/dir/file.ext
ortrunc/dir
. Several paths to be dropped can be given.Alternatively, we can filter the dump by specifying the path(s) to keep:
svndumpfilter include "‹path›" < ~/dump > ~/filtered_dump
Note
svndumpfilter
is not very strong and may fail for complicated situations in which, e.g., files have been moved. See Svndumpsanitizer for a more sound filter.Create a new repository and load the filtered dump
svnadmin create ~/svn/myfilteredrepo svnadmin load ~/svn/myfilteredrepo < ~/filtered_dump
Now we can checkout this new repository.