Day-to-day with Subversion

How many times have you said "What version is in production?" or "Can we rebuild production to fix a bug and release an update?"

Better yet my favourite:

"We're working on Feature Y so we can't fix the bug for Feature X. Doing so would mean we deploy part of Feature X and Y with the patch!"

These are typical problems with source control, patching, and keeping your working flowing. Often it's hard to keep track of what's being worked on vs. what was already deployed. Sometimes you end up deploying something not tested or "ready for primetime". For example, at one point I was deploying screens and we had to pass along explicit instructions to the QA folks to "not touch that button!" because we hadn't finished the backend or our own testing. Of course, they touched it and logged a bug. Still, we often run into the problem of working on one set of features while testing another.

Recently we've switched over (not fully yet, but most of the projects are going there) from TFS to Subversion. TFS is just a bloody nightmare when it comes to trying to keep the trunk revision stable while performing updates on branches and not getting into a merge from hell scenario, which is sometimes typical when you have branches.

In doing the switch, we landed on a solution around branching code for new features and keeping the trunk clean. Branching is a hot topic in source control circles and has been known to start holy wars. In my past life (like a month ago) I avoided branches like the plague. This is probably due to the fact that branching (and more importantly the merge back) in TFS and VSS was like a live enema. Not something you want to do every day.

However in working through the process in a few projects and experiencing the daily merge routine first-hand, it's become my friend and makes for building systems along a feature driven development stream much easier. Here's how the process goes and all the details on each step.

Revision 1

Code and screenshots are always the best way to work through a process. While the code here is trivial (just a WinForms app with a few custom forms and dialogs) the principles are the same no matter how big your project is.

First we setup our subversion repository for the project. The typical setup is to create three folders in the repository; branches, tags, and trunk. Branches hold any branches you work on for new feature development; Tags contains named copies of revisions representing some point in time (perhaps a deployment); Trunk contains the main codebase and is always stable. These become vital to organizing your code and not clobbering other work going on as we'll see as go along.

Here's our sample repository in TortoiseSVN:

image

We'll start with revision 1, the basic application (the proverbial WinForms "Hello World!"). A single application with a single form. Check this in to Subversion into the trunk path. This gives us an updated repository:

image

Now your day to day work begins. The trunk revision is the most important (aka "The King"). Any other work being done will happen in branches and are known as servants. Servants are important but they take less priority than The King. The most important and highest priority work being done is the King (and there is only one king, viva Las Vegas baby!).

Fast forward to day 10 of our development cycle. We've been adding forms and code (all committed to the trunk by various people) and it's time to do a release. A release is cut (using whatever process you use here, the details are not important) and deployed. At that point we want to tag the release.

Tag and Deploy

Tagging is a way to identify a set of code, a snapshot, so you can retrieve it later. Once tagged, we can go back to the revision and all files from that point in time to rebuild the system. This is mainly a deployment thing. For example, you tag the release "1.0" and then continue on. At some point in the future you can check the code out using that tag, rebuild it, and it will be the same as the day you deployed it.

We'll tag our release as "1.0". This creates what looks like an entire copy of the code in the "tags" folder, but in reality it's all virtual. Unlike "other" source control systems, this doesn't actually make a copy and the magic of Subversion will let us pull this tag out and all the code associated with that later.

To tagging and creating branches is essentially the same act (it's the same dialog box) but will differ in where you put the tag. Subversion does not have special commands for branching or tagging, but uses so-called cheap copies instead. Cheap copies are similar to hard links in Unix, which means that instead of making a complete copy in the repository, an internal link is created, pointing to a specific tree/revision. As a result branches and tags are very quick to create, and take up almost no extra space in the repository.

So while the dialog box says "Copy" you're creating this cheap copy. Don't get miffed if you're project is huge, tagging takes next to nothing. Here's our tag ready to go:

image

For tagging, you generally won't want to click on the "Switch working copy to new branch/tag" checkbox. Tags are just snapshots in time and you go along your merry way in the trunk. For branches we'll be doing something different. So after you create the tag, don't be alarmed when you see this message in TortoiseSVN:

image

And here's the repository tree after the tag. Note the tags folder has a new entry, "1.0" which contains an exact copy of what's in the "trunk", our King.

image

Now comes the fun. We've tagged the work and deployed. At any point in time we can go back and redeploy this version by pulling out the "1.0" tag and building/deploying from there. At this point is where we branch. We want to work in a new feature set. This is going to involve new dialogs and new code.

Branching New Features 

Why do we branch? Isn't branching bad?

No. Branching, when used this way keeps your trunk clean. Remember, there can only be one King (trunk). Any other work is a servant and will eventually go into the trunk.

Why again do we branch? Imagine if we didn't branch. So right after you apply the "1.0" tag start modifying trunk. Sure, we can go back to "1.0" but how are we going to get any changes merged together when we're on a single line? We're also violating the "One King" rule. Who's the King now? Our new branch becomes a servant. The King still takes priority (for example to fix bugs) but work will continue on in the servant branch.

Walk with me on this, by the end you'll see what the branch is for and why we want it.

We'll create a new branch just like creating a tag. Call the branch "1.1" except in this case, we're going to switch to the branch as our working copy. Here's the branch dialog:

image

And here's the repository after the branch. Our work is now all going to be committed to the "svn-demo/branches/1.1" branch, keeping the trunk clean.

image

Work in the 1.1 branch is underway with new features being added. We've created a few new forms, modified the main form, and generally added new functionality. The 1.1 branch is quite different from the original trunk it came from now:

image

A couple of scenarios will arise out of this. For example, if there's a bug found in the 1.0 version we deployed what do you do? You don't want to dirty the 1.0 tag. That's why trunk is King (and there is only one King). "trunk" is still the most important thing being worked on (at this point its in testing or production or whatever). Until it's verified, everyone else is a servant. Any problems found in "trunk" can be resolved on trunk. So we'll explore that scenario.

Waiter, There's a Bug in my Trunk!

There's a problem with 1.0. The window title is wrong. It reads "Hello World!" but it should read "Hello World?".

Huge problem! Stop the presses. Halt the line. We need to fix this now!

You may be tempted to create a branch, fix it, then merge the branch back into trunk. This might be normal, but our trunk is clean so we can just work with it directly. Check out a copy of trunk to a local directory and we'll do the fix. Then commit it back. Now here's the updated repository:

image

I've highlighted the file that changed in both versions. "/tags/1.0" is our deployed version (revision 25), "/trunk" is our bug fix update (revision 32). We can still, at any point, re-deploy "1.0" without any problems.

We'll do a deploy of our new trunk (which we'll call "1.0.1") and a series of exhaustive and intensive tests beings. Weeks pass testing our massive change and finally QA accepts the version and allows it be deployed to production. This will replace "1.0" in production with "1.0.1" and the updated title bar. Tag trunk as "1.0.1" like we did "1.0" above and we'll now have this in our repository:

image

The Graph is your Friend

TortoiseSVN has a wonderful feature called "Revision Graph" which gives you a visual tree of your branches and tags and revisions. You will live and die by this tool. Here's ours so far:

image

From this visual we can assess:

  • A tag called "1.0" was created from the trunk at revision 28, creating revision 29
  • A branch called "1.1" was created from the trunk at revision 29
  • Work continues on the "1.1" branch with daily commits (so far at revision 31)
  • A tag called "1.0.1" was created from the trunk (after a bug fix) at revision 32, creating revision 33

At this point I want to point out some major advantages with this approach:

  • You can rebuild any deployed release easily (well, as long as you tagged it in the first place)
  • Fixes can be done to the trunk and deployed quickly
  • Work can continue on separate features without disturbing the main work

Day to Day Merges

So now we have a bit of a disconnect don't we? The trunk (revision 32) and the re-deployed tagged version (1.0.1, revision 33) contains the fix we need however we're working on Feature X in the 1.1 branch. We don't have that fix. If we were to merge our code back to the trunk (which we will have to do at some point) we might miss this fix, or worse yet clobber it.

To avoid this problem, anyone working in a branch follows one simple rule. Each day (say at the start of the day) you update your branch from the trunk. In other words, you pick up any changes that have been applied to the trunk into your little branched world. Doing this will avoid any merge issues when you commit your branch back to the trunk.

We do this with a merge. It's a simple merge but one that has to happen, and merges can get complicated and ugly. In your working directory where you're commits are happening on the branch, you won't see changes to trunk.

Here's the merge dialog that we perform on a daily basis. We'll merge changes from the trunk into the 1.1 branch:

image

A few notes about this merge:

  • We merge from the branch and specify the branch in the top section. This seems backwards but we're merging "from a point in time" which needs to be the last revision when the two trees (trunk and branch) were synchronized. Remember, we're looking for all the changes "from trunk to branch" since we branched. The revision graph is essential in determining this. In our case, this is our first sync and is when we created the branch (revision 30).
  • By default the merge to uses the "From" value but we want to merge into our branch so uncheck this and pick the trunk in the "To" section. For the trunk we're going to pick the HEAD revision but this happens to be revision 32. Picking either HEAD or revision 32 here results in the same merge.
  • Confirm the location and behaviour you expect in the bottom section. The working copy should be your current working folder, and it should end up pointing at your current branch
  • Always (always) do a Dry run first and confirm the updates your going to do are correct.

So in this merge we expect to get the changes to MainForm.Designer.cs (that title change bug). If we had selected the HEAD revision for our branch version rather than the time where the branch split off from trunk, we would be comparing all the changes. This would result in the dry run telling us we have new forms. This is incorrect because a) we only want the changes from trunk and b) trunk doesn't know (or need to know) about any new forms we created. We're only interested in the changes made on trunk that we don't have yet.

Here's the dry run dialog with the proper response (based on the last merge dialog):

image

Perfect! We just want the changes to MainForm.Designer.cs (or whatever files changed since we last sync' d) and we got them. Execute this to get the new changes from trunk into your branch.

When you do a merge, you're merging those changes into your working copy but you're still one more step away. This will modify your working code but now you have to commit it back to the repository. If you check your updates you'll see that the MainForm.Designer.cs file has changed. Here's the unified diff of the changes:

Index: D:/Development/spikes/SvnMergeDemo/WindowsApplication1/MainForm.Designer.cs
===================================================================
--- D:/Development/spikes/SvnMergeDemo/WindowsApplication1/MainForm.Designer.cs    (revision 31)
+++ D:/Development/spikes/SvnMergeDemo/WindowsApplication1/MainForm.Designer.cs    (working copy)
@@ -61,7 +61,7 @@
             this.Controls.Add(this.button1);
             this.Name = "MainForm";
             this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
-            this.Text = "Hello World!";
+            this.Text = "Hello World?";
             this.Load += new System.EventHandler(this.MainForm_Load);
             this.ResumeLayout(false);

As you can see, the title bar change is here and replaces our old (buggy) version.

Commit this to the repository. Your branch now has the changes from trunk and you can continue on with your new feature work.

Remember, the key point of working in the branch is we don't pollute the trunk with our new dialogs or code, yet doing this daily merge (which will take all of 5 minutes on any codebase, trust me ;) keeps your branch up to date with any changes that may have happened.

Getting back to trunk

As we continue with our day to day work in the 1.1 branch, more changes might happen with trunk. More bug fixes, etc. However we don't introduce new features. We only add things on our branch. In the rare instance we're building a new feature while another feature is in play, we might create another branch with another team. I would however keep the number of active branches going on to a minimum. It'll just get ugly later in life.

In any case, we continue with our branch until we're ready to deploy. At this point we probably have a stable trunk (we should always have a stable trunk) with a number of tags. All changes in the trunk are in our branch and the team has decided it's time to deploy a new version to replace 1.0.1. This is our 1.1 branch and we need to merge all the new stuff in 1.1 back into trunk.

Here's our repository as it stands:

image

  • The 1.1 branch contains all of our new work, 3 additional forms and some changes to the main form to invoke our new forms
  • As a result of our daily "merge from trunk" routine, we have any bug fixes or changes that were done in trunk
  • Our trunk is clean and the version that was deployed (with various tags in our tags folder)

To merge back into the trunk it's the opposite of what we do on a daily basis. Rather than merging into the branch, we reverse it and merge into trunk. Also, you'll need a working copy of trunk to merge into. Check out trunk into a folder and invoke the merge. Again, the key point here is to pick the right revision. For the branch it'll be the HEAD revision. For trunk, it's the last point of synchronization which in this case is revision 32. Here's the merge dialog to commit our 1.1. features to the trunk.

image

In this case, we're committing to a working folder with a copy of trunk checked out to it. Click on Diff to see what changes are going to be applied:

image

Here we've added our new forms and there's changes to the MainForm.cs and MainForm.Designer.cs (we've added buttons to invoke the new dialogs). Here's the unified diff of MainForm.Designer.cs (with some lines removed for brevity):

Index: MainForm.Designer.cs
===================================================================
--- MainForm.Designer.cs    (.../trunk)    (revision 35)
+++ MainForm.Designer.cs    (.../branches/1.1)    (revision 35)
@@ -28,13 +28,49 @@
         /// </summary>
         private void InitializeComponent()
         {
+            this.button1 = new System.Windows.Forms.Button();
+            this.button2 = new System.Windows.Forms.Button();
+            this.button3 = new System.Windows.Forms.Button();
             this.SuspendLayout();
             //
+            // button1
+            //
+            this.button1.Location = new System.Drawing.Point(12, 12);
+            this.button1.Text = "Search";
+            //
+            // button2
+            //
+            this.button2.Location = new System.Drawing.Point(12, 41);
+            this.button2.Text = "Admin";
+            //
+            // button3
+            //
+            this.button3.Location = new System.Drawing.Point(12, 70);
+            this.button3.Text = "Customers";
+            //
             // MainForm
             //
+            this.Controls.Add(this.button3);
+            this.Controls.Add(this.button2);
+            this.Controls.Add(this.button1);
             this.Name = "MainForm";
             this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
             this.Text = "Hello World?";
@@ -44,6 +80,10 @@
         }
         #endregion
+
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.Button button2;
+        private System.Windows.Forms.Button button3;
     }
}

Note towards the bottom of this diff, this.Text = "Hello World?". This was the result of our daily merge so there's nothing to be applied back to trunk. We're in sync here. Only the changes/additions/deletions are applied which will bring "trunk" up to par with the 1.1 branch work. Again, do your dry run. You should see only the new work done in the branch as being applied to trunk. If not; stop, drop, and roll and recheck your revisions.

Again, the trunk now is merged together with the 1.1 branch. At this point you'll want to load the solution up, build it, run unit tests, etc. and do a sanity check that everything works as expected. You would probably do your deployment and tag the new trunk as "1.1".

You can just simply ditch the branch folder or leave it there in the repository. After all, it's just a symbolic link and doesn't take up much space (we have a new tag created in our repository on every CruiseControl.NET build so there are hundreds of tags, no big deal).

Lather, Rinse, Repeat

Now you're back on the trunk. Trunk is King, there is only one King, and your day to day work continues with whatever feature you're working on. You have the option to "always live in the branch" which might be an idea but this requires that daily merge from trunk and could cause problems. There's no problem "running on trunk" and building from it. The point at which you branch should be when you do a release and want to continue on with new (different) work, otherwise daily commits to trunk by the entire team is fine.

When a new feature comes along, branch, move part of the team (or the entire team) to that branch and keep trunk clean, doing any bug fixes as they come up. Then merge back from the feature branch back into trunk at the appropriate time. Keep doing this as often as necessary, until you run out of money or the team quits. Sit back, relax, and enjoy the simplicity of life.

Conclusion

It may seem complicated but it's really pretty basic when you boil it down. Just follow a few simple rules:

  • On a daily basis, developers in branches merge changes from the trunk into their branch
  • Merge branch features back into trunk when you're ready to deploy
  • Bug fixes are performed on the trunk then tagged and re-deployed

Give it a shot, email me if you're stuck or lost, or let me know what your experiences are.

Enjoy!

40 Comments

  • Phew, nice job. I understand the basic mechanics, but this takes it a lot further than I ever did, and makes it understandable!

  • Hi Bill,

    Great article !! one thing to add is the notation of VSTS style shelfs, this is easily done in SVN using the following - http://wiki.littlebluefroglabs.com/index.php?title=Subversion_and_Shelving.

    I suppose one thing that is also worth adding is what is SVN and why use SVN for those that have not seen it before.

    Andy

  • That's really good stuff.
    I used it for my own day to day development and now the company where I work uses it :)

    Now we do not chase each other for updated or missing files because of that.

  • Good content but a little confusing.
    You do cite alternative models for branching but you might want to make it a little bit more explicit.

    For example, here are two models I'm familiar with:

    A. Release Branches
    - New work goes in trunk
    - Create a branch when freezing a release candidate
    - Perform maintenance work on the frozen release branches (and copy back to trunk)
    - Release issued from branch
    - Continue new work in trunk

    B. Work branches
    - Trunk is kept clean and release-worthy at all times
    - New features developed in branches
    - Branches merged into trunk when features are ready
    - Release issued from trunk

    We use option A which works quite well and there's never any confusion about where new work should go since it always goes in trunk. Only maintenance work on pending releases go in other branches.

  • Truly a great post.

  • +1 for release branches, not feature branches.

  • Awesome post on how to use SVN. This is definitely a favorites page for SVN noobs like myself.

  • I've found it hard to have people let go of their financial investment in TFS...

    Also the perception of a tool that costs money vs. a free tool. The costly one _must_ be better!

    Good writeup though, I've forwarded it to my team (small jabs, ya know)

  • Thanks Bill. Great article.

  • +1 for release branches...

  • +1 for release branches...

  • Great post. Much thanks.

  • Great writeup - well done in explaining the "day-to-day" working with Subversion.

    I've been using SVN for a year now for one of my projects, only doing work in trunk. Have recently created a branch for adding in some unit tests (a more recent adventure). Have also made changes to the trunk in that time, so will need to merge trunk to the branch. Now I have a good idea of how that will be done!

    And I like the discussion over branching models, and I agree that release branches sound like the better way to go. I will try to do that in the future. I think my current unit tests branch is more of a feature branch!

  • Thanks for perfect article!!!

    p.s. I think you should swap merge screenshots :)

  • That clarified and highlighted some ways of working with version control that I hadn't properly considered before.

    -dave

  • Release branches are the way to go and are far less work for the developer to maintain than feature branches. I only recommend feature branches if the project is extremely large and is in danger of becoming broken (or has had a history of being broken) by someone's trunk updates. Also, you can start with release branches and switch to feature branches later on in the project's lifecycle if the project size warrants it and it becomes a problem for your team.

  • Bill,

    What happens if you deleted/renamed a file in the branch in a refactoring cycle? How can we merge any changes done to that file in the trunk?

    Similarly, let us say you modified the namespace names that are referenced (via using statements) in a source file in trunk. Now you are trying to merge some other changes in the same file from trunk. When you run the merge operation, SVN overrides the using statements with old ones. It would take more than 5 minutes to fix all these breaking changes.

    I am interested to know whether you have any tips in addressing these issues.

  • Very nice article on branching. Doesn't matter if you are using Subversion or not, the concepts are the same (and just as powerful in other tools as well, just not TFS).

  • @Kiran: You'll pick up the deletion (or any other changes) in your daily merge from trunk. No problems there. If you're doing a *big* refactoring (like a domain shift or a massive namechange) you might want to co-ordinate with the team. Tell them the intent and talk about it (most times something like this is needed and with a good refactoring tool and unit tests you shouldn't worry). Get them all to merge up then do the change and get them to re-merge from the trunk.

  • @Cory: Moving from SVN to TFS is IMHO bad. I won't get into a holy war here about the best source control (as I don't feel is SVN is the "best" but think it's "better" than TFS). WIth TFS I have this crazy workspace/local drive mapping issue which has caused me pain and suffering. With SVN I just move a directory somewhere. It doesn't care. TFS requires me to tell the server to map my local drive to some location it knows about. And when a person leaves the company the workspace lingers and is a PITA to get rid of. Enough on that (for now).

    As for SVN and CC.NET, not sure if that's worthy of an entire blog post. It's just a task in your ccnet.config file and is supported OOTB. How to track bugs and issues might be interesting and maybe I'll look at a post on Developer->Bug Tool->SVN->CC.NET or something like that.

    Thanks.

  • Thank you very much for this great article that explains feature branching very clearly! And together with the comments you get a really good picture of the two most common branching strategies. One of the best SVN tutorials I've read so far.

  • Hello.

    Nice work Bil.

    I have one question that keeps bothering me with this approach.

    for instance, suppose we've release v1.0 and we've also release v2.0, which has lots of new features. This means you'll have something like this:

    - tags
    - v1.0
    - v2.0
    - trunk
    - v2.0 files
    - branches
    - v2.0 branch code

    the trunk is the king and we've already updated it to 2.0 and have already put it on the web. So, now the latest version is 2.0 but the client has to pay to update to it or else he must keep using 1.0.

    the problem: how do we solve a 1.0 error that is found after publishing the 2.0 version? Well, with the model you're using and when there was only a 1.0 version, solving it would be easy: just correct the trunk and publish it to a new tag (like you've shown on your post).

    but now that the trunk has been updated to 2.0, how do you solve this problem withouth changing the existing 1.0 snapshop that exists on the tags folder?

    thanks.

  • Luis:

    My boss and I had a discussion about this, and we concluded that the crux of the matter is this:
    By choosing to support two separate major versions (whether for backwards compatibility, stingy customers, or dire security holes), you are ultimately maintaining two distinct products with code bases that may well be wildly divergent. This is likely to be an issue no matter what method you use.

    So you can either maintain a separate branch for version 1.0 just for bug fixes (i.e., without any feature branches of its own -- those are reserved for 2.0) or create a separate trunk for what is essentially a separate project. It runs slightly counter to the original intent, but it's more or less necessary in any case. The end result may require you to fix the same bugs twice, but that's basically what you sign up for when offering fixes for older versions.

  • Great article! Our team is fairly new to SVN and this goes a long way in explaining the "how-to" of branching and merging. The inclusion of screenshots was essential in that understanding. Thank you Bill!

  • This is great, it establishes perfectly why this is so confusing, why it will stay confused, and just how deeply broken TortoiseSVN's UI is. "We'll merge changes from the trunk into the 1.1 branch"... by specify the BRANCH in the FROM field, and the TRUNK in the TO field.

    It's astounding, but there it is. No way to write a clear explanation of something that is obfuscated by design.

    I hope they don't use TortoiseSVN in the space program.

  • Been having some trouble with this stuff, sought help, and read through your account very carefully, tried to put it into practice. I'm good with the branching, and the day-to-day merge works as expected, with the important insight that it's FROM the branch revision that was in common with the trunk.

    But I've been unable to get TortoiseSVN to bring the branch changes back to the trunk. My test project has one change in one file in the trunk, and one change to another file in the branch. The trunk's change has been day-to-day merged to the branch, so the reintegration should comprise ONE change to ONE file in the trunk.

    But the TEST merge (on the clean working copy of the trunk, FROM its HEAD, TO the HEAD of the branch) shows TWO changes coming, one to each file:
    Updated Default.aspx.cs
    Updated Default.aspx

    But that's not the bad part. The bad part is that having it perform the merge after the test shows that, it does SOMETHING DIFFERENT:

    Merging
    Updated Default.aspx.cs
    Updated Default.aspx
    Merging r641 through r644
    Updated Default.aspx.cs
    Reverse merging 644 through 641
    Updated Default.aspx.cs

    It does bring in the branch's change to Default.aspx, but there are FOUR entries on a file it should not be touching, and looking at the resulting file, I see that it has reverted to a version that is earlier than what's in EITHER the trunk or the branch in the repository.

    Some things are profoundly broken here, and "it's not just me."

  • Hey thanks for posting. From all my internet researches on the subject of TortoiseSVN / Subversion, this is the only one that makes any sense for me. This has saved me a LOT of brain damage. Great stuff.

    Cheers

    Andy

  • great article, wish images were more clear.

  • Thanks for an excellent article! We're doing some initial R & D on switching from VSS over to SVN, and this article really helped me understand the process of using SVN & Tortoise on a daily basis. Thanks again!

  • Nice post!
    This article clarified the most part of my questions.

  • It does bring in the branch's change to Default.aspx, but there are FOUR entries on a file it should not be touching, and looking at the resulting file, I see that it has reverted to a version that is earlier than what's in EITHER the trunk or the branch in the repository.

  • Hi,

    I'm new to Subversion. I found your post very helpful, but there's one thing that actually confused me when I was reading along. When you say "We'll merge changes from the trunk into the 1.1 branch:" the image right below it shows something different from what you're saying. It shows you're merging from the branch 1.1 to the trunk, wasn't it supposed to be done the other way around? Maybe I'm wrong, but that made me think whether it's a typo or you uploaded the wrong image.

    Anyways thank you for posting such info.

  • Ohh,

    I guess my question was already answered in the explanation you gave in the section «A few notes about this merge». I'm sorry, but maybe I had to continue reading to the end before asking something, which was explained further down.

    Great post!

  • Thank you so much, now I'm understand what is "stable trunk".
    If I may suggest, please update on how to compile into download ready file (.zip) please.
    And I can't find the donation button, where it is?

  • Unexceptional branching is just a sign of poor planning of forthcoming features and lack of quality.

  • Awesome article. &nbsp;I don't care how old it is - still relevant. &nbsp;Subversion is easy to setup (VisualSVN + TourtiseSVN) and is a Godsend when I discover clients still using VSS &quot;because they don't have the money to move to TFS&quot;. This article saved me tons of time and hair.

  • Thanks so &nbsp;much for such a crisp explanation. Clarifies all remaining questions about subversion.

  • Hmm.

    Obfuscated a fairly simple topic, it seems to me, with gibberish such as:

    &quot;Why again do we branch? Imagine if we didn't branch. So right after you apply the &quot;1.0&quot; tag start modifying trunk. Sure, we can go back to &quot;1.0&quot; but how are we going to get any changes merged together when we're on a single line? We're also violating the &quot;One King&quot; rule. Who's the King now? Our new branch becomes a servant. The King still takes priority (for example to fix bugs) but work will continue on in the servant branch.&quot;

  • Wow! This is a very good article in 2008. But still it is applicable very much. Thank you very much for sharing.

  • This is just what I was looking for!

    Been using subversion for about an year and never created a branch, mainly because we have been stabilizing and finishing our first "true" stable release.

    Since we are almost releasing it, I was thinking to apply something like this strategy, but was having trouble visualize it, and this article really helped.

    thanks!

Comments have been disabled for this content.