Chapter 2. Best Practices

Tips to use Subversion more effectively.

In this chapter, we'll focus on how to avoid some pitfalls of version control systems in general and Subversion specifically.

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.

You can avoid these problems by following clearly-defined formatting rules. The Subversion project's own hacking.html document (http://svn.collab.net/repos/svn/trunk/www/hacking.html) and the Code Conventions for the Java Programming Language (http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html), are good examples.

Tabs are particularly important. Some projects, like Subversion, do not use tabs at all in the source tree. Others always use them and define a particular tab size.

It can be very helpful to have an editor smart enough to help adhere to these rules. For example, vim can do this on a per-project basis with .vimrc commands like the following:

autocmd BufRead,BufNewFile */rapidsvn/*.{cpp,h}
    setlocal ts=4 noexpandtab
autocmd BufRead,BufNewFile */subversion/*.[ch]
    setlocal sw=2 expandtab cinoptions=>2sn-s{s^-s:s
    

Check your favorite editor's documentation for more information.

In the real world, we're not always so perfect. Formatting preferences may change over time, or we may just make mistakes. There are things you can do to minimize the problems of reformatting.

These are good guidelines to follow:

Here's an example of a sweeping reformat:

$ svn co file:///repo/path/trunk indent_wc
$ indent -gnu indent_wc/src/*.[ch]
$ svn commit -m 'Ran indent -gnu src/*.[ch]' indent_wc
        

This follows all rules: there were no semantic changes mixed in (no files were changed other than through indent). The indent commandline was given, so the changes can be very easily duplicated. All the reformatting was done in a single revision.

Let's say these changes occurred to the trunk at revision 26. The head revision is now 42. You created a branch at revision 13 and now want to merge it back into the trunk. Ordinarily you'd do this:

$ svn co file://repo/path/trunk merge_wc
$ svn merge -r 13:head file://repo/path/branches/mybranch merge_wc
… # resolve conflicts
$ svn commit -m 'Merged branch'
      

But with the reformatting changes, there will be many, many conflicts. If you follow these rules, you can merge more easily:

$ svn co -r 25 file://repo/path/trunk merge_wc
$ svn merge -r 13:head file://repo/path/branches/mybranch merge_wc
… # resolve conflicts
$ indent -gnu src/*.[ch]
$ svn up
… # resolve conflicts
$ svn commit -m 'Merged branch'
      

In English, the procedure is: