TortoiseSVN and Subversion Cookbook Part 5: Instrumenting Files with Version Information

Subversion lets you embed, and automatically update, information within source-controlled files to make it easy to see who did what, and when they did so. It is not entirely straightforward to get it working, though; unless of course you read, and follow, Michael's easy guide.

Contents

This is the fifth 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.

This installment examines the less well-known but extremely handy world of embedded version information.

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

Say you are trying to track down a defect and need to review a collection of files as you probe the system, test hypotheses, and follow your hunches. You believe that this defect showed up only in the last month and seems tied to the minor release that was the result of adding features X and Y worked on by developers A, B, and C. So you know who, you know what (i.e. which files you want to examine) and you know when (both by date and by revision number by cross-referencing the release M.N tag with revision history). So now all you need is an easy way to identify the who, what, and when of the files you are examining. Subversion lets you embed and automatically update these identifying pieces of information within each file you choose with the use of keywords.

The Keyword Substitutions section in the Subversion book introduces keywords succinctly:

“Subversion has the ability to substitute keywords-pieces of useful, dynamic information about a versioned file-into the contents of the file itself. Keywords generally provide information about the last modification made to the file. Because this information changes each time the file changes, and more importantly, just after the file changes, it is a hassle for any process except the version control system to keep the data completely up to date. Left to human authors, the information would inevitably grow stale.”

To use keywords in a file you insert a keyword anchor, which is simply a keyword sandwiched between two dollar signs, e.g. $Date$ or $Id$. The table displays the available keywords, some of which have aliases. You can use either the main keyword or its alias interchangeably in a keyword anchor.

 

Keyword

Alias

Meaning

Date

LastChangedDate

Date of last known commit; date in local time.

Revision

LastChangedRevision

Revision of last known commit.

Author

LastChangedBy

Last known user to commit.

HeadURL

URL

URL to latest version of the file in the repository.

Id

none

Abbreviated combination of other 4 keywords; date in UTC time.

Header

none

Same as Id except the URL is not abbreviated.

Note that keywords do not update based on repository activity; rather they update based on your activity, because keyword expansion is a client-side operation. When you commit, the keywords are updated because of your changes. When you update, keywords are updated because of other people’s changes.

There are some other things you’ll need to do to allow keyword expansion to occur, however, as I’ll explain in the recipes of this section.

Enabling keyword substitution in a file

Keyword substitution happens only in those files where you have specifically enabled it using the svn:keywords property. You can manually enable it on a file by setting the Subversion properties of that file. To do this, open the TortoiseSVN properties panel from the context menu either with TortoiseSVN >> Properties or with Properties >> Subversion >> Properties and create, or edit, the property there.

Alternately, as with most Subversion properties, if you set svn:keywords on a folder you can apply it recursively to every file within that folder. In version 1.6 you must manually select the ‘Apply property recursively checkbox in the property editor. Version 1.7 has streamlined the process: it automatically checks the ‘Apply property recursively checkbox for folders and unchecks it for files. Technically the svn:keywords property does not apply to folders at all, only to files. Thus, when you apply the svn:keywords property to a folder, you might think nothing happens if the folder is small enough. TortoiseSVN applies the property to all child files but not to the folder itself, and it is the folder’s property list that you are looking at once you apply the property. TortoiseSVN shows a progress box as it processes all the children but again, for a small folder, you might not even notice it.

A third approach to setting svn:keywords on a file is the proper, lazy approach: let the system do it for you when you add a file to source control. See the Automatically enabling keyword expansion in new files recipe.

The value you provide to the svn:keywords property is simply a list of one or more keywords (see the table in the introduction). In version 1.6 you are on your own with supplying this list. One great feature of Version 1.7 is the custom property editors for each Subversion property. For the svn:keywords property you are given a list of the available keywords and you simply check the ones you want to include. Upon closing the property editor your definition appears in the list of Subversion properties (Figure 5-1).

1448-image001.png

Figure 5-1 A Subversion property list showing the svn:keywords property. Any of the keywords listed may be actively substituted in the file to which these properties are attached.

Inserting the author, the revision, or other keywords when committing

To actually have keywords appear in your files you must enable keywords (see the Enabling keyword substitution in a file recipe) and you must instrument your file with keyword anchors (see the introductory remarks). (You must also satisfy a few further constraints-see Troubleshooting why keyword expansion fails later in this installment.) For example, here is a typical format that I tend to favor-I use just a single keyword anchor (marked in red), but this particular keyword references a composite of the other primary keywords (Date, Revision, Author, and HeadURL). So this is what your file might look like just before a commit:

The commit action triggers keyword substitution so your working copy immediately after a commit might look like this for a file called EnumerableDebugger.cs being checked in at revision 1158:

Note that Subversion is smart enough to recognize anchors whether they are virgin or whether they have already had substitution applied. Thus, if you commit the same file some time later it will update the revision number and the date in the previously expanded keyword, e.g.:

Alternately, you might prefer individual keywords, perhaps something like this:

And note that you may use either keywords or aliases (as presented in the table in the introductory remarks), so this is equivalent:

However you choose to organize your keyword anchors, typically you put them in some commented preamble to your file.

Automatically enabling keyword expansion in new files

It would be quite a hassle if, every time you add a new file to the repository, you have to manually edit its Subversion properties to enable keyword substitution (as detailed in the Enabling keyword substitution in a file recipe). Fortunately, TortoiseSVN-well, Subversion really-lets you enable keyword substitution in newly added files automatically with some simple, one-time setup.

1448-image002.png

“TortoiseSVN… lets you enable keyword substitution in newly added files automatically with some simple, one-time setup.”

First, locate your Subversion configuration file in one of your Window’s ApplicationData directories. To find just the right one examine $Env:APPDATA from PowerShell (or $APPDATA from DOS). The full path to the configuration file is $Env:APPDATA\Subversion\config.

Second, search for the enable-auto-props property and make sure it is set to yes. This is the master switch for enabling automatic property attachment to new files. Once the master switch is turned on, then you can enable groups of files specified by extension.

Finally, enable automatic properties for the specific files that you are interested in by specifying a line in the config file for the given file extension. In the example fragment shown below, a variety of file extensions define automatic properties but only .h and .txt files define keywords among their properties (highlighted in red). Furthermore, the particular keywords you want to use must be included in the defined list. For example, here the Id keyword is activated for *.txt files but not for *.h files.

With those settings in place in the configuration file, the next time you add a file with a .txt suffix that includes any keyword anchors, they will be expanded when you commit the file. Similarly, the next time you add an include file (.h) including either the Author or Date keyword anchor, those will be expanded.

Keeping your keyword expansions to fixed widths

If your keyword anchors appear last on each line, as in this…

…it does not really matter what width the expanded values take, e.g.

However, if your preference is to put them earlier in the line and attempt to make the subsequent phrases line up horizontally like this…

…then as soon as you commit the file your alignments will be askew:

Subversion provides a fixed-length keyword syntax to address just this issue. For each keyword anchor in your file instead of specifying just $anchor$ instead use $anchor::â¡â¡â¡â¡$ (each box represents one space character), where the number of spaces between the double-colon and the final dollar sign define the fixed-length field width. Thus, the above example becomes this:

When committed, the result is this-notice that short values are padded with spaces while longer values are truncated to the given field width (and include an octothorp to indicate truncation):

See the Keyword Substitution section of the Subversion book for more details.

Finding keyword anomalies

If you decide to become a keyword aficionado and instrument all your files with keyword anchors, you will likely want to have an easy way to check that you have made all the right connections among anchors, enabled files, and auto-enabled properties and determine whether you missed any. Furthermore, once you manage to achieve a harmonious balance of anchors, enabled files, and auto-enabled properties, you will want to be able to verify over time that the balance you have laboriously put in place remains. Because neither Subversion nor TortoiseSVN provides this capability inherently I created the PowerShell Measure-SvnKeywords function to handle it. (The link takes you directly to the API of that function; the root of my open-source PowerShell library is here.) Note that this function requires that you have command-line Subversion available, not just TortoiseSVN. (But if you are using TortoiseSVN 1.7 or later, it includes the command-line executables in the installation!)

1448-image002.png

“Measure-SvnKeywords… lets you easily see where you are missing keyword anchors or, conversely, where you have keyword anchors but did not enable keyword expansion.”

Measure-SvnKeywords reports a variety of statistics on keywords and keyword-related anomalies, letting you easily see where you are missing keyword anchors or, conversely, where you have keyword anchors but did not enable keyword expansion. It even gives you information to determine if there are other files where you might want to add keywords. Think of it as being primarily designed to answer these two questions:

  • Do you have files with keyword anchors that do not have keyword expansion enabled?
  • Do you have files with keyword expansion enabled that do not use keyword anchors?

Here is the calling signature of the function:

The first four parameters are quite standard; you will find them behaving identically to those in the standard Get-ChildItem cmdlet, for example. The penultimate parameter, ExcludeTree, is semi-standard, in that it operates the same as it does in Get-EnhancedChildItem (also from my open-source library). That parameter extends the capability of Get-ChildItem to let you prune whole subtrees, quite a useful capability! The final parameter, EnableKeywords, lets you actually go beyond just measuring Subversion keywords and update them! I’ll say more on that shortly.

Measure-SvnKeywords generates a report of a variety of keyword-related statistics on the set of files you specify. It can take some time to run, though: it takes perhaps a full minute to process a couple thousand files in my working copy. Because of the non-instantaneous run time, it makes use of the standard Write-Progress cmdlet to provide feedback during execution; this flexible cmdlet adapts to its environment-see Figure 5-2. Running inside the PowerGUI Script Editor, it displays a first-class pop-up progress monitor (left side of the figure). Inside a plain, text-oriented PowerShell window, it displays an ASCII rendition of a progress bar (right side of the figure).

1448-image003.png

Figure 5-2 The PowerShell Write-Progress cmdlet renders a progress bar for Measure-SvnKeywords, adapting to the environment in which it runs (PowerGUI on the left, plain PowerShell window on the right).

The Measure-SvnKeywords report includes these six sections:

Report Section

Description

Extensions enabled in configuration file

Enumerates each file type (by extension) enabled for auto-property attachment in your configuration file, along with the keyword anchors assigned to each type.

Summary of SVN files with keywords

Summary of all SVN files instrumented with keyword anchors plus a count of each file type.

All files with keywords not enabled IN CONFIG FILE

List of all files (not just SVN files) that have keyword anchors but whose file types are not enabled in the configuration file.

SVN files without keywords

List of all SVN files not instrumented with keyword anchors.

SVN files without keywords where keywords are enabled

List of all SVN files not instrumented with keyword anchors yet having the svn:keywords property.

SVN files with keywords to be enabled

List of all SVN files instrumented with keyword anchors but without the svn:keywords property.

Here is an excerpt from the report generated on my own development system:

The final section of the report (Enabling keywords on files containing keywords) displays the effect of the –EnableKeywords parameter: it processes the files identified in the section just above it, i.e. those that have keyword anchors but do not have the svn:keywords property. Any such files clearly indicate an error-keyword anchors are useful if and only if svn:keywords is defined. Other sections of the report may or may not show something that needs to be fixed: This is something you’ll need to check individually; but any files in that last section of the report are in a known inconsistent state so may be fixed programmatically. Recalling the two-stage process of Subversion (make changes, then commit changes) activating the -EnableKeywords action is perfectly safe; you still have to commit these property changes so you may review them at your leisure.

Troubleshooting why keyword expansion fails

For Subversion keyword expansion to occur you must satisfy all of the criteria listed below-if any one of these is missing you will not see keyword expansion occur-and neither Subversion nor TortoiseSVN provides any clue which criterion failed. The table distinguishes files newly added to Subversion (SVN Add) from those already in Subversion just being modified (SVN Update). The additional criteria for new files (items 1 – 3) are technically not for keyword expansion to occur; rather, they are convenience steps that alleviate the need to items 4 and 5 by hand for each new file that you add.

 

Action

New file

Existing file

1

Master switch enabled in config file (enable-auto-props property)

2

File type defined in config file

3

Keyword of interest specified for file type in config file

4

Keyword expansion enabled for given file (svn:keywords exists)

5

Particular keyword enabled (included in svn:keywords property list)

6

File instrumented with keyword anchor

7

Keyword anchors correctly cased

8

File svn:mime-type indicates text

9

File is not Unicode (UTF-16 or UTF-32)

10

File committed to repository

Notes on the table:

  • Items 1 through 6 are amply covered in the earlier recipes in this section.
  • Item 7: You must use the correct case for keyword anchors in your file for them to be recognized. That is you must use $Date$ or $Revision$; case variations (e.g. $DATE$) would not work.
  • Item 8: Subversion only performs keyword substitution on files that it considers to be human-readable-this is, files which don’t carry an svn:mime-type property whose value indicates otherwise.
  • Item 9: I almost did not include this line item when I encountered the situation because I could not believe Subversion does not support keyword expansion on Unicode files! To investigate this, I added a Unicode file to Subversion and noticed that it set the mime-type (in Subversion properties) to application/octet-stream. To see if I could override this indication of a non-text status, I changed the mime-type manually to text, which actually resulted in the svn:mime-type property being deleted from the properties list (since text is the default presumably). I committed the file to the repository then added a keyword anchor and committed again. The keyword anchor was not expanded. This issue, as it turns out, is really a sub-category of item 8: Subversion simply does not provide support for Unicode files as text, so it does not expand keywords. This is an outstanding defect.

    I found one other symptom related to this (item 9): I tried to assign the svn:eol-style property a value of native but TortoiseSVN refused saying the file has inconsistent line endings; in reality, it appears to be simply because it does not realize it is text. To confirm, I converted my file from Unicode to ASCII and then the keywords expanded upon commit.

    1448-image002.png

    “Keyword expansion … occurs only when you initiate an SVN Update or SVN Commit, i.e. at the time you synchronize your working copy with the repository.”

  • Item 10: This last item-committing your file-seems so innocuous but you should take a moment to consider the implications. Keyword expansion from virgin anchors or, perhaps more insidiously, keyword update from previous expanded anchors, occurs only when you initiate an SVN Update or SVN Commit, i.e. at the time you synchronize your working copy with the repository. That is, keyword expansion is strictly a client-side operation. As the Subversion book states, “…your client ‘knows’ only about changes that have occurred in the repository when you update your working copy to include those changes. If you never update your working copy, your keywords will never expand to different values even if those versioned files are being changed regularly in the repository. [my emphasis]” So SVN Update will trigger keyword expansion, as will SVN Commit: both of these operations synchronize your working copy with the repository.