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 creation¶
Create a repository for the project myproject:
svnadmin create ~/svn/myproject
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:¶
|
|
|
|
|
|
|
|
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):
|
A merged file with conflict markers in it |
|
The file as it was before the update |
|
The file as it is in the |
|
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:
|
My working copy before the merge |
|
The two files whose differences
should have been merged with
|
|
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 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.txtand 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
svndumpfilterproduce afiltered_dumpin 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.extortrunc/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
svndumpfilteris 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.