{"id":1344,"date":"2012-05-30T00:00:00","date_gmt":"2012-05-30T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/tortoisesvn-and-subversion-cookbook-part-7-managing-revisions\/"},"modified":"2021-05-11T15:56:21","modified_gmt":"2021-05-11T15:56:21","slug":"tortoisesvn-and-subversion-cookbook-part-7-managing-revisions","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/tortoisesvn-and-subversion-cookbook-part-7-managing-revisions\/","title":{"rendered":"TortoiseSVN and Subversion Cookbook Part 7: Managing Revisions"},"content":{"rendered":"<div id=\"pretty\">\n<h2>Contents<\/h2>\n<p> <a href=\"#part7\"> Managing Revisions<\/a> <a href=\"#workingcopies\"> Working Copies and Revisions<\/a>  <a href=\"#currentrev\"> Identifying the Current Revision<\/a> <a href=\"#determining\"> Determining if a working copy is up to date<\/a> <a href=\"#mixedcurrent\"> Understanding mixed revisions and current revision<\/a> <a href=\"#twocopies\"> Working on two copies of the same revision at the same time<\/a> <a href=\"#twodifferent\"> Working on two different revisions at the same time<\/a> <a href=\"#selectiveupdating\"> Selective Updating and Notification<\/a>  <a href=\"#refreshingselected\"> Refreshing selected files from the repository<\/a> <a href=\"#selectedfiles\"> Receiving notification when selected files are updated<\/a> <a href=\"#anyfile\"> Receiving notification when any file is updated<\/a> <a href=\"#keypoints\"> Key points of Commit Monitor<\/a> <\/p>\n<h2 id=\"part7\">Part 7: Managing Revisions (3800) <\/h2>\n<p class=\"start\">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: <\/p>\n<ul>\n<li><a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/subversion-and-tortoisesvn-cookbook-part-1--the-basics\/\">Part 1<\/a>: Checkouts and commits in a multiple-user environment.  <\/li>\n<li><a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/tortoisesvn-and-subversion-cookbook-part-2-file-operations-and-subversion-filtering\/\">Part 2<\/a>: Adding, deleting, moving, and renaming files, plus filtering what you add.  <\/li>\n<li><a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/tortoisesvn-and-subversion-cookbook-part-3-in,-out,-and-around\/\">Part 3<\/a>: Putting things in and taking things out of source control.  <\/li>\n<li><a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/tortoisesvn-and-subversion-cookbook-part-4-sharing-common-code\/\">Part 4:<\/a> Sharing source-controlled libraries in other source-controlled projects.  <\/li>\n<li><a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/tortoisesvn-and-subversion-cookbook-part-5-instrumenting-files-with-version-information\/\">Part 5<\/a>: Embedding revision details within your source files.  <\/li>\n<li><a href=\"http:\/\/www.simple-talk.com\/dotnet\/.net-framework\/tortoisesvn-and-subversion-cookbook-part-6-snapshots\/\">Part 6<\/a>: Working with tags, revisions, and snapshots. <\/li>\n<\/ul>\n<p>This installment explains how to manage revisions. <\/p>\n<div class=\"note\">\n<p class=\"note\"><em>Reminder: Refer to the <\/em><a href=\"http:\/\/svnbook.red-bean.com\/\"><strong><em>Subversion book<\/em><\/strong><\/a><em> and the <\/em><a href=\"http:\/\/tortoisesvn.net\/docs\/release\/TortoiseSVN_en\/index.html\"><strong><em>TortoiseSVN book<\/em><\/strong><\/a><em> for further reading as needed, and as directed in the recipes below.<\/em> <\/p>\n<\/div>\n<h2 id=\"workingcopies\">Working Copies and Revisions <\/h2>\n<h3 id=\"currentrev\">Identifying the current revision <\/h3>\n<p>To paraphrase a famous quote: <em>in order to get to where you want to go it helps to know where you are.<\/em> In Subversion terms, that translates to: <em>what is your <\/em><strong><em>current<\/em><\/strong><em> <\/em><em>(or <\/em><strong><em>base<\/em><\/strong><em> or <\/em><strong><em>working copy<\/em><\/strong><em>) <\/em><em>revision?<\/em><em> <\/em>The <a href=\"http:\/\/svnbook.red-bean.com\/en\/1.5\/svn-book.html\">Subversion book<\/a> defines this as: &#8220;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.&#8221; <\/p>\n<p>To identify your current revision, then, you must answer the further question, current revision <em>of what<\/em>? 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: <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1498-image001.png\" alt=\"1498-image001.png\" \/><\/p>\n<p class=\"caption\">Figure 7-1 Three examples, among others, of how to see the current revision for a selected item. <\/p>\n<ul>\n<li><strong>TortoiseSVN Log<\/strong><br \/>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 <strong>HKCU\\Software\\TortoiseSVN\\RecursiveLogRev<\/strong> 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 <em>Current revision highlighting for folders in log dialog<\/em> under <a href=\"http:\/\/tortoisesvn.net\/docs\/release\/TortoiseSVN_en\/tsvn-dug-settings.html\">Registry Settings<\/a>. In both 1.6 and 1.7 editions, see <a href=\"http:\/\/tortoisesvn.net\/docs\/release\/TortoiseSVN_en\/tsvn-dug-showlog.html\">Current Working Copy Revision<\/a>.)  <\/li>\n<li><strong>File properties<\/strong><br \/>From Windows Explorer or equivalent, open the <strong>standard<\/strong> file properties dialog&#8211;<strong><em>not<\/em><\/strong> the TortoiseSVN properties! Then select the <strong>Subversion<\/strong> 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.  <\/li>\n<li><strong>Windows Explorer<\/strong><br \/>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 <strong>More<\/strong> from the context menu, then scroll down to the SVN choices. Select <strong>SVN <\/strong><strong>revision<\/strong> then select OK. This technique displays only the current revision but for all objects in the current folder. <em>Caveat: Available in Windows XP but not later <\/em><em>Windows versions <\/em><em>(Vista, Win7&#8230;). Sigh&#8230;<\/em> <\/li>\n<\/ul>\n<p>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 <strong>Get-<\/strong><strong>Enhanced<\/strong><strong>ChildItem<\/strong>, a module from my <a href=\"http:\/\/cleancode.sourceforge.net\/wwwdoc\/APIbookshelf.html\">open-source PowerShell library<\/a> (look in the PowerShell &#8220;book&#8221;) that adds useful options to <strong>Get-ChildItem<\/strong>. <\/p>\n<pre class=\"lang:c# theme:vs2012\">$fields = @(\"Path\", \"Revision\")\n\nfunction Match-Expression($string, $regex)\n{\n&#160;&#160;&#160;&#160;if ($string -match $regex)\n&#160;&#160;&#160;&#160;{ $Matches[1..($Matches.Count-1)] }\n&#160;&#160;&#160;&#160;else { @() }\n}\n\nGet-EnhancedChildItem -Svn -Recurse | % {\n&#160;&#160;&#160;&#160;$obj=new-object object\n&#160;&#160;&#160;&#160;svn info $_.fullname | % {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;$name, $value = Match-Expression $_ '(.*?):\\s+(.*)'\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if ($name -and $fields -contains $name) {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Add-Member -inputobject $obj NoteProperty $name $value\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;$obj\n} <\/pre>\n<p>Here is the output of the script for the same directory used in Figure 7-1: <\/p>\n<pre>Path&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Revision\n----&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;--------\nC:\\Projects\\SeleniumTest\\Seleni...&#160;13983\nC:\\Projects\\SeleniumTest\\Seleni...&#160;12364\nC:\\Projects\\SeleniumTest\\Seleni...&#160;11206\nC:\\Projects\\SeleniumTest\\Seleni...&#160;11629\n<\/pre>\n<p>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 <strong>FormatTable<\/strong> with the <strong>AutoSize<\/strong> switch specified, yielding this much better result: <\/p>\n<pre>Path&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Revision\n----&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;--------\nC:\\Projects\\SeleniumTest\\SeleniumTest\\bin&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;13983\nC:\\Projects\\SeleniumTest\\SeleniumTest\\Properties&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;12364\nC:\\Projects\\SeleniumTest\\SeleniumTest\\app.config&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;11206\nC:\\Projects\\SeleniumTest\\SeleniumTest\\SeleniumTest.csproj&#160;11629 <\/pre>\n<p>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 <strong>Get-SvnInfo<\/strong> function, also available from my <a href=\"http:\/\/cleancode.sourceforge.net\/wwwdoc\/APIbookshelf.html\">library<\/a> (look in the PowerShell &#8220;book&#8221; then the <strong>SvnSupport<\/strong> section). <strong>Get-SvnInfo<\/strong> lets you specify any fields from the underlying <strong>svn info<\/strong> 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: <\/p>\n<pre class=\"lang:c# theme:vs2012\">Get-SvnInfo . -Recurse \"Path|C:\\Projects\\SeleniumTest\", \"Revision\" <\/pre>\n<p>&#8230;yielding this neat and tidy result: <\/p>\n<pre>Path&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Revision\n----&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;-------- \n\\SeleniumTest\\bin&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;13983\n\\SeleniumTest\\Properties&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;12364\n\\SeleniumTest\\app.config&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;11206\n\\SeleniumTest\\SeleniumTest.csproj&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;11629 <\/pre>\n<p>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: <\/p>\n<pre class=\"lang:c# theme:vs2012\">Get-SvnInfo . -Recurse -UseRegex \"Path|([^\\\\]*\\\\){6}\", \"Revision\" <\/pre>\n<h3 id=\"determining\">Determining if a working copy is up to date <\/h3>\n<p>This question is really two separate questions and not realizing this can cause consternation for innumerable users: <\/p>\n<ol>\n<li>Have any files or folders in a given subtree been modified by someone else since the last time I pulled files from the repository?  <\/li>\n<li>Are all the files and folders in a given subtree up to date with respect to revision numbers of the repository? <\/li>\n<\/ol>\n<p>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 <strong>Tortoise<\/strong><strong>SVN &gt;&gt; <\/strong><strong>Check for modifications<\/strong>, which shows your uncommitted changes by default, and then select <strong>Check repository<\/strong> to include everyone else&#8217;s changes. Alternately, you can check and synchronize in one step with <strong>Tortoise<\/strong><strong>SVN &gt;&gt; <\/strong><strong>SVN Update<\/strong>. <\/p>\n<p>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-<em>no<\/em>. 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! <\/p>\n<p>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. <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1498-image002.png\" alt=\"1498-image002.png\" \/><\/p>\n<p class=\"caption\">Figure 7-2 Simple working copy labeled with last modified revisions. <\/p>\n<p>To find the numbers in Figure 7-2, I used the same PowerShell <strong>Get-SvnInfo<\/strong> function discussed in the <strong>Identifying the current revision<\/strong> recipe: <\/p>\n<pre class=\"lang:c# theme:vs2012\">Get-SvnInfo . -Recurse \"path|C:\\stuff\", \"Revision\" <\/pre>\n<p>. . .to generate this output (Windows Explorer reports the same values in Windows XP if you add the SVN Revision column as described earlier): <\/p>\n<pre>Path&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Revision\n----&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;-------- \n\\svn\\project\\commands&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;6\n\\svn\\project\\commands\\subdir&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8\n\\svn\\project\\commands\\file1.txt&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;6\n\\svn\\project\\commands\\subdir\\file2.txt&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;9 <\/pre>\n<p>This <strong>Get-SvnInfo<\/strong> 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: <em>your working copy is <\/em><strong><em>not<\/em><\/strong><em> up to date<\/em>. You just need to know how to interpret the message. To do this, examine the Subversion log (<strong>TortoiseSVN<\/strong><strong> &gt;&gt; Show Log<\/strong>) on the root of the subtree (Figure 7-3). <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1498-image003.png\" alt=\"1498-image003.png\" \/><\/p>\n<p class=\"caption\">Figure 7-3 TortoiseSVN log from the root of the directory in Figure 7-2. <\/p>\n<p>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 <em>latest revision number of any descendant<\/em> of the selected directory (both <strong>SVN <\/strong><strong>Show <\/strong><strong>log<\/strong> and <strong>SVN<\/strong> <strong>repo-browser<\/strong>). 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 <strong>SVN <\/strong><strong>Show <\/strong><strong>log<\/strong> reports a higher revision than <strong>Get-SvnInfo<\/strong> you can safely answer <em>no<\/em> to question 2 above, i.e. your working copy <em>is<\/em> out of date. <\/p>\n<p>But wait! Now that you know the key fact that a directory&#8217;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 <strong>Get-SvnInfo<\/strong> <em>without<\/em> having to compare it to the log viewer. Look back at the output of <strong>Get-SvnInfo<\/strong>: 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. <\/p>\n<p>Finally, if you go ahead and do an <strong>SVN U<\/strong><strong>pdate<\/strong>, take a look at the state of your working copy; add one more column to the <strong>Get-SvnInfo<\/strong> output for more revealing information: <\/p>\n<pre class=\"lang:c# theme:vs2012\">Get-SvnInfo . -Recurse \"path|C:\\stuff\", \"Revision\", \"Last Changed Rev\" <\/pre>\n<p>The <strong>SVN Update<\/strong> brings everything up to the current revision, independent of when you last changed it: <\/p>\n<pre>Path&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Revision&#160;&#160;Last Changed Rev\n----&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;--------&#160;&#160;---------------- \n\\svn\\project\\commands&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;9&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;6\n\\svn\\project\\commands\\subdir&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;9&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8\n\\svn\\project\\commands\\file1.txt&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;9&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;6\n\\svn\\project\\commands\\subdir\\file2.txt&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;9&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;9 <\/pre>\n<h3 id=\"mixedcurrent\">Understanding mixed revisions and current revision <\/h3>\n<p>Immediately after an <strong>SVN Update<\/strong> all the files in the tree you updated are up to date by definition. But every time you do a commit operation <em>your working copy has mixed revisions<\/em>: 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 <a href=\"http:\/\/svnbook.red-bean.com\/en\/1.0\/ch02s03.html\">Limitations of Mixed Revisions<\/a>, you may occasionally want to work with older copies of some files and this capability lets you do that. <\/p>\n<p>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: <\/p>\n<ul>\n<li>You cannot commit <em>the deletion of an <\/em><em>object<\/em> unless it is fully up-to-date.  <\/li>\n<li>You cannot commit <em>a property change of an object<\/em> unless it is fully up-to-date. <\/li>\n<\/ul>\n<p>The <a href=\"http:\/\/svnbook.red-bean.com\/en\/1.0\/ch02s03.html\">How Working Copies Track the Repository<\/a> 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 <em>you<\/em> or not and whether changed by <em>someone else<\/em> or not. It goes on to explain what happens to an object in each state when you do an <strong>SVN Commit<\/strong> or an <strong>SVN Update<\/strong>. I converted the Subversion book&#8217;s textual description of these four states and actions&#8230; <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1498-image004.png\" alt=\"1498-image004.png\" \/><\/p>\n<p>&#8230;into the table below that lets you absorb the information much more readily. Furthermore, I submit that there are really <em>six<\/em> possible states. I have highlighted my additional material in the table. <\/p>\n<p>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. <\/p>\n<p>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 <em>current<\/em> means (a) no changes in the repository <em>and<\/em> (b) the working copy revision is the head revision; my experiments, and the Subversion book itself, confirm otherwise, i.e. that only (a) applies.) <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1498-table.jpg\" alt=\"1498-table.jpg\" \/><\/p>\n<p>You can easily check if anything else has been committed, i.e. if you are at the head revision: run <strong>svn info<\/strong> on your working copy directory (<strong>svn info<\/strong> .) and compare the value of the <strong>Rev<\/strong><strong>ision<\/strong><strong> <\/strong>field with that of the head revision (<strong>svn info<\/strong> . -r HEAD). <\/p>\n<p>But for an even quicker answer use the <a href=\"http:\/\/svnbook.red-bean.com\/nightly\/en\/svn.ref.svnversion.re.html\">svnversion<\/a> utility, a command-line utility available from any Subversion command-line client as well as TortoiseSVN&#8217;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 <em>mixed-revision working copy<\/em>, as in the example, it shows the whole range, e.g. &#8220;1034:1039&#8221; to indicate something is as low as 1034 and something else as high as 1039. Furthermore, <strong>svnversion<\/strong> 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! <\/p>\n<h3 id=\"twocopies\">Working on two copies of the same revision at the same time <\/h3>\n<p>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. <\/p>\n<p>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. <\/p>\n<h3 id=\"twodifferent\">Working on two different revisions at the same time <\/h3>\n<p>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. <\/p>\n<p>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 <em>single<\/em> working copy by context switching, i.e. switch from revision A to revision B and back, as needed, with the <strong>TortoiseSVN &gt;&gt; Switch<\/strong> command as discussed in the <strong>Restoring your environment to an unlabeled revision<\/strong> recipe in part 6 of this series. Another recipe in that installment, <strong>Understanding the difference between revert and update<\/strong>, warns to never edit when you use <strong>Update<\/strong> or <strong>Switch<\/strong> but there is a key difference in the current situation. Here you will be switching between <em>head<\/em> revisions of two different branches; it is <em>always<\/em> acceptable to edit the <em>head<\/em> revision of a branch so in this case editing after a <strong>Switch<\/strong> is perfectly sane and safe. <\/p>\n<h2 id=\"selectiveupdating\">Selective Updating and Notification <\/h2>\n<h3 id=\"refreshingselected\">Refreshing selected files from the repository <\/h3>\n<p>Normally you synchronize your working copy with the latest changes in your repository with the<strong> <\/strong><strong>TortoiseSVN &gt;&gt; Update<\/strong> 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 <strong>TortoiseSVN &gt;&gt; Update<\/strong> command to one or more files. Of course, they would have to be in the same folder if you are using Windows Explorer. <\/p>\n<p>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 <strong>TortoiseSVN &gt;&gt; <\/strong><strong>Check for Modifications <\/strong>command. Select the <strong>Check repository<\/strong> 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 <strong>Check for Modifications <\/strong>dialog and invoke the <strong>Update<\/strong> command from the context menu on any one of them. <\/p>\n<p>Another handy technique to see a new file (assuming you know the file name) is to use the <strong>svn cat<\/strong> command, as in: <\/p>\n<pre class=\"lang:c# theme:vs2012\">svn cat http:\/\/Your SvnServer\/repo-dir\/trunk\/path1\/path2\/...\/filename <\/pre>\n<p>Redirect that console output into a file of the same name if you want to store it. <\/p>\n<h3 id=\"selectedfiles\">Receiving notification when <em>selected files<\/em> are updated <\/h3>\n<p>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 <em>push<\/em> rather than a <em>pull<\/em> 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 <a href=\"http:\/\/stackoverflow.com\/questions\/9330862\/svn-notification-for-commits-to-certain-files\">this Stack Overflow post<\/a>: define a post-commit hook script to trigger an action on any commit by anyone on your team. In the script use the <strong>svnlook<\/strong> utility with something like this: <\/p>\n<pre class=\"lang:c# theme:vs2012\">svnlook changed -r%REV% %REPOS% | &lt;find_or_grep&gt; &lt;filename&gt; <\/pre>\n<p>That is, pipe the output of <strong>svnlook<\/strong> 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). <\/p>\n<p>Clearly a lot of work to do this, but see the next recipe for a much simpler approach to a similar issue. <\/p>\n<h3 id=\"anyfile\">Receiving notification when <em>any file<\/em> is updated <\/h3>\n<p>Contrary to the complications of the previous recipe if you are willing to tolerate notification when <em>any<\/em> file is committed (or more fine-grained, when any files by specific users are committed) there is a simple answer. <a href=\"http:\/\/tools.tortoisesvn.net\/CommitMonitor.html\">Commit Monitor<\/a> is a handy utility developed by the creator of TortoiseSVN, Stefan K&#195;&#188;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. <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1498-image005.png\" alt=\"1498-image005.png\" \/><\/p>\n<p class=\"caption\">Figure 7-4 Commit Monitor&#8217;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. <\/p>\n<h2 id=\"keypoints\">Key points of Commit Monitor: <\/h2>\n<ul>\n<li>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.  <\/li>\n<li>Each new revision is considered <strong>unread<\/strong> 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.  <\/li>\n<li>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.  <\/li>\n<li>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.  <\/li>\n<li>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.  <\/li>\n<li>Commit Monitor does not, alas, work for file-based repositories (i.e. file:\/\/&#8230;). <\/li>\n<\/ul>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>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.&hellip;<\/p>\n","protected":false},"author":221868,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4204,5658,4179,5259,5500,5501],"coauthors":[],"class_list":["post-1344","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-tools","tag-managing-revisions","tag-source-control","tag-subversion","tag-tortoisesvn","tag-version-control"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1344","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221868"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1344"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1344\/revisions"}],"predecessor-version":[{"id":90913,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1344\/revisions\/90913"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1344"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1344"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1344"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1344"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}