Subversion – branching, merging and reintegration

3

Subversion is a great source control system. One of the great features is it’s branching and merging support. Although many developers avoid it, branching is very powerful and useful and should not be something to be afraid off but something to be familiar with. And for the stable and controlled development is it almost a necessity to master it.

In general we can identify two types of branches: product and feature branches.

  • The product branch is normally to support maintenance on a released version while development of the next version continues.
  • A feature branch is normally a temporary branch to work on a (complex) change without interfering with the stability of the main development line (trunk) and in the end is incorporated back into the main line again.

Now, while you can work on isolation on the feature branch, there will come a time that you’ll have to integrate (merge) the changes with the trunk. And although subversion does provide extensive merge support, this might get messy with big changes. So it’s a real good idea to keep the feature branch in sync with the trunk and have the changes in the trunk regularly applied to the feature branch too. Actually, this is not so complicated as it might seem, especially when using modern tools like TortoiseSVN or IDE’s.

For this article I’ll use mainly TortoiseSVN, it’s a great subversion client that integrates nicely with the context menu of windows explorer. But at the same time I prefer to work in the environment of an IDE, like JDeveloper and have subversion support. And although JDeveloper offers good subversion support, the current version (11.1.1.2) has a serious issue for merging (see below), so I use TortoiseSVN for this demo instead.

So let’s see how this looks in real life.

Let’s start with a simple project called ‘simpleApp’ that contains a very basic class that we modify on the trunk and a branch at the same and have these changes merged into the other. I’m a great fan of Maven archetype to get started quickly: mvn archetype:generate and choose option 15 (by the way, a preview of the new Maven extension for JDeveloper 11gPS1 is available, so I hope that we can do this directly from JDeveloper in the near future).

The generated project contains one file, App.java and a testcase. Import this project into subversion. I normally create the project directory and the default trunk, tags and branches directly in the repository and then do a checkout of the trunk, add the files and do a commit; but of course you can also use subversion import (followed by a checkout). We’ll see later that it’s very important to write write good commit messages. It’s also good practice to do an update after a commit to make sure that the working copy contains the latest revision.

With TortoiseSVN it’s actually quite easy to add all your files to subversion at once: go to the top (project) directory and select add from the context menu (followed by a commit). I haven’t figured it out how to accomplish that with JDeveloper; when you try to version the project it actually only versions the .jpr file :-(. Suggestions are welcome… By the way, most tools offer the option to define default ignore patterns to have the classes or the maven target directory ignored automatically)

Let’s add a method:

public int multiply (int a, int b) {
    return a*b;
}

And commit this to the repository.

Now it’s time to make our feature branch called ‘featureA’. Do an update first to make sure that the working copy is the latest revision. By convention, we make this in the branches directory. The result can be visualized in the revision graph

We’re now going to work on the feature branch, so switch to featureA. In the subversion context menu (in both JDeveloper and TortoiseSVN) you’ll find the subversion switch command, that let’s you easily change your working copy (NB JDeveloper will not always update an open file immediately, so close it first). The context – properties contains a tab with subversion information, so you can always see where your working copy originates from.

Let’s add a method above the previous one :

 public int add (int a, int b) {
  return a+b;
 }

Commit, switch back to the trunk and notice the add method has diappeared ;-).

Add a method (after the multiply method to prevent conflicts and make the merge process easier (don’t seek the problems if you can avoid them, although… now is a good time to try it out)):

 public int subtract (int a, int b) {
  return a-b;
 }

The situation is now that we have changes in both the trunk and the feature branch. The trunk has a multiply and subtract method, while the branch has a multiply and add method. When you check the subversion log (in JDev it’s called history) you can easily see what happened, on both the trunk and the branch we only see one change. Now you’ll also appreciate the quality of the commit messages.

Next step is to add the change in the trunk (the subtract method) to the branch, so it’s time to merge! Switch the working copy back to the branch.

Select ‘merge’ from the (context)menu.

You have three options (actually, both JDeveloper and TortoiseSVN present the almost same window).

Select the first one, ‘Merge a range of revisions’

Select the trunk to merge from and select the revision to merge via ‘Show Log’.

Select the revisions to merge (again, you’re happy with your comprehensive comment).

Next

Accept the defaults. On top it says to include the whole directory structure, that’s what we want.

You can do a test-run to see if anything unusually happens.

Finish.

The revision from the trunk is now applied to the working copy. You can check this with the context option – ‘Check for modification’.

Commit the changes.

So, the situation is that we have a branch that is synchronized with the trunk. The trunk contains the multiply and subtract methods while the branch also has the add method

Now it’s time to reintegrate the branch with the trunk. Switch the working copy to the trunk.

Actually, it’s the same process: select the changes in the branch and apply them to the trunk. But wait, for this situation there’s a special merge option: ‘Reintegrate a branch’.

merge7

This automagically identifies the changes in the branch from the merges and it will only merge these into the working copy (the trunk), you don’t have to do that yourself. Neat isn’t it :-).

However there are a few catches :

  • Make sure that the branch is done at the correct revision number or else you’ll get a message that some changes have not been applied, so make sure to do an update first before branching.
  • All changes in the trunk must be merged into the branch. If you have changes that should not be applied to the branch, e.g. in the pom file due to a release, you can’t reintegrate (or sort it out later).
  • Don’t merge and do other changes before the commit. You might loose the changes.

If a reintegrate fails, you have to perform the merge yourself. Again, you’re happy with decent log messages to identify the changes from the merges.

Commit.

It’s now also and advisable to remove the branch. Don’t be afraid, you won’t remove it completely, it’s still present somewhere (remember we’re working with a versioning system) and of course, so is the log.

Now when you take a look at the TortoiseSVN log and enable ‘Include merged revisions’, you’ll not only see the changes in the trunk, but also the ones in the branch.

So, branching and merging is nothing to be afraid of. Of course, I realize that this is a very simple example and that in real life things will be more complicated. But both TortoiseSVN and JDeveloper offer very good support for resolving conflicts in case problems arise. All in all, still the best way to prevent big issues is communication. Don’t rely blindly on your tools. Source control can be complex, so if humans have a hard time to figure things out, don’t always expect computers to solve things for you ;-).

A few remarks

  • Use a recent, 1.6.x, subversion client and server because the mergeinfo is only available since version 1.5 (and improved with 1.6). Only JDeveloper 11gPS1 has an 1.6 client, the previous 11g has a 1.5 client, while 10g only has a 1.4 client (although it’s possible to manually upgrade the subversion client as I described in an earlier).
  • When using maven, branching and reintegration can be a bit more complicated, because the pom file contains scm and version information that is probably different for the branche. You can use the maven release or scm plugins or do the updates manually, but they will result in revisions that are not to be merged or reintegrated. I don’t have a good solution for that, although it should be possible to mark certain revisions as ‘merged’.
  • Each version of JDeveloper provides more and better subversion support, but I still use JDeveloper mainly for the essential functions like commit, update, refactoring etc. Because I find it hard to get a good high level overview on the status of the project or application, I use TortoiseSVN mostly to view the log, to check for modification and to merge at the project level.
  • I’d like to advertise the JDeveloper history tab (for individual files). This is really a great feature, it not only allows easy comparison between different versions, including local changes, but also easy manipulation.

jdev-history

A few remarks for using the JDeveloper subversion extension

  • It’s confusing that the versioning info on the project level is about the jpr file, not the whole project.
  • I haven’t figured out how to get a good overview of the log (history) at the project or directory level. Any suggestions are welcome.
  • Commit of a working copy only shows a directory and not all the all files.
  • It seems that the subversion support in 11gPS1 (extension version 11..1.1.2.36.55.36) has some serious issues. One is about basic authentication when merging (not for update and commit). Another concerns the SOA suite. And a third one is about TortoiseSVN authentication that gets messed up and you have to type username password all the time. Can’t wait for a new version.
Share.

About Author

Aino Andriessen is a consultant on Enterprise Java, ADF, PL/SQL, XML, and SOA development and is Expertise Lead on Application Lifecycle Management (ALM). He has a strong interest in ADF, SOA, Maven, architecture, quality management, delivery and application lifecycle management. Aino publishes on the AMIS technology blog and has been a presenter at the ODTUG Kaleidoscope, Oracle Open World and UKOUG TechEbs.

3 Comments

  1. Just a note to spelling: you used “off course” three times, but correctly it is “of course” (single f).

  2. Pingback: Subversion – branching, merging and reintegration | Oracle