One of the main features of any version control system is keeping track of who changed what and when they did it. The svn log and svn blame commands are just the tools for this: when invoked on individual files, they show not only the history of changesets that affected the file, but also exactly which user wrote which line of code and when.
When changes start getting replicated between branches, however, things start to get complicated. For example, if you were to ask svn log about the history of your feature branch, it would show exactly every revision that ever affected the branch:
$ cd my-calc-branch $ svn log -q ------------------------------------------------------------------------ r390 | user | 2002-11-22 11:01:57 -0600 (Fri, 22 Nov 2002) | 1 line ------------------------------------------------------------------------ r388 | user | 2002-11-21 05:20:00 -0600 (Thu, 21 Nov 2002) | 2 lines ------------------------------------------------------------------------ r381 | user | 2002-11-20 15:07:06 -0600 (Wed, 20 Nov 2002) | 2 lines ------------------------------------------------------------------------ r359 | user | 2002-11-19 19:19:20 -0600 (Tue, 19 Nov 2002) | 2 lines ------------------------------------------------------------------------ r357 | user | 2002-11-15 14:29:52 -0600 (Fri, 15 Nov 2002) | 2 lines ------------------------------------------------------------------------ r343 | user | 2002-11-07 13:50:10 -0600 (Thu, 07 Nov 2002) | 2 lines ------------------------------------------------------------------------ r341 | user | 2002-11-03 07:17:16 -0600 (Sun, 03 Nov 2002) | 2 lines ------------------------------------------------------------------------ r303 | sally | 2002-10-29 21:14:35 -0600 (Tue, 29 Oct 2002) | 2 lines ------------------------------------------------------------------------ r98 | sally | 2002-02-22 15:35:29 -0600 (Fri, 22 Feb 2002) | 2 lines ------------------------------------------------------------------------
But is this really an accurate picture of all the changes that happened on the branch? What’s being left out here is the fact that revisions 390, 381, and 357 were actually the results of merging changes from the trunk. If you look at one of these logs in detail, the multiple trunk changesets that comprised the branch change are nowhere to be seen:
$ svn log -v -r 390 ------------------------------------------------------------------------ r390 | user | 2002-11-22 11:01:57 -0600 (Fri, 22 Nov 2002) | 1 line Changed paths: M /branches/my-calc-branch/button.c M /branches/my-calc-branch/README Final merge of trunk changes to my-calc-branch.
We happen to know that this merge to the branch was nothing but a
merge of trunk changes. How can we see those trunk changes as well? The
answer is to use the --use-merge-history
(-g
) option. This option expands those “child” changes
that were part of the merge:
$ svn log -v -r 390 -g ------------------------------------------------------------------------ r390 | user | 2002-11-22 11:01:57 -0600 (Fri, 22 Nov 2002) | 1 line Changed paths: M /branches/my-calc-branch/button.c M /branches/my-calc-branch/README Final merge of trunk changes to my-calc-branch. ------------------------------------------------------------------------ r383 | sally | 2002-11-21 03:19:00 -0600 (Thu, 21 Nov 2002) | 2 lines Changed paths: M /branches/my-calc-branch/button.c Merged via: r390 Fix inverse graphic error on button. ------------------------------------------------------------------------ r382 | sally | 2002-11-20 16:57:06 -0600 (Wed, 20 Nov 2002) | 2 lines Changed paths: M /branches/my-calc-branch/README Merged via: r390 Document my last fix in README.
By making the log operation use merge history, we see not just the revision we queried (r390), but also the two revisions that came along for the ride with it—a couple of changes made by Sally to the trunk. This is a much more complete picture of history!
The svn blame command also
takes the --use-merge-history
(-g
)
option. If this option is neglected, somebody looking at a line-by-line
annotation of button.c may get the
mistaken impression that you were responsible for the lines that fixed a
certain error:
$ svn blame button.c ... 390 user retval = inverse_func(button, path); 390 user return retval; 390 user } ...
And while it’s true that you did actually commit those three lines in revision 390, two of them were actually written by Sally back in revision 383:
$ svn blame button.c -g ... G 383 sally retval = inverse_func(button, path); G 383 sally return retval; 390 user } ...
Now we know who to really blame for those two lines of code!