============
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
.. _svnRepoURL:
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›.right`` | ``‹file›.working`` |
+--------------------+-----------------------------------+
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/
.. You might want to add this line to your ``.login`` script (if you don't have
root access) or have it as a startup script in your boot process.
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 ``$LastChangedDate$``
-0700 (Sat, 22 Jul 2006)$``
``$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
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:
1. **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
2. **Filter the repository**
First we have to dump the original repository::
svnadmin dump ~/path/to/repos > ~/dump
Then we use ``svndumpfilter`` produce a ``filtered_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`` or
``trunc/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.
3. **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.