########################################################################### # Subversion (0.14.2) Notes # # Anuradha Weeraman, 05 September 2002 # # Adapted from "svn-handbook" # # $Id: subversion.txt,v 1.1 2004/06/02 21:17:54 anuradha Exp $ # ########################################################################### Examples ======== svn commit search.c # commits changes svn update # updates working tree with source tree svn status # show the status code svn add foo.c # tagged for addition svn add dirname # add --recursive for recursion svn revert [items] # undo additions before committing svn commit # make additions permanent svn commit -m "desc" # make additions permanent svn update # required if working copy is out of date svn up # same as svn update svn rm foo.c # -f or --force removes file from working directory svn rm dirname # recursively remove directory svn undel foo.c # undelete the file svn undel dirname # --recursive to recurse svnadmin create myrepos # create repository svn import file:///absolute/path/to/repos /files/import-dir proj-name svn co file:///absolute/path/to/repos/proj-name # get a working copy svn co http://riv:8080/path/to/repos/proj-name # get a working copy also : svn checkout file:///absolute/path/to/repos/proj-name # get a working copy svn checkout http://riv:8080/path/to/repos/proj-name # get a working copy also : svn checkout file:///absolute/path/to/repos/proj-name dir # get a wc svn checkout http://riv:8080/path/to/repos/proj-name dir # get a wc svn cleanup # recursively cleanup the working copy (locks, operations etc) Flags ===== U : File was (U)pdated A : File or directory was (A)dded to your working copy D : File or directory was (D)eleted from your working copy R : File or directory was (R)eplaced in your working copy G : New updates were merged successfully C : Merge resulted in a (C)onflict. human intervention required. Tree Changes ============ svn add foo.c svn rm foo.c svn cp foo.c bar.c svn mv foo.c bar.c svn mkdir dirname Examine Changes =============== svn status svn status -v svn status -v -u # show which files are out of date codes: _ L ./abc.c [svn has a lock in its .svn directory for abc.c] M ./bar.c [the content in bar.c has local modifications] _M ./baz.c [baz.c has property but no content modifications] ? ./foo.o [svn doesn't manage foo.o] ! ./foo.c [svn knows foo.c but a non-svn program deleted it] ~ ./qux [versioned as dir, but is file, or vice versa] A + ./moved_dir [added with history of where it came from] M + ./moved_dir/README [added with history and has local modifications] D ./stuff/fish.c [this file is scheduled for deletion] A ./stuff/things/bloo.h [this file is scheduled for addition] svn diff svn diff -r 3 # working files are compared to particular revision svn diff -r 3:5 # the two revisions are compared svn diff -r 22:23 http://foo.com/some/project # inspect changes even when working copy is not available svn revert file # throws away all changes to a file svn resolve # automatically remove tempfiles after a conflicting merg svn log # see logs in reverse chronological order svn log foo.c # see logs for a particular file svn log -r 5:9 # see logs for revisions 5-9 Branch ====== svn cp http://foo.com/repos/project http://foo.com/repos/project-beta svn switch http://foo.com/repos/project-beta/subsystem/network subsytem/network # to switch part of the working copy to another branch svn merge -r 101:102 http://foo.com/repos/project-beta/subsystem/network # merge code from another branch # these changes can be examined using svn diff, svn status and removed # with svn revert svn merge -r 10:9 # to get back a previous revision when current rev is 10 svn merge -r 10:9 bar/ bar/ # you need to specify where it should be merged to svn rm http://foo.com/repos/project-bad-branch -m "removing bad branch" * Read up on Vendor Branches Properties ========== svn propset color green foo.c # add a new property svn propset x-face -F joeface.jpg foo.c # binary properties svn propget color foo.c # retrieve property svn propedit color foo.c # opens value of property in $EDITOR svn proplist foo.c # display all properties svn proplist foo.c --verbose # ditto... verbosely svn status # display changes to wc... notice _M svn propdel color foo.c # remove property svn diff # see the changes to wc svn revert foo.c # revert to original version svn commit -m "property changes" # to commit the property changes Special Properties ================== svn:executable # causes a file's permissions to be executable svn:mime-type # mime type of a file, will be used by mod_dav svn:ignore # filenames to ignore for svn status, eg. *.o svn:keywords # substitute strings in file $Id: subversion.txt,v 1.1 2004/06/02 21:17:54 anuradha Exp $ $Date: 2004/06/02 21:17:54 $ or $LastChangedDate$ $LastChangedRevision$ $LastChangedBy$ $URL$ or $HeadURL$ e.g. svn propset svn:keywords "Date Author" foo.c svn:eol-style # LF, CR, CRLF or native svn:externals e.g. $ svn propget svn:externals projectdir subdir1/foo http://url1/repos/proj/foo subdir2/bar http://url2/repos/proj/minto subdir3/baz http://different.url/proj/subdir/yepo svn checkout http://myhost/repos/projectdir Revisions ========= Apart from specifying the revision numbers after -r, subversion also understands several revision keywords. They are : HEAD : The latest revision in the repository BASE : The pristine revision of an item in the working copy COMMITTED : The last revision in which an item changed PREV : COMMITTED - 1 svn diff -r PREV:COMMITTED foo.c # last changed committed to foo.c svn log -r HEAD # shows log message for latest commit svn diff -r HEAD # diffs to the latest commit svn diff -r BASE:HEAD foo.c # compares pristine wc to latest commit svn log -r BASE:HEAD # all logs since last update svn update -r PREV foo.c # rewinds last change on foo.c Other Commands ============== svn cleanup # searches wc and re-runs leftover logs & removes locks # locked files will have an 'L' in svn status svn info foo.c # display tracked information about a file svn import # move a versioned tree of files into repository svnadmin create /usr/local/svn/newrepos svn import file:///usr/local/svn/newrepos /usr/local/mytree svn import file:///usr/local/svn/newrepos /usr/local/mytree fooproject svn export # create an unversioned copy of repository svn export file:///usr/local/svn/newrepos/fooproject svn ls http://riv/svn/repos/fooproject svn ls -v http://riv/svn/repos/fooproject svn mkdir new-dir # create new dir in working copy svn mkdir http://riv/svn/repos/fooproject/newdir -m "new dir" # no wc needed Repository Administration ======================== svnadmin and svnlook operate directly on the repository so they expect ordinary local paths to the repositories. A repository begins life at revision 0, and is nothing but the '/' directory. Every revision is created with an 'svn:date' timestamp property. Other common properties include 'svn:author' and 'svn:log'. Revision 0 is nothing but an 'svn:date' property attached to it. Repository directory structure : conf - currently unused dav - private housekeeping databases if the repository is accessed via Apache and mod_dav_svn db - main Berkeley DB environment. full of db tables that comprise the data store used by libsvn_fs. this is where all your data is. most of your files' contents end up in the 'strings' table. log files accumulate here as well, so transactions can be recovered. hooks - where pre-commit, post-commit hook scripts live. locks - a single file lives here. repository readers and writers take out shared locks on this file. Do not remove this file. A subversion repository is essentially a sequence of trees of revisions. Each revision begins its life as a transaction tree. In the case of updates the transactions are temporary trees that are immediately destroyed afterwards, in the case of commits, transactions are converted into permanent revisions. svnlook ======= svnlook is a read-only tool that can be used to examine the revision and transaction trees within a repository. svnlook repos # will print info about the HEAD rev of the repository svnlook repos rev 522 # revision 522 svnlook repos txn 343 # transaction 343 svnlook repos rev 522 subcommands: log : print the tree's log message author : print the tree's author date : print the tree's datestamp dirs-changed : list the directories that changed in the tree changed : list all files and dirs that changed diff : print a unified diff of changed files svnadmin shell ============== svnadmin has a toy shell mode which allows you to browse the repository like a normal file system. the basic commands are : cd ls exit help and the special command : cr (change revision) which allows you to move between revision trees. Repository Hooks ================ A "hook" is a program triggered by a repository read or write access. It is handed enough information to tell what action it is, what target(s) it is operating on and who's doing it. Depending on the hook's output or return status, the hook program may continue the action, stop it, or suspend it in some way. Subversion's hooks are programs that live in the hooks directory of the repository. The *.tmpl files are just templates and need to be copied into files without the tmpl extension to make a customized hook. * read-sentinels and write-sentinels are not yet implemented hooks : start-commit : run before the committers transaction is even created. typically checks if the user has commit privileges. repository passes two args to this program, the path to repos, and the username. pre-commit : run when the transaction is complete but before it is committed. this hook is used to protect against commits that are disallowed due to content or location post-commit : run after the transaction is completed and when there is a new revision. used to send out descriptive commit emails or to make a hot backup of the repository. At the moment, hook scripts are the only way to implement access control apart from that done by the web server. Embedded ACLs are a proposed feature. Berkeley DB Management ====================== Berkeley DB comes with a number of tools for managing the DB files in the repos/db directory. Berkeley DB has genuine transactions. Every attempt to change the DB is first logged. If anything goes wrong, the DB can back itself up to a previous 'checkpoint' and replay transactions to get the data back into a sane state. Sometimes, a bug in subversion can crash it, keeping the DB in a locked state, hanging subversion the next time its run. To overcome this : 1) Shut down the subversion server to make sure nobody is accessing the DB files 2) Switch to the user who owns and manages the database 3) Run the command 'db_recover -v -h REPOS/db', make sure db_recover is the same version that came with that particular version of Berkeley DB. 4) Restart the subversion server Log files are used to log transactions. When one log file reaches 10MB a new one is started and the old one continues to exist. To find out which log files aren't being actively written to : db_archive -a -h repos/db This is useful when trying to do a backup while the repos is still running. Tweaking with svnadmin ====================== Be careful with svnadmin, cos unlike svnlook which is read-only, svnadmin has the ability to alter the repository. A commit's log message is an unversioned property directly attached to the revision object. There is only ONE log message per revision. Sometimes it needs to be replaced. echo "New, correct log message" > newlog.txt svnadmin setlog repos 388 newlog.txt Another use of svnadmin is to inspect and clean up old, dead transactions. Commits and updates both create transaction trees but occasionally a bug or crash can leave them lying around. By inspecting the datestamp of a transaction the administrator can decide to remove them or not. svnadmin lstxns repository svnadmin lstxns --long repository svnadmin rmtxns repository 319 321 When a user attempts to access an earlier revision, the repository must apply a sequence of backwards-deltas to the newest fulltexts in order to derive the older data. If a particular revision tree is extremely popular, the administrator can speed up the access time to this tree by 'undeltifying' any path within the revision - that is, by converting every file to fulltext. svnadmin undeltify myrepos 230 /project/tag/release-1.3 Networking a Repository ======================= Subversion's primary network server is Apache httpd speaking WebDAV/deltaV protocol, which is a set of extension methods to HTTP. To network your repository : 1) get Apache httpd 2.0 running with mod_dav 2) install mod_dav_svn plugin to mod_dav, which uses subversion's libraries to access the repository 3) configure httpd.conf to export the repository To httpd.conf : DAV svn SVNPath /absolute/path/to/svn/repos This makes repos available at http://hostname/svn/repos Alternately, you can use SVNParentPath directive to indicate a parent directory whose immediate subdirectories are assumed to be independent repositories. DAV svn SVNParentPath /absolute/path/to/svn/repos If you were to run 'svnadmin create foorepo' within ^ parent directory, then url http://hostname/svn/repos/foorepo would automatically be accessible without having to change httpd.conf or restart httpd. Next: access restrictions. Currently, Anyone can : Checkout ahything Browse repository using browser Make commits To restrict read/write access, you have to use Apache built in access control features. 1) use htpasswd to create a password file 2) add the following to httpd.conf AuthType Basic AuthName "Subversion Repository" AuthUserFile /path/to/passwd/file if you want to restrict *ALL* access : Require valid-user to restrict write-access only : Require valid-user *note: in order for 'svn cp' to work (which is implemented as a DAV COPY request), mod_dav needs to be able to determine the hostname of the server. A standard way of doing this is to use the ServerName directive in httpd.conf. Migrating a Repository ====================== Sometimes situations arise that need you to move all of your filesystem data from one repository to another. Like: 1) change of internal fs database schema 2) you'd like to start using a different database backend This is done by 'svnadmin dump' and 'svnadmin load' commands. 'svnadmin dump' writes a stream of your repository data to stdout. svnadmin dump myrepos > dumpfile The stream describes every change in your repository as a list of change to nodes. After dumping your data, you would then move your file to a different system (or somehow alter the environment to use a different version of svnadmin or libsvn_fs) and create a new repository that has a new schema or db backend. svnadmin create newrepos then you restore the db fs by : svnadmin load newrepos < dumpfile your revisions will then by committed to the new repository. To create a dumpfile with a specific range of revisions : svnadmin dump myrepos 23 > rev-23.dump svnadmin dump myrepos 23 50 > revs-23-50.dump The first revision created is compared with revision 0 which is the empty root directory. More examples : to dump : svnadmin dump myrepos 0 1000 > dumpfile1 svnadmin dump --incremental 1001 2000 > dumpfile2 svnadmin dump --incremental 2001 3000 > dumpfile3 to restore : svnadmin load myrepos < dumpfile1 svnadmin load myrepos < dumpfile2 svnadmin load myrepos < dumpfile3 This can be used for incremental backups. WebDAV ====== Subversion uses WebDAV (Web Based Distributed Authoring and Versioning) as its primary network protocol. WebDAV was designed to make the web into a read/write medium rather than a read-only one. The theory is that directories and files can be shared over the web using standardized extensions to HTTP. However RFC 2518 doesn't fully implement the versioning aspect of WebDAV. A separate committee has created RFC 3253 known as the DeltaV extensions to WebDAV. These extensions add version-control concepts to HTTP and this is what Subversion uses. The subversion client is not a general purpose DeltaV client and the server only implements a subset of the DeltaV protocol. Future versions of subversion will address more complete WebDAV interoperability. At the moment, most DAV browsers and clients do not support the DeltaV protocol and so the repository can only be mounted read-only. An HTTP put request is valid only when sent to a WebDAV-only server, but a DeltaV server such as mod_dav_svn will not allow it. The client must use special version control methods to write to the server. And on the flip side, a subversion client cannot cannot checkout a working copy from a generic WebDAV server; it expects a specific subset of DeltaV features. Source Code Formatting ====================== Subversion diffs and merges text files work on a line-by-line basis. They don't understand the syntax of programming languages or even know when you've just reflowed text to a different line width. Given this design, it's important to avoid unnecessary reformatting. It creates unnecessary conflicts when merging branches, updating working copies, and applying patches. It also can drown you in noise when viewing differences between revisions. Line Endings ============ Different platforms (Unix, Windows, MacOS) have different conventions for marking the line endings of text files. Simple editors may rewrite line endings, causing problems with diff and merge. This is a subset of the formatting problems. Subversion has built-in support for normalizing line endings. To enable it, set the `svn:eol-style' property to "native". When You Commit =============== It pays to take some time before you commit to review your changes and create an appropriate log message. You are publishing the newly changed project anew every time you commit. This is true in two senses: * When you commit, you are potentially destabilizing the head revision. Many projects have a policy that the head revision is "stable" -- it should always parse/compile, it should always pass unit tests, etc. If you don't get something right, you may be inconveniencing an arbitrary number of people until someone commits a fix. * You can not easily remove revisions. (There is no equivalent to `cvs admin -o'.) If you might not want something to be in the repository, make sure it is not included in your commit. Check for sensitive information, autogenerated files, and unnecessary large files. Binary Files ============ Subversion does not have any way to merge or view differences of binary files, so it's critical that these have accurate log messages. Since you can't review your changes with `svn diff' immediately before committing, it's a particularly good idea to write the log entry as you go. Revision Numbers Are Different Now ---------------------------------- In CVS, revision numbers are per-file. This is because CVS uses RCS as a backend; each file has a corresponding RCS file in the repository, and the repository is roughly laid out according to structure of your project tree. In Subversion, the repository looks like a single filesystem. Each commit results in an entirely new filesystem tree; in essence, the repository is an array of trees. Each of these trees is labeled with a single revision number. When someone talks about "revision 54," they're talking about a particular tree (and indirectly, the way the filesystem looked after the 54th commit). Technically, it's not valid to talk about "revision 5 of `foo.c'". Instead, one would say "`foo.c' as it appears in revision 5." Also, be careful when making assumptions about the evolution of a file. In CVS, revisions 5 and 6 of `foo.c' are always different. In Subversion, it's most likely that `foo.c' did *not* change between revisions 5 and 6. Subversion vs CVS ================= More disconnected operations ---------------------------- In recent years, disk space has become outrageously cheap and abundant, but network bandwidth has not. Therefore, the Subversion working copy has been optimized around the scarcer resource. The `.svn' administrative directory serves the same purpose as the `CVS' directory, except that it also stores "pristine" copies of files. This allows you to do many things off-line: * `svn status' shows you local modifications (see below) * `svn diff' shows you the details of your modifications * `svn ci' sends differences to the repository (CVS only sends fulltexts!) * `svn revert' removes your modifications Distinction between status and update ------------------------------------- In Subversion, we've tried to erase a lot of the confusion between the `status' and `update' subcommands. The `status' command has two purposes: (1) to show the user any local modifications in the working copy, and (2) to show the user which files are out-of-date. Unfortunately, because of CVS's hard-to-read output, many CVS users don't take advantage of this command at all. Instead, they've developed a habit of running `cvs up' to quickly see their mods. Of course, this has the side effect of merging repository changes that you may not be ready to deal with! With Subversion, we've tried to remove this muddle by making the output of `svn status' easy to read for humans and parsers. Also, `svn update' only prints information about files that are updated, _not_ local modifications. Here's a quick guide to `svn status'. We encourage all new Subversion users to use it early and often: * `svn status' prints all files that have local modifications; the network is not accessed by default. * `-u' switch add out-of-dateness information from repository * `-v' switch show _all_ entries under version control * `-n' switch nonrecursive The status command has two output formats. In the default "short" format, local modifications look like this: % svn status M ./foo.c M ./bar/baz.c If you specify either the `-u' or `-v' switch, a "long" format is used: % svn status M 1047 ./foo.c _ * 1045 ./faces.html _ * - ./bloo.png M 1050 ./bar/baz.c Head revision: 1066 In this case, two new columns appear. The second column contains an asterisk if the file or directory is out-of-date. The third column shows the working-copy's revision number of the item. In the example above, the asterisk indicates that `faces.html' would be patched if we updated, and that `bloo.png' is a newly added file in the repository. (The `-' next to bloo.png means that it doesn't yet exist in the working copy.) Lastly, here's a quick summary of status codes that you may see: A Add D Delete R Replace (delete, then re-add) M local Modification U Updated G merGed C Conflict Meta-data properties -------------------- A new feature of Subversion is that you can attach arbitrary metadata to files and directories. We refer to this data as "properties", and they can be thought of as collections of name/value pairs (hashtables) attached to each item in your working copy. To set or get a property name, use the `svn propset' and `svn propget' subcommands. To list all properties on an object, use `svn proplist'. Directory versions ------------------ Subversion tracks tree structures, not just file contents. It's one of the biggest reasons Subversion was written to replace CVS. Here's what this means to you: * the `svn add' and `svn rm' commands work on directories now, just as they work on files. So do `svn cp' and `svn mv'. However, these commands do *not* cause any kind of immediate change in the repository. Instead, the working directory is recursively "scheduled" for addition or deletion. No repository changes happen until you commit. * Directories aren't dumb containers anymore; they have revision numbers like files. (Or more properly, it's correct to talk about "directory `foo/' in revision 5".) Conflicts --------- CVS marks conflicts with in-line "conflict markers", and prints a `C' during an update. Historically, this has caused problems. Many users forget about (or don't see) the `C' after it whizzes by on their terminal. They often forget that the conflict-markers are even present, and then accidentally commit garbaged files. Binary files ------------ CVS users have to mark binary files with `-kb' flags, to prevent data from being munged (due to keyword expansion and line-ending translations). They sometimes forget to do this. Subversion examines the `svn:mime-type' property to decide if a file is text or binary. If the file has no `svn:mime-type' property, Subversion assumes it is text. If the file has the `svn:mime-type' property set to anything other than `text/*', it assumes the file is binary. Subversion also helps users by running a binary-detection algorithm in the `svn import' and `svn add' subcommands. These subcommands will make a good guess and then (possibly) set a binary `svn:mime-type' property on the file being added. (If Subversion guesses wrong, you can always remove or hand-edit the property.) As in CVS, binary files are not subject to keyword expansion or line-ending conversions. Also, when a binary file is "merged" during update, no real merge occurs. Instead, Subversion creates two files side-by-side in your working copy; the one containing your local modifications is renamed with an `.orig' extension. Authorization ------------- Unlike CVS, SVN can handle anonymous and authorized users in the same repository. There is no need for an anonymous user or a separate repository. If the SVN server requests authorization when committing, the client should prompt you for your authorization (password). Branches and tags ----------------- Subversion doesn't distinguish between filesystem space and "branch" space; branches and tags are ordinary directories within the filesystem. This is probably the single biggest mental hurdle a CVS user will need to climb. User impact ----------- Really, the Subversion client seems to have two difficult--almost contradictory--goals. First, it needs to make the user experience friendly, which generally means being a bit "sloppy" about deciding what a user can or cannot do. This is why it allows mixed-revision working copies, and why it tries to let users execute local tree-changing operations (delete, add, move, copy) in situations that aren't always perfectly, theoretically "safe" or pure. Second, the client tries to keep the working copy in correctly in sync with the repository using as little communication as possible. Of course, this is made much harder by the first goal! So in the end, there's a tension here, and the resolutions to problems can vary. In one case (the "lagging directory"), the problem can be solved through a bit of clever entry tracking in the client. In the other case ("the overeager directory"), the only solution is to restrict some of the theoretical laxness allowed by the client.