{"id":1306,"date":"2012-03-19T00:00:00","date_gmt":"2012-03-19T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/tortoisesvn-and-subversion-cookbook-part-6-snapshots\/"},"modified":"2021-05-17T18:36:16","modified_gmt":"2021-05-17T18:36:16","slug":"tortoisesvn-and-subversion-cookbook-part-6-snapshots","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/tortoisesvn-and-subversion-cookbook-part-6-snapshots\/","title":{"rendered":"TortoiseSVN and Subversion Cookbook Part 6: Snapshots"},"content":{"rendered":"<div id=\"pretty\">\n<h2>Contents<\/h2>\n<ul>\n<li><a href=\"#managinglabels\">Managing Labels<\/a>\n<ul>\n<li><a href=\"#latestversion\">Labeling the latest revision as a release<\/a>  <\/li>\n<li><a href=\"#earlierversion\">Labeling an earlier revision as a release<\/a>  <\/li>\n<li><a href=\"#bitsandpieces\">Labeling by bits and pieces<\/a>  <\/li>\n<li><a href=\"#movingtag\">Moving a Tag<\/a> <\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#adjusting\">Adjusting your World View with Labels and Revisions<\/a>\n<ul>\n<li><a href=\"#labeledrevision\">Restoring your environment to a labeled revision<\/a>  <\/li>\n<li><a href=\"#unlabeledrevision\">Restoring your environment to an unlabeled revision<\/a>  <\/li>\n<li><a href=\"#switchupdate\">Understanding the difference between switch and update<\/a>  <\/li>\n<li><a href=\"#revertupdate\">Understanding the difference between revert and update<\/a>  <\/li>\n<li><a href=\"#returning\">Returning to the present from a previous revision<\/a> <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p id=\"intro\" class=\"start\">This is the sixth 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<\/ul>\n<p>This installment explains how to work with revisions and releases using tags. <\/p>\n<p><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<p>Once you have done your testing and tweaking and are ready to deliver your code to production, perhaps the most important thing you need to do (besides actually <em>deliver<\/em><em>ing<\/em> the code) is to <em>know what you are delivering<\/em>. You must be able to come back in an hour, a month, or a year and be able to examine, diagnose, tweak, compile, or recreate the <em>exact same release<\/em> you just delivered. Taking such a snapshot in source control lingo is called <em>tagging<\/em> in some systems (including Subversion) and <em>labeling<\/em> in others. Regardless of the name, the concept of a <em>snapshot<\/em> is a central tenet &#8211; indeed, possibly <em>the<\/em> central tenet &#8211; of source control: a snapshot allows you to shift your world view to restore an arbitrary build or environment. <\/p>\n<div class=\"float-right\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1460-image001.png\" class=\"float-left\" alt=\"1460-image001.png\" \/><\/p>\n<p>&#8220;Because there is only a single, global current revision number in Subversion, every commit creates a snapshot &#8230;by definition.&#8221;<\/p>\n<\/div>\n<p>In Subversion, taking snapshots is easy. In fact, because there is only a single, global current revision number in Subversion, <em>every<\/em> commit creates a snapshot of the filesystem by definition. Assuming you write on a post-it that revision 58329 in your Subversion repository corresponds to your latest release of WhizBang version 5.1, you could come back anytime in the future and use the <strong>TortoiseSVN &gt;&gt; Update to Revision<\/strong> command to recreate the world as it existed in revision 58329. But that is rather unpalatable; a much more savory approach is to associate a tag (e.g. &#8220;WhizBang 5.1&#8221;) with a revision (58329 in this example) within Subversion itself. Then, instead of having to remember the association, you use the <strong>TortoiseSVN &gt;&gt; Switch<\/strong> command to switch to the tag name. As an example, consider the revision graph of a portion of my open-source libraries in Figure 6-1. Starting from the bottom you can observe that revision 847 has been tagged with Release 0_9_31. If you move upward looking for similar tags (i.e. \/tags\/Release_x_x_x) you will find 0_9_32 and 0_9_33 consecutively, then jump up and over to the right a bit to find 1_0_0 when I did a major release. Finally at the top is 1_00_01, a minor release. Also notice that I have a different product, SqlDiffFramework, first appearing at revision 1021, which goes through a couple minor revisions as well. Finally, second from the top (at revision 970) I have a tag that is not for a product but rather just for a notable milestone, my last revision using Visual Studio 2008 before switching to Visual Studio 2010. So you can add tags for whatever is of use to you, be it releases, milestones, builds, etc. <\/p>\n<p>The leftmost column in the graph-the grey rectangles-represent the mainline of code. The rectangles with rounded corners represent tags. Each tag, being a snapshot of the mainline, is tied back to a specific revision in the mainline. So, for example, Release 0_9_32 ties to revision 887. But curiously the tag itself has <em>its own revision<\/em> (891 in this example)! The reason is that tags are committed just like any other file; since every commit is associated with a new global revision number, each tag must then have its own unique revision. You can add multiple tags to a mainline revision-you can find a couple examples of this in the illustration. Each tag will have its own unique revision number though each is associated to the same mainline revision number. <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1460-image002.png\" alt=\"1460-image002.png\" \/><\/p>\n<p class=\"caption\">Figure 6-1 A revision graph showing labeled snapshots over time. <\/p>\n<h2 id=\"managinglabels\">Managing Labels <\/h2>\n<h3 id=\"latestversion\">Labeling the latest revision as a release <\/h3>\n<p>To create a tag, invoke the <strong>TortoiseSVN &gt;&gt; Branch\/Tag<\/strong> command. Branches and tags are equivalent in Subversion. They are only different by convention. According to Chapter 4 (<a href=\"http:\/\/svnbook.red-bean.com\/en\/1.5\/svn.branchmerge.tags.html\">Branching and Merging<\/a>) of the Subversion book: <\/p>\n<p>&#8220;In Subversion, there&#8217;s no difference between a tag and a branch. Both are just ordinary directories that are created by copying. Just as with branches, the only reason a copied directory is a &#8220;tag&#8221; is because humans have decided to treat it that way: as long as nobody ever commits to the directory, it forever remains a snapshot. If people start committing to it, it becomes a branch.&#8221; <\/p>\n<p>Use the browse button on the URL field to find the correct URL to your tags directory, then type the tag name as the final component, as in Figure 6-2. Select the head revision as indicated to label your latest committed set of files. <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1460-image003.png\" alt=\"1460-image003.png\" \/><\/p>\n<p class=\"caption\">Figure 6-2 Dialog to create a tag. <\/p>\n<h3 id=\"earlierversion\">Labeling an earlier revision as a release <\/h3>\n<p>Depending on your methodology you might tag your release immediately (in which case you need only tag the head revision as detailed in the <strong>Labeling the latest revision as a release<\/strong> recipe) or you might wait until you are sure the release is stable before tagging it. In the interim, however, your colleagues may have made other, unrelated, commits to your repository; so tagging the head revision is no longer an option. But you can just as easily tag some previous revision. <\/p>\n<p>To create a tag, invoke the <strong>Branch\/Tag<\/strong> command. (Branches and tags are equivalent in Subversion. See <strong>Labeling<\/strong><strong> the latest revision as a release<\/strong> for more.) Use the browse button on the URL field to find the correct URL to your tags directory, then type the tag name as the final component, as in Figure 6-2. Select a specific revision number to label. If you know it, just type it in. If you do not, press the browse button to open the log viewer, letting you browse for what you need. Select the appropriate version in the log viewer; TortoiseSVN shows a check mark on the one you select. When you close out the dialog by pressing OK, it copies the selected version number into the original dialog. <\/p>\n<h3 id=\"bitsandpieces\">Labeling by bits and pieces <\/h3>\n<p>The previous two recipes explained the process of applying a simple tag, where all files were at the same revision. But Subversion has the flexibility to apply a complex tag where different files or folders are at different revisions or even if they have local modifications. The procedure to do this is virtually the same as the last two recipes, with one prerequisite. Before invoking the <strong>Branch\/Tag<\/strong> command, configure your environment with the various revisions and local modifications that you want to snapshot. Open the <strong>Branch\/Tag<\/strong> dialog as before and select your tag name but, this time, select the <strong>Working Copy<\/strong> option in the dialog. <\/p>\n<h3 id=\"movingtag\">Moving a Tag <\/h3>\n<p>Consider this scenario: you finish your code, test thoroughly, and release to production. Your final flourish is to create a snapshot\/label the release as &#8220;version_2.0.0&#8221; in the repository so that you can quickly and easily restore your environment to this release at any time in the future. Invoke the <strong>TortoiseSVN &gt;&gt; Branch\/Tag<\/strong> command to create the tag. Great; it&#8217;s a wrap. But then a day passes and a customer reports a minor problem that, you determine, requires only the slightest tweak of a configuration file. You update the file, commit it to Subversion, and release to production. You still consider this version 2.0.0 but now your label is stale: if you restore your working copy to the &#8220;version_2.0.0&#8221; tag it will be <em>wrong<\/em> because it will not include this configuration file tweak. Realizing this, you just want to move the label so it also includes this configuration file change. There is no command to move a tag but it is almost that simple: in the repository browser delete the tag, which is simply a folder. Then back in Windows Explorer, recreate the tag with the standard <strong>TortoiseSVN &gt;&gt; Branch\/Tag<\/strong> command. Before you invoke the command, however, you need to consider whether you are tagging a single revision or a mix of revisions-see the earlier recipes in this section once you make this determination. <\/p>\n<div class=\"float-right\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1460-image001.png\" class=\"float-left\" alt=\"1460-image001.png\" \/><\/p>\n<p>&#8220;Before you blithely move a tag&#8230; consider whether you<em> should<\/em>.&#8221;<\/p>\n<\/div>\n<p>Before you blithely move a tag in this fashion, however, consider whether you <em>should<\/em>. To borrow the argument presented by Gabor Szabo in this <a href=\"http:\/\/svn.haxx.se\/users\/archive-2005-07\/0697.shtml\">forum post<\/a>, how will QA report bugs after you move a tag? &#8220;Well, we found a bug in version_2.0.0,&#8221; they might report. But <em>which<\/em> &#8220;version_2.0.0&#8221;? Was that before or after you moved the tag? Some organizations make the whole question moot by requiring a version increment for any change, no matter how small. So you would never have moved the original &#8220;version_2.0.0&#8221; tag; instead you would have created a new &#8220;version_2.0.1&#8221; tag-no ambiguity. But even if you do not bump the <em>version<\/em>, you can still bump the <em>tag<\/em>, e.g. use something like &#8220;version_2.0.0_A&#8221; where you always look for the highest suffix to find the variation of version 2.0.0 that is actually in production. <\/p>\n<h2 id=\"adjusting\">Adjusting your World View with Labels and Revisions <\/h2>\n<h3 id=\"labeledrevision\">Restoring your environment to a labeled revision <\/h3>\n<p>To recreate your world as it existed in a particular, tagged release, use the <strong>TortoiseSVN &gt;&gt; Switch<\/strong> command (Figure 6-3). Use the browse button on the URL field to find the tag of interest. Regardless of whether your tag is on the trunk or on a branch, the <strong>Switch<\/strong> command retargets your working copy to the revision associated with that tag. <strong>Switch<\/strong> operates as a branch-agnostic <strong>Update<\/strong> command. <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1460-image004.png\" alt=\"1460-image004.png\" \/><\/p>\n<p class=\"caption\">Figure 6-3 Dialog to switch to a tag \/ snapshot. <\/p>\n<p>By convention, tags represent a single point; so you should always use the default HEAD revision selection in the dialog. The same dialog box, as its title implies, is used for switching to branches as well. (Branching will be covered in a later installment.) A branch is a continuum rather than a point, so it makes sense to be able to select which revision on the branch you wish to target. <\/p>\n<p>When you press OK in the <strong>Switch<\/strong> dialog, TortoiseSVN will show a progress dialog indicating it is deleting and adding files and folders, and this list could vary enormously, depending on how far you are diverging from your previous revision and on how extensive your code-base changes from any one revision to another. If this is the first time you have used <strong>Switch<\/strong> &#8212; <em>remain calm<\/em>! The files being deleted are not lost; they are completely recoverable by simply switching back to where you came from. Remember that your working copy is a projection of the repository at a single revision. When you switch to a different revision, TortoiseSVN makes all the necessary changes to your working copy to make it now reflect the new revision. <\/p>\n<h3 id=\"unlabeledrevision\">Restoring your environment to an unlabeled revision <\/h3>\n<p>Tags make it particularly convenient to return to particular snapshots of your code base, detailed in the previous recipe but, even without tags, it is almost as simple to jump to anywhere in your code base history. As in the previous recipe, you could also use the <strong>TortoiseSVN &gt;&gt; Switch<\/strong> command. You would then specify the branch URL and the revision number on that branch. (Note that the trunk is just a special case of a branch, so is also covered by the term &#8220;branch&#8221;.) If, however, you are already on the branch where your target lies, you can more simply use the <strong>TortoiseSVN &gt;&gt;<\/strong> <strong>Update to Revision<\/strong> command (Figure 6-4). Here, you need only enter your target revision number. <\/p>\n<p>TortoiseSVN often provides more than one way to perform the same action. An equivalent way to accomplish the same task is to open the log viewer (<strong>TortoiseSVN &gt;&gt; Show log<\/strong>) where you can see all the revisions with comments and scroll to the one you are interested in. Open the context menu on that revision and then select <strong>Update item to revision<\/strong>. <\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1460-image005.png\" alt=\"1460-image005.png\" \/><\/p>\n<p class=\"caption\">Figure 6-4 Dialog to update to a specific revision. <\/p>\n<h3 id=\"switchupdate\">Understanding the difference between switch and update <\/h3>\n<p><strong>Update<\/strong><strong> to revision<\/strong> and <strong>Switch<\/strong> are very similar operations. In fact, <strong>Switch<\/strong> is a superset of <strong>Update<\/strong><strong> <\/strong><strong>to revision<\/strong>. An <strong>Update<\/strong> <strong>to revision<\/strong> adjusts your working copy to a different revision on the <em>same<\/em> branch. A <strong>Switch<\/strong> adjusts your working copy to a different revision on <em>any<\/em> branch. (Branching will be covered in a later installment.) Refer to the <strong>Switches and Updates<\/strong> section of <a href=\"http:\/\/svnbook.red-bean.com\/en\/1.6\/svn.branchmerge.switchwc.html\">Traversing Branches<\/a> in the Subversion book for more. <\/p>\n<h3 id=\"revertupdate\">Understanding the difference between revert and update <\/h3>\n<div class=\"float-right\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1460-image001.png\" class=\"float-left\" alt=\"1460-image001.png\" \/><\/p>\n<p>&#8220;<strong>Update to revision<\/strong> actually takes you back in time to a previous revision. <strong>Revert<\/strong> modifies your current working copy to make it look exactly like a previous revision.&#8221;<\/p>\n<\/div>\n<p>As several recipes above have shown, an <strong>Update<\/strong><strong> <\/strong><strong>to revision<\/strong> operation changes your world view. If your head revision is 29322 and you update it to 11043 then you have essentially traveled back in time. As far as your working copy, everything is as it was the instant after revision 11043 was committed, whether that was a month ago or five years ago. And just as all the movies warn, do not tamper with the past! When you update to a previous revision or tag, you must think of yourself as just an observer visiting the past-do not edit any files or attempt to commit them. But what if that is just what you need to do? That is, you want to back up to a previous release and start off a new branch of development from that point. This is where the <strong>Revert<\/strong> command comes in. <strong>Update<\/strong><strong> <\/strong><strong>to revision<\/strong> actually takes you back in time to a previous revision. <strong>Revert<\/strong> modifies your current working copy to make it look exactly like a previous revision. With <strong>Revert<\/strong>, you are free to edit the files in your working copy, create a branch, or whatever else you like. And just like any other modification to your working copy, commit the changes if you wish to make them permanent. <\/p>\n<p>Study the difference between <strong>Revert<\/strong> and <strong>Update<\/strong><strong> <\/strong><strong>to revision<\/strong> until it becomes second nature. Knowing which one you need when you want to get something accomplished will end up saving you time in the long run. It is, in that sense, just like learning the alphabet. There is nothing magical about &#8220;A&#8221; and &#8220;B&#8221; and &#8220;C&#8221;; you just needed to learn their ordering, pronunciation, and use. Same thing here. Why is one called <strong>U<\/strong><strong>pdate<\/strong> and the other <strong>R<\/strong><strong>evert<\/strong>? The definition of either word could be stretched to encompass either purpose; they are what they are so learn them. One thing that may help appreciate the difference: first, start with an up-to-date working copy (<strong>Check for modifications<\/strong> should show no files modified.) After you do an <strong>Update<\/strong><strong> <\/strong><strong>to revision<\/strong><strong>,<\/strong> invoke <strong>Check for modifications<\/strong> again and it should <em>still<\/em> show no files modified. But after a <strong>Revert<\/strong> then <strong>Check for modifications<\/strong> should list some files that need to be committed. <\/p>\n<h3 id=\"returning\">Returning to the present from a previous revision <\/h3>\n<p>The previous two recipes have explained how to move back in time to an arbitrary point. Once you have traveled back in time, however, it is important to be able to return to the present! But this is something you already know and use every day &#8211; the simple <strong>SVN Update<\/strong> command. <strong>SVN Update<\/strong>, as you may have surmised, is just the degenerate case of <strong>SVN Update to revision<\/strong> where the target revision is the head revision. <\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Moving backwards in time in Subversion is like time travel in science fiction. It&#8217;s fine to  look around, but If you change anything it can have unforseen consequences, and you always have to return to the present. Snapshots enable you to navigate in source control to examine or compile the code as it existed at a point in time; to access a particular build.&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,4229,4172,4179,5259,5500,5501],"coauthors":[],"class_list":["post-1306","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-framework","tag-snapshots","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\/1306","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=1306"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1306\/revisions"}],"predecessor-version":[{"id":91103,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1306\/revisions\/91103"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1306"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1306"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1306"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}