1 <chapter id="misc-docs-best_practices">
2 <title>Best Practices</title>
6 <para>Tips to use Subversion more effectively.</para>
8 <para>In this chapter, we'll focus on how to avoid some pitfalls
9 of version control systems in general and Subversion
14 <!-- ================================================================= -->
15 <!-- ======================== SECTION 1 ============================== -->
16 <!-- ================================================================= -->
17 <sect1 id="misc-docs-best_practices-sect-1">
18 <title>Source Code Formatting</title>
20 <para>Subversion diffs and merges text files work on a
21 line-by-line basis. They don't understand the syntax of
22 programming languages or even know when you've just reflowed
23 text to a different line width.</para>
25 <para>Given this design, it's important to avoid unnecessary
26 reformatting. It creates unnecessary conflicts when merging
27 branches, updating working copies, and applying patches. It also
28 can drown you in noise when viewing differences between
31 <para>You can avoid these problems by following clearly-defined
32 formatting rules. The Subversion project's own
33 <filename>hacking.html</filename> document (<systemitem
34 class="url">http://svn.collab.net/repos/svn/trunk/www/hacking.html</systemitem>)
35 and the Code Conventions for the Java Programming Language
37 class="url">http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html</systemitem>),
38 are good examples.</para>
40 <para>Tabs are particularly important. Some projects, like
41 Subversion, do not use tabs at all in the source tree. Others
42 always use them and define a particular tab size.</para>
44 <para>It can be very helpful to have an editor smart enough to
45 help adhere to these rules. For example, <command>vim</command>
46 can do this on a per-project basis with
47 <filename>.vimrc</filename> commands like the following:</para>
50 autocmd BufRead,BufNewFile */rapidsvn/*.{cpp,h}
51 setlocal ts=4 noexpandtab
52 autocmd BufRead,BufNewFile */subversion/*.[ch]
53 setlocal sw=2 expandtab cinoptions=>2sn-s{s^-s:s
56 <para>Check your favorite editor's documentation for more
59 <sect2 id="misc-docs-best_practices-sect-1.1">
60 <title>When You Have To Reformat</title>
62 <para>In the real world, we're not always so perfect. Formatting
63 preferences may change over time, or we may just make
64 mistakes. There are things you can do to minimize the problems
65 of reformatting.</para>
67 <para>These are good guidelines to follow:</para>
72 <para>If you're making a sweeping reformatting change, do it
73 in a single commit with no semantic changes. Give precise
74 directions on duplicating formatting changes.</para>
78 <para>If you've made semantic changes to some area of code and
79 see inconsistent formatting in the immediate context, it's
80 okay to reformat. Causing conflicts is not as great a
81 concern because your semantic changes are likely to do that
87 <para>Here's an example of a sweeping reformat:</para>
90 $ svn co file:///repo/path/trunk indent_wc
91 $ indent -gnu indent_wc/src/*.[ch]
92 $ svn commit -m 'Ran indent -gnu src/*.[ch]' indent_wc
95 <para>This follows all rules: there were no semantic changes mixed
96 in (no files were changed other than through
97 <command>indent</command>). The <command>indent</command>
98 commandline was given, so the changes can be very easily
99 duplicated. All the reformatting was done in a single
102 <para>Let's say these changes occurred to the trunk at revision
103 26. The head revision is now 42. You created a branch at
104 revision 13 and now want to merge it back into the
105 trunk. Ordinarily you'd do this:</para>
108 $ svn co file://repo/path/trunk merge_wc
109 $ svn merge -r 13:head file://repo/path/branches/mybranch merge_wc
110 … # resolve conflicts
111 $ svn commit -m 'Merged branch'
114 <para>But with the reformatting changes, there will be many, many
115 conflicts. If you follow these rules, you can merge more
119 $ svn co -r 25 file://repo/path/trunk merge_wc
120 $ svn merge -r 13:head file://repo/path/branches/mybranch merge_wc
121 … # resolve conflicts
122 $ indent -gnu src/*.[ch]
124 … # resolve conflicts
125 $ svn commit -m 'Merged branch'
128 <para>In English, the procedure is:</para>
133 <para> Check out a pre-reformatting trunk working copy.</para>
137 <para> Merge all branch changes. Fix conflicts.</para>
141 <para> Reformat in the same manner.</para>
145 <para> Update to the head revision. Fix conflicts.</para>
149 <para> Check in the merged working copy.</para>
156 <sect2 id="misc-docs-best_practices-sect-1.2">
157 <title>Ignoring Whitespace Differences</title>
159 <para>When viewing differences between revisions, you can
160 customize <command>svn diff</command> output to hide whitespace
161 changes. The <option>-x</option> argument passes arguments
162 through to GNU diff. Here are some useful arguments:</para>
164 <table id="misc-docs-best_practices-table-1">
165 <title>Some useful GNU diff arguments</title>
169 <entry>Option</entry>
170 <entry>Description</entry>
176 <entry><option>-b</option></entry>
177 <entry>Ignore differences in whitespace only.</entry>
181 <entry><option>-B</option></entry>
182 <entry>Ignore added/removed blank lines.</entry>
186 <entry><option>-i</option></entry>
187 <entry>Ignore changes in case.</entry>
191 <entry><option>-t</option></entry>
192 <entry>Expand tabs to spaces to preserve
197 <entry><option>-T</option></entry>
198 <entry>Output a tab rather than a space at the beginning
199 of each line to start on a tab stop.</entry>
206 <para>The commit emails always show whitespace-only changes.
207 <filename>commit-email.pl</filename> uses <command>svnlook diff</command> to get
208 differences, which doesn't support the <option>-x</option>
213 <sect2 id="misc-docs-best_practices-sect-1.3">
214 <title>Line Endings</title>
216 <para>Different platforms (Unix, Windows, Mac OS) have different
217 conventions for marking the line endings of text files. Simple
218 editors may rewrite line endings, causing problems with diff and
219 merge. This is a subset of the formatting problems.</para>
221 <para>Subversion has built-in support for normalizing line
222 endings. To enable it, set the <command>svn:eol-style</command>
223 property to ``native''. See Properties in the Subversion
224 book for more information.</para>
230 <!-- ================================================================= -->
231 <!-- ======================== SECTION 2 ============================== -->
232 <!-- ================================================================= -->
233 <sect1 id="misc-docs-best_practices-sect-2">
234 <title>When you commit</title>
236 <para>It pays to take some time before you commit to review your
237 changes and create an appropriate log message. You are
238 publishing the newly changed project anew every time you
239 commit. This is true in two senses:</para>
244 <para> When you commit, you are potentially destabilizing the
245 head revision. Many projects have a policy that the head
246 revision is <quote>stable</quote>—it should always
247 parse/compile, it should always pass unit tests, etc. If you
248 don't get something right, you may be inconveniencing an
249 arbitrary number of people until someone commits a fix.</para>
253 <para> You cannot easily remove revisions. (There is no
254 equivalent to <command>cvs admin -o</command>.) If you might
255 not want something to be in the repository, make sure it is
256 not included in your commit. Check for sensitive
257 information, autogenerated files, and unnecessary large
263 <para>If you later don't like your log message, it is possible to
264 change it. The <command>svnadmin setlog</command> command will
265 do this locally. You can set up the script <systemitem
266 class="url">http://svn.collab.net/repos/svn/trunk/tools/cgi/tweak-log.cgi,tweak-log.cgi</systemitem>
267 to allow the same thing remotely. All the same, creating a good
268 log message beforehand helps clarify your thoughts and avoid
269 committing a mistake.</para>
271 <para>You should run a <command>svn diff</command> before each
272 commit and ask yourself:</para>
277 <para> do these changes belong together? It's best that each
278 revision is a single logical change. It's very easy to
279 forget that you've started another change.
284 <para> do I have a log entry for these changes?
290 <para>Defining a log entry policy is also helpful --- the
291 Subversion <filename>hacking.html</filename> document
293 class="url">http://svn.collab.net/repos/svn/trunk/www/hacking.html</systemitem>
294 is a good model. If you always embed filenames, function names,
295 etc. then you can easily search through the logs with
296 search-svnlog.pl <systemitem
297 class="url">http://svn.collab.net/repos/svn/trunk/tools/client-side/search-svnlog.pl</systemitem>.</para>
299 <para>You may want to write the log entry as you go. It's common
300 to create a file <filename>changes</filename> with your log
301 entry in progress. When you commit, use <command>svn ci -F
302 changes</command>.</para>
304 <para>If you do not write log entries as you go, you can generate
305 an initial log entry file using the output of <command>svn
306 status</command> which contains a list of all modified files and
307 directories and write a comment for each one.</para>
309 <sect2 id="misc-docs-best_practices-sect-2.1">
310 <title>Binary Files</title>
312 <para>Subversion does not have any way to merge or view
313 differences of binary files, so it's critical that these have
314 accurate log messages. Since you can't review your changes
315 with <command>svn diff</command> immediately before
316 committing, it's a particularly good idea to write the log
317 entry as you go.</para>
327 sgml-parent-document: ("misc-docs.xml" "chapter")