7
votes

The Subversion SVN book says:

...Another way of thinking about this pattern is that your weekly sync of trunk to branch is analogous to running svn update in a working copy, while the final merge step is analogous to running svn commit from a working copy

I find this approach very unpractical in large developments, for several reasons, mostly related to reintegration step.

  1. From SVN v1.5, merging is done rev-by-rev. Cherry-picking the areas to be merged would cause us to resolve the trunk-branch conflicts twice (one when merging trunk revisions to the FB, and once more when merging back).
  2. Repository size: trunk changes might be significant for a large code base, and copying the differences files (unlike SVN copy) from trunk elsewhere may be a significant overhead.

Instead, we do what we call "re-branching". In this case, when a significant chunk of trunk changes is needed, a new feature branch is opened from current trunk, and the merge is always downward (Feature branches -> trunk -> stable branches). This does not go along SVN book guidelines and developers see it as extra pain.

How do you handle this situation?

5
Updated my answer... If this does not help then I don't understand the question.Artyom
Updated once more for SVN 1.5Artyom

5 Answers

3
votes

From SVN v1.5, merging is done rev-by-rev. Cherry-picking the areas to be merged would cause us to resolve the trunk-branch conflicts twice (one when merging trunk revisions to the FB, and once more when merging back)

Then you are doing something wrong!

Let's see:

trunk    fb
 ---------\
 r1-10    |
 r11-20   |
 r20-30   |

Generally if you want changes done in 11-20, then best practice is to merge 1-20 to fb and get everything there.

Then when fb is done, merge 20-30 and then copy fb to trunk (no merge!).

If you decide to merge only r11:20, ok, at end you will need to merge r1:10 and r20:30 and then copy fb to trunk.

There is no way you merge changes twice!

I assume that you probably do following:

copy trunk->fb
merge 11:20 -> fb.
merge fb-1:30 -> trunk !!!!! WRONG

You can't do this because you would merge 11:20 twice. You should always merge code in one direction only.

Correct way:

copy trunk->fb
merge 1:20 -> fb.
merge 21:30 -> fb (now fb=trunk+feature)
copy fb -> trunk

Edit

So the correct steps are:

  1. Create feature branch (FB) from trunk (copy trunk to feature branch with svn-copy)

    FB_0=trunk_0
    
  2. Work on FB.

    FB_1=FB_0 + change_a
    
  3. Merge all upcoming changes from trunk to FB.

    trunk_1=trunk_0 + tr_change_a;
    FB_2 = FB_1 + (trunk_1 - trunk_0) == trunk_0 + change_a + tr_change_a
    
  4. Work on FB

    FB_3 = FB_2 + change_b
    
  5. Merge all upcoming unmerged changes from trunk to FB.

    trunk_2=trunk_1 + tr_change_n;
    FB_4 = FB_3 + (trunk_2 - trunk_1) == trunk_0 + change_a + change_b + tr_change_a + tr_change_b
    
  6. At this point we have a feature branch that consists of all new features and all changes in trunk. So we just copy the difference between two branches.

    trunk_3 = trunk_2 + (FB_4 - trunk_2) = FB_4 = trunk_0 + change_a + change_b + tr_change_a + tr_change_b
    

    Now FB deleted as trunk has all changes we need.

    The last step is executed by:

    svn merge /path/to/trunk@LatestRev /path/to/branches/fb@LatestRev .
    svn ci
    

    Or in ordinary language take difference between trunk and branch and put them to trunk making them equivalent.

This pattern is described in http://svnbook.red-bean.com/en/1.4/svn.branchmerge.commonuses.html#svn.branchmerge.commonuses.patterns.feature

Now if this does not work for you, then I don't understand the question.

Edit2: For svn-1.5

When working with svn-1.5 you can merge much simpler:

When you work on feature branch you just merge changes from trunk time to time:

$ svn merge /path/to/trunk
Solve conflicts
$ svn ci

It will line up your FB with all changes in trunk. At the end of FB you run this procedure once more to make sure that everything is up-to date. The you go to trunk and run

$ svn merge --reintegrate /path/to/fb
$ svn ci

In the last one there should be no conflicts if you are working as shown.

1
votes

After research:

After many brainstorming sessions at visionmap, F2F discussions including Artyom, opening an SVN book case, etc - it looks like this is not possible to do. A feature branch is totally not like working copy. The only working way to update it is recreate a new branch, as described above.

0
votes

We're an small company, so I don't known if our solution will apply to your situation. What we do is a rev-by-rev merging from trunk to the stable branch. We can do it in 2 different ways: - Really needed fix, we merge just after committing to trunk - Dangerous fix/change. We wait some days until the change is proofed in trunk and then we merge

With this continuous merging we avoid tons of conflicts.

My 2 cents.

0
votes

Sadly everything mentioned can be thought of as hacks. Updating from trunk on a branch can lead to very serious problems when bringing it back into trunk and opens the possibility for the worst of all conflicts, tree conflicts. This is because directories are not treated as first class citizens. The best approach is to use Mercurial with the SVN extension as your standard SVN client. It allows you to keep using SVN while getting the power of Mercurial's folder handling.

Then on the wworkstation side you can use a number of approaches which provides a array of features to suit many situations over SVN's single one. You can use regular patching, patch queues, updating from a local copy of trunk without affecting the shared trunk and various other approaches.

This approach works around all of SVN's downn sides. I had tto switch to this approach because of similar circumstances. Even if you don't use this approach immediately you should at least give it a try ASAP.

0
votes

I think I have to take up the cudgels for @Artyom here. I too think that if you have to

resolve the trunk-branch conflicts twice

something is wrong. And I think @Artyoms argument/solution is quite solid.

I believe one of the minor things @Artyom could have written clearer is that in the end where you "copy" fb to trunk you do not use svn copy but svn merge (or svn merge --reintegrate). This might be the reason you do not find the "copy-merge" pattern in Common Branching Patterns.

As I am struggling with understanding what you are doing up until now, I am unsure what else to say.

Here is what I hear:

Instead, we do what we call "re-branching". In this case, when a significant chunk of trunk changes is needed, a new feature branch is opened from current trunk, ...

Now you have a new branch (let us call it b2) that is equivalent to trunk, right? And where is the "significant chunk of trunk changes needed"? I assume in fb?

...and the merge is always downward (Feature branches -> trunk -> stable branches).

But as you just created b2 from trunk there is nothing to merge into trunk, no? And you are not merging changes from b2 to fb either (as this would be the same as merging trunk to fb...). So how do the "significant chunks of changes" get into fb? And once they are there, why would you want to merge them back to trunk (since this is where they came from in the first place)?

Actually the following links the section called “Tracking Merges Manually" and/or the section called “Merging a Whole Branch to Another" provided in the SVN 1.4 documentation (I know, you do not use SVN 1.4 but I believe it applies anyway) under Common Branching Patterns might help to clear some things up. These links are "missing" in the 1.5 documentation (probably because of the new --reintegrate option in merge).

You really seem to be merging the same changes twice and I really think you should not (need to) do that.