TortoiseSVN and Subversion Cookbook: Part 8: Log Messages

There should always be a reason for a commit to source control, so why not make a log message mandatory when you commit, and make it easy add a link to a record in a bug-tracking system, or to another Log message? Michael Sorens explains how.

Contents

This is the eighth installment of the TortoiseSVN and Subversion Cookbook series, a collection of practical recipes to help you navigate through the occasionally subtle complexities of source control with Subversion and its ubiquitous GUI front-end, TortoiseSVN. So far this series has covered:

  • Part 1: Checkouts and commits in a multiple-user environment.
  • Part 2: Adding, deleting, moving, and renaming files, plus filtering what you add.
  • Part 3: Putting things in and taking things out of source control.
  • Part 4: Sharing source-controlled libraries in other source-controlled projects.
  • Part 5: Embedding revision details within your source files.
  • Part 6: Working with tags and snapshots.
  • Part 7: Managing revisions and working copies.

This installment explains how to take full advantage of the capabilities of the Subversion log message.

Reminder: Refer to the Subversion book and the TortoiseSVN book for further reading as needed, and as directed in the recipes below.

Justifying requiring log messages

Good software practice dictates that you should always have a reason to commit a file. I would argue that it is almost a tautology: if you do not have a reason to commit a file, why would you commit it? It is, thus, little burden to require you to provide that reason when you do the commit. Other developers should at least have a hint as to why something was changed; also official process audits (ISO 9001 et al) would typically require this. And, oh yes, you might want to know in one terse remark why you committed that file once the memory has faded.

Another good reason for explaining why the commit took place is that the act forces you to consciously review what you are committing. For me, this is the most useful point, so I warm to Justin Ethier’s comments on the StackOverflow question ‘What is the use of commit messages?‘ “Even if I remember what I have changed, I will often do a quick ‘diff’ of a file before checking it in. I will briefly read it all over again to make sure that there are no ‘typos’, that I changed everything I meant to, etc. This is a simple way to review your code for those minor bugs that would otherwise find their way into your code.”

1383-img23.jpg

“[P]roviding a commit reason… forces you to consciously review what you are committing.”

Given that the policy of commenting a commit is good, what is going to stop you from doing so? Among the reasons for omitting comments, the most common, I believe, is that the developer simply forgot. If so, then make log messages a requirement.

But requiring comments is by no means a panacea. There is no way to mandate good comments-your diligence and professionalism are still required for that. A little bit of context goes a long way. Thus, try to avoid phrases like this:

Fixed.(What was fixed?)

Passed. (What passed?)

Messy code. (You are checking in messy code? Really?)

Instead, use something like these comments at a minimum that, though still short, provide some context:

Fixed account template bug.

Vendor NUnit test now passes.

Tidied up per Resharper.

For more best practices, see Write Meaningful Commit Messages in Anders Sandvig’s excellent article Best Practices for Version Control.

Making log messages required

To require log messages you need to obtain and install a pre-commit hook script. This particular hook runs as soon as you press the OK button in the commit dialog box. Actually, by pressing the button, you invoke a three-phase process; the pre-commit phase, the actual commit, and the post-commit phase. The pre-commit hook script runs, obviously, in the pre-commit phase. Thus, if the hook script decides the commit is not valid (due to, for example, no log message being entered) it can roll back the commit. (For more details, see the repository hook section in the Subversion book.)

Obtaining the pre-commit hook script is a simple matter: the Windows version (from Philibert Perusse) is available on the StackOverflow post Common Types of Subversion Hooks. And you already have the Unix/Linux version in your Subversion repository hooks directory. (Another Windows variation is available here.)

Installing the hook script is almost as easy. You must have access to your repository (or talk to your system admin). Then just copy the script into the hooks subdirectory in the repository. The hooks directory comes pre-populated with templates for a variety of hooks. The pre-commit.tmpl is a template containing the Unix/Linux version, together with instructions for the Windows version. If you want to explore more about these hooks but do not have access to the repository, just create your own dummy repository (TortoiseSVN >> Create repository here) and look in the hooks subfolder it generates.

The above discussion describes how to implement a server-side hook script. TortoiseSVN also supports requiring log messages by means of the client-side project property tsvn:logminsize. However, while you can do this, it does not mean you should do it. Client-side enforcement, to my mind, is tantamount to no enforcement: it simply does not make sense because it then merely becomes voluntary compliance at the discretion of each team member, rather than enforcement.

Finding commits with empty messages

If you have implemented the recipe to require log messages you should never again have empty messages. But there may be empty ones lurking from before you started requiring them! Prolific StackOverflow contributor manojlds offered a clever way to find these within TortoiseSVN in this StackOverflow post. Open the log message viewer and in the search box set the search type to just messages, enable regular expressions, and enter !^.+$ to search for messages without non-empty lines (see Figure 8-1).

1554-search-empty-log-messages-b7c9ca53-

Figure 8-1: Search for empty log messages in TortoiseSVN with this regular expression

Making log messages editable

Commit messages, being unversioned properties, have no history. Because there is no trace of its previous value when you modify one of them, Subversion defaults to disallowing, or preventing, such changes, but it provides hooks to allow you to enable it. You need to obtain and install a pre-revprop-change hook script to override the default behavior of disallowing the change.

Obtaining the pre-revprop-change hook script is a simple matter: the Windows version (from Philibert Perusse) is available on the StackOverflow post Common Types of Subversion Hooks. And you already have the Unix/Linux version in your Subversion repository hooks directory. (For an instantly available version, though, see this StackOverflow post.)

Installing the hook script is almost as easy. You must have access to your repository (or talk to your system admin). Then just copy the script into the hooks subdirectory in the repository. The hooks directory comes pre-populated with templates for a variety of hooks. The pre-revprop-change.tmpl is a template containing the Unix/Linux version, plus instructions for the Windows version. (If you want to explore more about these hooks but do not have access to the repository, just create your own dummy repository (TortoiseSVN >> Create repository here) and look in the hooks subfolder it generates.)

Editing a log message

There are a variety of reasons to edit a log message: to correct a ‘typo’, to add some missing information, or to correct a (someone else’s?) gaff. Whatever the reason, it is a simple matter-once you have enabled editing! See the previous recipe for that. After editing has been enabled, open the log viewer for the object containing the log message you wish to edit (TortoiseSVN >> Show Log). Right-click the log message and select Edit log message. This opens a simple text window with the existing message. Make your changes and save it. If the pre-revprop-change hook is correctly in place, the operation succeeds; otherwise TortoiseSVN will let you know it cannot save your change.

Linking log messages to your bug tracking system

With just a modicum of effort you can make your Subversion log messages come alive-in the sense of providing hyperlinks to issues in your bug tracking system. So while this log message that includes bug IDs is helpful…

…it is much more convenient if those bug IDs actually hyperlink to the actual tickets in your bug tracking system like this:

TortoiseSVN provides a very easy way to accomplish this and it works with any bug tracking system that has a web interface. (I set up one system to point to a private installation of Jira and another to point to the publicly accessible SourceForge issue tracker.) Figure 8-2 shows what your log window will look like once you enable connections to issues.

1554-bug%20tracking%20linkage-79700d6b-4

Figure 8-2: Once you enable linkage to your bug tracking system, TortoiseSVN adds a Bug-ID column in the top pane and live hyperlinks in the middle pane

First, notice the Bug-ID column that is auto-populated from whatever was typed in the log message when you delineate a bug with your predefined format. (On my system I like the bug IDs to be enclosed in square brackets.) Second, notice the log detail (the lower pane in the figure). As you know, this displays the full log message of the selected revision from the top pane. Here the bug-IDs are now hyperlinks. Clicking on each takes you directly to the specified ticket in your issue tracker (in your default browser).

No additional effort is required to create these links other than to be sure to put those bug IDs in the log message into the correct format. Furthermore, if you have been using the same standard format previously (without the convenience of links) it is automatically retroactive: once you or your admin configures Subversion for this (see next recipe), all of your prior entries will also automatically display these links.

1383-img23.jpg

“No additional effort is required to create [bug-tracking] links… [and] it is automatically retroactive: once you configure Subversion… all of your prior entries will also automatically displays these links. “

The previous paragraph included the deceptively comforting phrase “…in the correct format.” But just what is the correct format? That is determined either by your system administrator, or by you and your development team. My example above showed bug IDs in square brackets. That is by no means a standard nor a predefined convention; it is simply my personal preference that I have setup on my system. So, to know what to type, you need to either know what your team uses by way of oral traditions, or you need to examine the TortoiseSVN property that specifies the format.

TortoiseSVN provides a couple different ways to let you specify this format. I prefer the method that uses regular expressions which, though a bit more complicated, provides much more expressive power. So with this method, the format is defined by a regular expression contained in the bugtraq:logregex property of the current folder. If it isn’t there, the property is automatically inherited by child folders unless explicitly overridden. So traverse up the file tree until you find the closest ancestor that does define the property to see what it is.

I developed a handy PowerShell cmdlet (Get-IssueTrackerLogPattern) to let you skip the work and find the correct pattern for you. This cmdlet is available free from my open-source PowerShell library. You need to load its containing module (Import-Module CleanCode/SvnSupport) then just execute Get-IssueTrackerLogPattern <directory> (or omit the argument to check the current directory). Get-IssueTrackerLogPattern reports the format for the specified file or folder by walking up the tree until it finds the closest parent having the bugtraq:logregex pattern defined. If it crawls to the working copy root finding no pattern, it reports -none-. You can even use the common -Verbose parameter to display the treewalk if so desired.

My favorite format, which requires square brackets as delimiters and accepts numbers intermixed with commas, whitespace and the “and” conjunction, is defined by this rather abstruse regex: \[(\s*(,|,?\s*and\s+)?\s*\d+)+\]. Unless you “eat regular expressions for lunch” you may find that daunting. But it does not matter because of TortoiseSVN’s handy dynamic regex recognizer: when you invoke TortoiseSVN >> SVN Commit… and start typing a log message, TortoiseSVN recognizes pattern matches as you type! As soon as you type the closing bracket on “[5]” the TortoiseSVN dialog marks the phrase as a hyperlink. You do not have to type your complete message nor complete the commit operation-see Figure 8-3. You have immediate feedback character by character to know whether what you typed matches the defining regular expression. As soon as TortoiseSVN recognizes a successful match it highlights the text as a hyperlink. Furthermore, the hyperlink is live; you can click on it and it will open the associated bug in your browser!

1554-issue%20tracker-commit-f5a8314c-4e0

Figure 8-3: Hyperlinks that match your custom format are materialized immediately while you are still within the commit dialog

Linking log messages to your bug tracking system (Setup)

There is little administrative effort required to enable hyperlinks in log messages back to your bug tracking system: it all revolves around specifying what a bug ID looks like using regular expressions and providing a template URL in which the bug ID gets plugged in. The one and only rule to understand is that every folder in the Subversion tree inherits the link specification from its parent unless overridden. From that single rule, the implementation is straightforward:

  1. Specify a generic, catch-all expression on the repository root.
  2. Override individual project roots with variations or customizations as needed.

For example, start with a regular expression that recognizes any sequence of digits delimited by octothorps as a bug id. A couple entries that would match this regex are #123# or #92382#. With that regex attached to your root, then any project in the repository can use this format without additional setup. Now let’s imagine that your team eventually decides on a new convention, perhaps that bug IDs for new projects will all consist of 5 letters, a hyphen and an integer, e.g. PRSDW-2932. For each such project you need only define a regular expression to match this format at the project root; all legacy projects are undisturbed and will still work with the original #ddd# notation.

The table below specifies the regular expressions for the two examples just mentioned (rows A and B). For either of those patterns you can specify just one bug ID. If you want to reference multiple bug IDs, you simply use multiple instances of the pattern, e.g. “See also #123# and #456” or “See also PRSDW-2932 and PRTXY-2392” respectively. The last two rows in the table (rows C and D) automatically provide for multiple bug IDs in a phrase instead of just a single instance. The benefit of this is that your pattern is more specific so you are less likely to get false positive matches (creating hyperlinks on text that was not supposed to have a hyperlink).

 

Example Use

Notes

Message Part Expression

Bug ID Expression

A

#123# integer bracketed by octothorps

#\d+#

\d+

B

PRSDW-123 five letters, hyphen, integer

[a-zA-Z]{5}-\d+

[a-zA-Z]{5}-\d+

C

issues #23, #24 and #259 used by the Subversion project itself*

[Ii]ssues?:?(\s*(,|and)?\s*#\d+)+

\d+

D

[23, 24, and 259] used on my open-source projects

\[(\s*(,|,?\s*and\s+)?\s*\d+)+\]

\d+

*Footnote to table: The published Subversion pattern (row C) actually has a couple minor flaws: it will match the grammatically poor phrase “issues #23, #24 and#25” (missing a space after the “and”) and it will not match “issues #23, #24, and #25” (additional comma after the penultimate entry). This revised message part expression corrects both those issues: [Ii]ssues?:?(\s*(,|,?\s*and\s)?\s*#\d+)+.

Subversion 1.7 provides not just a custom property editor for the relevant properties, but also a built-in test bed for checking your regular expressions, though it is cleverly hidden(!). If you hover your mouse over the unlabeled button (highlighted in red in Figure 8-4) the tooltip indicates “Test the regex strings”. Selecting the button opens another dialog with a regex tester, allowing you to fine tune your expressions.

1554-bugtraq%20definition-b1678cb2-7524-

Figure 8-4: TortoiseSVN’s property editor for bugtraq properties (top) lets you specify linkages a couple different ways. The dialog here shows entries for a regular expression match. The dialog also provides a regex tester, accessible via the unlabeled button to the right (highlighted in red). Once you close the dialog, your entries are mapped back to the Subversion property list (bottom)

As the top dialog in Figure 8-4 indicates, there are several different approaches you can take in setting up bug ID recognition, the two principal methods being by pattern-and-label (the “Message” section of the dialog) or by regular expression (the “Regular Expression” section of the dialog). I prefer the latter because it is more powerful and more flexible; refer to the manual for more information on the former.

You must always specify a URL to your bug tracker, using the %BUGID% placeholder where the actual bug ID should be inserted (see the URL field in the figure). When using regular expressions, you actually need to define two: the message part expression recognizes the entire phrase from the surrounding log message, while the bug-ID expression picks out of that an individual bug id from the output of the first regex, which can be substituted for the %BUGID% placeholder. The table above gives you several examples. Those two regular expressions are actually combined into a single Subversion property, bugtraq:logregex while the URL is stored in a separate property, bugtraq:url (see bottom dialog, Figure 8-4).

Earlier in this recipe you learned that every folder in a Subversion tree inherits the link specification from its parent. That link specification is provided by these TortoiseSVN properties, bugtraq:logregex and bugtraq:url. Unless all your projects can use the same values for these properties, you will likely need to follow the strategy outlined earlier, whereby you define a default at the repository root, and then override this on a per-project basis as needed. Of course, you are not limited to one per project; you can get as elaborate as you like. This capability can be misused, inadvertently or deliberately. For any given folder, then, there is no simple way to tell what pattern it is expecting via these properties. You would have to check the properties of the folder first. If the properties are not defined, then you check its parent, and its parent, etc. until you find the closest ancestor that does define them. Or you can invoke the Get-IssueTrackerLogPattern PowerShell command, available free from my open-source PowerShell library. You need to load its containing module (Import-Module CleanCode\SvnSupport) then just execute Get-IssueTrackerLogPattern <directory> (or omit the argument to check the current directory). Get-IssueTrackerLogPattern reports the format for the specified file or folder by walking up the tree until it finds the closest parent having the bugtraq:logregex pattern defined. If it crawls to the working copy root finding no pattern, it reports -none-. You can even use the common -Verbose parameter to display the treewalk if so desired.

Linking log messages to other log messages

As of TortoiseSVN 1.7 you can link log messages to other log messages. This is even easier than linking to your bug tracking system (see earlier recipes) because it requires no setup at all! You simply enter a revision number prefixed by the letter “r” surrounded by whitespace or punctuation. Thus, if you enter some text in a log message but want it to associate with another revision, you could add something like “… See also r13232.” (See the TortoiseSVN 1.7 release notes for further details.)

Alas, you will not see these intra-log hyperlinks until you complete your commit operation then open up the log dialog, unlike the hyperlinks to your bug tracking system discussed in the Linking Log Messages to Your Bug Tracking System recipe where you had immediate feedback as you type. As Figure 8-5 shows, once you open the log dialog you can see the unadorned log message in the top pane, but in the middle pane it has a live link, referencing an earlier revision. Clicking on the link is the same as if you had clicked on the revision in the upper pane-that revision becomes the current revision so its log message appears in the middle pane and its associated files in the lower pane (not shown in the figure).

1554-Intralog%20links-b69a3cfa-0563-4df0

Figure 8-5: Intralog links are easy to apply by simply prefixing a revision number with a lowercase “r” when you type a log message. Intralog links do not appear in the commit dialog; they are visible in the resulting log once you complete a commit.