============ 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.