Make svn --version (and svnsync --version, etc) tell you if ra_svn has
[svn.git] / doc / misc-docs / best_practices.xml
blob5fd7a73eceb97811461d3bcbc5b028418214153a
1 <chapter id="misc-docs-best_practices">
2   <title>Best Practices</title>
4 <simplesect>
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
10       specifically.</para>
12   </simplesect>
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
29       revisions.</para>
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
36       (<systemitem
37       class="url">http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html</systemitem>),
38       are good examples.</para>
39     
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>
49     <screen>
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
54     </screen>
56     <para>Check your favorite editor's documentation for more
57       information.</para>
59     <sect2 id="misc-docs-best_practices-sect-1.1">
60       <title>When You Have To Reformat</title>
61       
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>
66       
67       <para>These are good guidelines to follow:</para>
68       
69       <itemizedlist>
70         
71         <listitem>
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>
75         </listitem>
76         
77         <listitem>
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
82             anyway.</para>
83         </listitem>
84         
85       </itemizedlist>
86       
87       <para>Here's an example of a sweeping reformat:</para>
88       
89       <screen>
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
93         </screen>
94       
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
100         revision.</para>
101       
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>
106       
107       <screen>
108 $ svn co file://repo/path/trunk merge_wc
109 $ svn merge -r 13:head file://repo/path/branches/mybranch merge_wc
110 &hellip; # resolve conflicts
111 $ svn commit -m 'Merged branch'
112       </screen>
113       
114       <para>But with the reformatting changes, there will be many, many
115         conflicts. If you follow these rules, you can merge more
116         easily:</para>
117       
118       <screen>
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 &hellip; # resolve conflicts
122 $ indent -gnu src/*.[ch]
123 $ svn up
124 &hellip; # resolve conflicts
125 $ svn commit -m 'Merged branch'
126       </screen>
127       
128       <para>In English, the procedure is:</para>
129       
130       <itemizedlist>
131         
132         <listitem>
133           <para> Check out a pre-reformatting trunk working copy.</para>
134         </listitem>
135         
136         <listitem>
137           <para> Merge all branch changes. Fix conflicts.</para>
138         </listitem>
139         
140         <listitem>
141           <para> Reformat in the same manner.</para>
142         </listitem>
144         <listitem>
145           <para> Update to the head revision. Fix conflicts.</para>
146         </listitem>
147         
148         <listitem>
149           <para> Check in the merged working copy.</para>
150         </listitem>
151         
152       </itemizedlist>
153       
154     </sect2>
155     
156     <sect2 id="misc-docs-best_practices-sect-1.2">
157       <title>Ignoring Whitespace Differences</title>
158       
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>
163       
164       <table id="misc-docs-best_practices-table-1">
165         <title>Some useful GNU diff arguments</title>
166         <tgroup cols="2">
167           <thead>
168             <row>
169               <entry>Option</entry>
170               <entry>Description</entry>
171             </row>
172           </thead>
173           <tbody>
174             
175             <row>
176               <entry><option>-b</option></entry> 
177               <entry>Ignore differences in whitespace only.</entry>
178             </row>
179             
180             <row>
181               <entry><option>-B</option></entry>
182               <entry>Ignore added/removed blank lines.</entry>
183             </row>
184             
185             <row>
186               <entry><option>-i</option></entry>
187               <entry>Ignore changes in case.</entry>
188             </row>
189             
190             <row>
191               <entry><option>-t</option></entry>
192               <entry>Expand tabs to spaces to preserve
193                 alignment.</entry>
194             </row>
195             
196             <row>
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>
200             </row>
201             
202           </tbody>
203         </tgroup>
204       </table>
205       
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>
209         option.</para>
210       
211     </sect2>
213     <sect2 id="misc-docs-best_practices-sect-1.3">
214       <title>Line Endings</title>
215       
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>
220       
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>
226     </sect2>
228   </sect1>
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>
241     <itemizedlist>
243       <listitem>
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>&mdash;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>
250       </listitem>
252       <listitem>
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
258           files.</para>
259       </listitem>
261     </itemizedlist>
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>
274     <itemizedlist>
276       <listitem>
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.
280         </para>
281       </listitem>
283       <listitem>
284         <para> do I have a log entry for these changes?
285         </para>
286       </listitem>
288     </itemizedlist>
290     <para>Defining a log entry policy is also helpful --- the
291       Subversion <filename>hacking.html</filename> document
292       <systemitem
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>
311       
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>
319     </sect2>
321   </sect1>
323 </chapter>
325 <!--
326 local variables: 
327 sgml-parent-document: ("misc-docs.xml" "chapter")
328 end: