TortoiseSVN and Subversion Cookbook Part 7: Managing Revisions

Here are recipes to manage Subversion source control revisions effectively, such as managing revisions, working out the current revision, whether it is up to date, working with more than one revision at a time, and getting notifications when certain files change.

Contents

Managing Revisions Working Copies and Revisions Identifying the Current Revision Determining if a working copy is up to date Understanding mixed revisions and current revision Working on two copies of the same revision at the same time Working on two different revisions at the same time Selective Updating and Notification Refreshing selected files from the repository Receiving notification when selected files are updated Receiving notification when any file is updated Key points of Commit Monitor

Part 7: Managing Revisions (3800)

This is the seventh 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, revisions, and snapshots.

This installment explains how to manage revisions.

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

Working Copies and Revisions

Identifying the current revision

To paraphrase a famous quote: in order to get to where you want to go it helps to know where you are. In Subversion terms, that translates to: what is your current (or base or working copy) revision? The Subversion book defines this as: “The revision number of an item in a working copy. If the item has been locally modified, this refers to the way the item appears without those local modifications.”

To identify your current revision, then, you must answer the further question, current revision of what? Each file or folder in your working copy has its own notion of current revision. So first take a look at Figure 7-1 illustrating three techniques (there are yet a couple others) for finding the current revision:

1498-image001.png

Figure 7-1 Three examples, among others, of how to see the current revision for a selected item.

  • TortoiseSVN Log
    The log viewer is often the best choice for identifying the current revision of a selected object; it highlights the log message for the current revision within the list of all its revisions. This technique displays all revisions but only for the current object. (Note that this highlighting is cheap for files but is expensive for folders if you have a large working copy because TortoiseSVN must crawl your working copy rooted at the selected folder. See The 1.7 release addresses this issue by performing the crawl in a separate thread; the log appears immediately but highlighting of folders may not appear right away for large working copies. Because version 1.6 does not use a separate thread to do this, it can delay displaying the log at all for some time but it does provide two workarounds. You can disable the default behavior by adding an HKCU\Software\TortoiseSVN\RecursiveLogRev DWORD registry key with a value of 0 to disable highlighting of folders completely or a value of 2 to examine just the selected folder, i.e., a non-recursive crawl. In the 1.6 TortoiseSVN book see Current revision highlighting for folders in log dialog under Registry Settings. In both 1.6 and 1.7 editions, see Current Working Copy Revision.)
  • File properties
    From Windows Explorer or equivalent, open the standard file properties dialog–not the TortoiseSVN properties! Then select the Subversion tab to see all the info available from the command line, including the current revision of the selected object. This technique displays only the current revision and only for the selected object.
  • Windows Explorer
    Windows Explorer has the flexibility to add columns from a large set of choices beyond the standard name, size, type, and modified date. Right click on the column headers bar, select More from the context menu, then scroll down to the SVN choices. Select SVN revision then select OK. This technique displays only the current revision but for all objects in the current folder. Caveat: Available in Windows XP but not later Windows versions (Vista, Win7…). Sigh…

Because this Windows Explorer technique, though not available in current versions of Windows, is rather useful, here is a PowerShell script lets you generate the same report from the command line. This script uses Get-EnhancedChildItem, a module from my open-source PowerShell library (look in the PowerShell “book”) that adds useful options to Get-ChildItem.

Here is the output of the script for the same directory used in Figure 7-1:

Clearly the output leaves something to be desired-default path truncation has left you with no clue as to which files are in the list! A simple fix is to pipe the above into FormatTable with the AutoSize switch specified, yielding this much better result:

As you might imagine, though, you could very quickly get a long, unwieldy path making even this output untenable. I wanted a generic solution to handle this long-value problem, which I encapsulated in the Get-SvnInfo function, also available from my library (look in the PowerShell “book” then the SvnSupport section). Get-SvnInfo lets you specify any fields from the underlying svn info command and trim off a prefix from any or all such fields. This call trims a prefix from the Path field while leaving the Revision field unchanged:

…yielding this neat and tidy result:

As I was writing this I realized it would be handy to be able to choose between using a regular expression or a constant prefix. The above example shows the use of a constant path prefix. But what if you had a listing with voluminous paths and wanted to discard the first 6 levels of directory regardless of the folder names? Enable the use of regular expressions with the -UseRegex parameter and specify an appropriate regular expression. Here is an example call to trim off the first 6 path components of the Path field:

Determining if a working copy is up to date

This question is really two separate questions and not realizing this can cause consternation for innumerable users:

  1. Have any files or folders in a given subtree been modified by someone else since the last time I pulled files from the repository?
  2. Are all the files and folders in a given subtree up to date with respect to revision numbers of the repository?

Question 1 is what most people think of when wanting to check if a working copy is up to date. You can answer the question without pulling files using TortoiseSVN >> Check for modifications, which shows your uncommitted changes by default, and then select Check repository to include everyone else’s changes. Alternately, you can check and synchronize in one step with TortoiseSVN >> SVN Update.

Say you are working in a small subtree that you absolutely know is not being touched by anyone else. So you know the answer to question 1-no. Now you want to rename a folder (or move a file) within that subtree. You perform the rename (or move) and then attempt to commit, but the commit fails, reporting that there are tree conflicts. This is due to question 2: even if you are the only one who has made commits in a subtree you can still be out of date!

Consider the simple directory structure in Figure 7-2. Each object is labeled in the diagram with the latest revision where it was modified. That is, changes to file2.txt were committed in revision 9. Changes to its parent (subdir) were committed in version 8; the change was, in fact, adding file2.txt to that directory.

1498-image002.png

Figure 7-2 Simple working copy labeled with last modified revisions.

To find the numbers in Figure 7-2, I used the same PowerShell Get-SvnInfo function discussed in the Identifying the current revision recipe:

. . .to generate this output (Windows Explorer reports the same values in Windows XP if you add the SVN Revision column as described earlier):

This Get-SvnInfo output confirms the same revision numbers from the illustration, indicating the revision where each object was last committed. Both are telling you something important, but probably not what you expect: your working copy is not up to date. You just need to know how to interpret the message. To do this, examine the Subversion log (TortoiseSVN >> Show Log) on the root of the subtree (Figure 7-3).

1498-image003.png

Figure 7-3 TortoiseSVN log from the root of the directory in Figure 7-2.

Notice that TortoiseSVN reports the root (the commands folder) is at revision 9 while the output above reported revision 6. For the revision number of a directory, TortoiseSVN reports the latest revision number of any descendant of the selected directory (both SVN Show log and SVN repo-browser). Thus, TortoiseSVN can-and usually does-show a revision number higher than the latest revision in which the directory itself was modified. (In fact, there is no way to find the revision number of a directory in isolation-you always get a rolled up revision number reflecting its entire subtree.) Because SVN Show log reports a higher revision than Get-SvnInfo you can safely answer no to question 2 above, i.e. your working copy is out of date.

But wait! Now that you know the key fact that a directory’s revision number is up to date if and only if none of its children have a higher revision number, then you could tell the working copy in this example is out of date using just the output of Get-SvnInfo without having to compare it to the log viewer. Look back at the output of Get-SvnInfo: the commands directory (committed at revision 6) has a child with a higher revision number (subdir committed at revision 8). This tells you immediately that the working copy is out of date.

Finally, if you go ahead and do an SVN Update, take a look at the state of your working copy; add one more column to the Get-SvnInfo output for more revealing information:

The SVN Update brings everything up to the current revision, independent of when you last changed it:

Understanding mixed revisions and current revision

Immediately after an SVN Update all the files in the tree you updated are up to date by definition. But every time you do a commit operation your working copy has mixed revisions: the object or objects you commit are at the head revision while everything else in your working copy is now at an older revision. Though hard to initially fathom at first, this flexibility to operate with mixed revisions is a feature! As the Subversion book describes under Limitations of Mixed Revisions, you may occasionally want to work with older copies of some files and this capability lets you do that.

The reason so much discussion was devoted to the previous question of determining whether your working copy is current has to do with these selfsame limitations. Specifically:

  • You cannot commit the deletion of an object unless it is fully up-to-date.
  • You cannot commit a property change of an object unless it is fully up-to-date.

The How Working Copies Track the Repository section in the Subversion book presents a discussion of the four possible states of a file, derived from all combinations of two simple conditions: whether changed locally by you or not and whether changed by someone else or not. It goes on to explain what happens to an object in each state when you do an SVN Commit or an SVN Update. I converted the Subversion book’s textual description of these four states and actions…

1498-image004.png

…into the table below that lets you absorb the information much more readily. Furthermore, I submit that there are really six possible states. I have highlighted my additional material in the table.

The table is divided into two sections vertically: the columns on the left describe a file state in three different ways (terse, Boolean, and verbose); the columns on the right indicate what occurs from performing key actions.

The table is also divided into two sections horizontally: the top rows cover when the file is fully up-to-date (current) with respect to the repository; the bottom rows cover when the file is out of date. Thus, even with local changes present, and even with the revision of the working copy not on the head revision, you can perform deletions and property changes, per the two rules stated earlier. (While investigating details for this recipe, I found some sources indicating that current means (a) no changes in the repository and (b) the working copy revision is the head revision; my experiments, and the Subversion book itself, confirm otherwise, i.e. that only (a) applies.)

1498-table.jpg

You can easily check if anything else has been committed, i.e. if you are at the head revision: run svn info on your working copy directory (svn info .) and compare the value of the Revision field with that of the head revision (svn info . -r HEAD).

But for an even quicker answer use the svnversion utility, a command-line utility available from any Subversion command-line client as well as TortoiseSVN’s bin directory. This summarizes the range of revisions for the subtree you specify. If you are up-to-date, you only get a single number. But if you have a mixed-revision working copy, as in the example, it shows the whole range, e.g. “1034:1039” to indicate something is as low as 1034 and something else as high as 1039. Furthermore, svnversion indicates whether you have any modifications in your working copy as well as whether you are on a branch. And it does all this not just on one line but typically in 15 characters or less!

Working on two copies of the same revision at the same time

Say you want to work on two new product features that are not related. Unrelated is promising-perhaps you could just edit the appropriate files in your working copy-but features being unrelated does not at all guarantee that the set of files related to them will not overlap. A much cleaner approach is to have two completely separate sets of files, i.e. two working copies. Since a working copy is just a checkout of a repository to an arbitrary folder on your machine, there is no reason you cannot do two separate checkouts to create two separate working copies. That way, you are guaranteed that work on one feature will not interfere with work on the other.

To get two separate copies you actually have two choices: do two separate checkouts as indicated above or, if you have not started work on either new feature yet, just copy your existing working copy with Windows Explorer. The latter would likely be faster if you have a huge repository.

Working on two different revisions at the same time

You can apply the same principals from the previous recipe to this recipe, just a bit more generically: checkout one working copy at revision A and a second working copy at revision B. (A real application of this might be while you are hard at work on new features you also need to investigate a newly discovered bug in production from an earlier revision.) This dual checkout again guarantees a clean separation.

There is one drawback to this approach, though: you might accidentally start editing in one working copy when you meant to work in another working copy. An approach to remove this drawback is to work with a single working copy by context switching, i.e. switch from revision A to revision B and back, as needed, with the TortoiseSVN >> Switch command as discussed in the Restoring your environment to an unlabeled revision recipe in part 6 of this series. Another recipe in that installment, Understanding the difference between revert and update, warns to never edit when you use Update or Switch but there is a key difference in the current situation. Here you will be switching between head revisions of two different branches; it is always acceptable to edit the head revision of a branch so in this case editing after a Switch is perfectly sane and safe.

Selective Updating and Notification

Refreshing selected files from the repository

Normally you synchronize your working copy with the latest changes in your repository with the TortoiseSVN >> Update command. Applying this command on any folder in Windows Explorer updates everything in that folder or lower. If you want to synchronize changes to several specific files without merging in changes to all other files at the same time, you can also invoke the TortoiseSVN >> Update command to one or more files. Of course, they would have to be in the same folder if you are using Windows Explorer.

That works for simple cases, but you need an alternate approach if you need to update files across multiple folders, or even to update files that do not yet exist in your working copy (i.e. new files added by a colleague). Identify an ancestor folder of all the files you are interested in and invoke the TortoiseSVN >> Check for Modifications command. Select the Check repository button to tell TortoiseSVN to identify what is new or changed by your colleagues. That will give you a list of all files with changes across folder boundaries. Finally, select the specific files you want to update locally within the Check for Modifications dialog and invoke the Update command from the context menu on any one of them.

Another handy technique to see a new file (assuming you know the file name) is to use the svn cat command, as in:

Redirect that console output into a file of the same name if you want to store it.

Receiving notification when selected files are updated

The previous recipe showed how to update specific files. It would be nice to be able to know when those files change, though, so you do not have to manually check (i.e. a push rather than a pull approach). Unfortunately for selected files you have to do some setup; there is no automatic technique or tool for this. I found a simple strategy for this by William Leara in this Stack Overflow post: define a post-commit hook script to trigger an action on any commit by anyone on your team. In the script use the svnlook utility with something like this:

That is, pipe the output of svnlook into a filter to identify the specific file or files of interest. Then, as William continues, if the filter returns a result, your file is among those in the change set, so your script should take an appropriate action (e.g. sending an email).

Clearly a lot of work to do this, but see the next recipe for a much simpler approach to a similar issue.

Receiving notification when any file is updated

Contrary to the complications of the previous recipe if you are willing to tolerate notification when any file is committed (or more fine-grained, when any files by specific users are committed) there is a simple answer. Commit Monitor is a handy utility developed by the creator of TortoiseSVN, Stefan Küng. With simple configuration-naming a project and providing a URL to its repository-Commit Monitor behaves much like your email program, checking periodically (at an interval you select) for new commits and notifying you via your system tray. Figure 7-4 shows the main window. I have overlaid the context menu available on any project in the figure to show some of the functionality.

1498-image005.png

Figure 7-4 Commit Monitor’s main window. The project selected in the navigation panel at left populates the revisions in the top-right; selecting a revision there indicates the log message and the affected files in the bottom-right.

Key points of Commit Monitor:

  • The left pane in Figure 7-4 is your project navigator. You can specify multiple projects to different repositories or even multiple projects within a single repository. If one URL is a descendant of another Commit Monitor automatically shows them nested together, as shown with the TestProject and the Subset of that.
  • Each new revision is considered unread just as in your email program and uses the same typical notation: bold for unread (with a number indicating how many unread), plain for read.
  • The upper right pane in Figure 7-4 lists revisions. Selecting a revision populates the lower right pane with the log message for that revision plus the list of associated files.
  • The system tray icon for Commit Monitor is the same pair of goofy-looking eyes you see as the program icon (extreme left of the title bar). When the program detects new commits the irises in the eyes wiggle up-and-down (!) informing you that someone else has committed one or more files.
  • When you define a project the default is to monitor all commits. However, you can optionally specify to restrict this to watch only a specific set of users, or to ignore a specific set of users.
  • Commit Monitor does not, alas, work for file-based repositories (i.e. file://…).