Merge

This function is initiated via the Team > Merge menu option.

Branching and merging within SVN can become quite complex and so it is recommended that you gain a thorough understanding of the concepts before you start using it. The chapter on Branching and Merging in the Subversion Book provides a detailed description of the concepts as well as many examples of how branching and merging can be used.

Overview

Where branches are used to maintain separate lines of development, at some stage you will want to merge the changes made on one branch back into the trunk, or vice versa.

The merge process works by generating a list of differences between two points in the repository, and applying those differences to your working copy. For example if you want to merge the changes made in revision N then you have to compare revision N with revision (N-1). Novices often ask, “Why do I have to subtract 1 from the start revision.” Think of the underlying Diff process and it will become clearer. To make this easier, when you use Show Log to select a range of revisions to merge, the SVN plug-in for Eclipse makes this adjustment for you automatically.

If you have made changes in your working copy, commit those changes first before executing the merge. Otherwise, if the merge does not go as you expect, you may want to Revert the merged result. In this scenario, the revert command will discard all changes including any you had made before the merge. The only exception to this is files which are added to your working copy by the merge process. When you initiate a revert and there are additions in your working copy, those files are not removed. Instead they become unversioned files in your working copy, and you have to manually delete them before you attempt the merge again.

Process

There are two common use cases for merging which are handled in slightly different ways. These are discussed below.

Merging a Range of Revisions

This method covers the case when you have made one or more revisions to a branch (or to the trunk) and you want to port those changes across to a different branch. To merge revisions you need to Switch to a working copy of the branch in which you want to receive the changes, often the trunk. Select Merge... from the Team context menu.


  1. In the From: field enter the full folder URL of the branch or tag containing the changes you want to port into your working copy. You may also click Browse... to browse the repository and find the desired branch. If you have merged from this branch before, then just use the drop down list which shows a history of previously used URLs.

  2. Because you are porting a range of revisions from the same branch into your working copy, make sure the Use "From:" URL check box is checked.

  3. In the From Revision field, enter the start revision number. This is the revision before the changes you want to merge. Remember that SVN will create a diff file in order to perform the merge, so the start point has to be just before the first change you are interested in. For example, your log messages may look something like this:

            Rev Comments
            39. Working on MyBranch 
            38. Working on trunk 
            37. Working on MyBranch 
            36. Create branch MyBranch
            35. Working on trunk
            34. Working on trunk
            ... 
            

    If you now want to merge all of the changes from MyBranch into the trunk you have to choose 36 as the From Revision, not 37 as you might think. If you select revision 37 as the start point, then the difference engine compares the end point with revision 37, and will miss the changes made in revision 37 itself. If that sounds complicated, don't worry, there is an easier way with the SVN plug-in for Eclipse ...

    The easiest way to select the range of revisions you need is to click on Show Log, as this will list recent changes with their log comments. If you want to merge the changes from a single revision, just select that revision. If you want to merge changes from several revisions, then select that range (using the usual Shift-modifier). Click on OK and the revision numbers of the From revision and To revision in the Merge dialog will both be filled in for you.

    If you have already merged some changes from this branch, hopefully you will have made a note of the last revision merged in the message when you committed the change. In that case, you can use Show Log for the working copy to trace that log message. Use the end point of the last merge as the start point for this merge. For example, if you have merged revisions 37 to 39 last time, then the start point for this merge should be revision 39.

  4. If you have not used Show Log to select the revision range, then you will need to set the To Revision manually. Enter the last revision number in the range you want to merge. Often this will be the HEAD revision, although it doesn't need to be - you may just want to merge a single revision.

    If other people may be committing changes then be careful about using the HEAD revision. It may not refer to the revision you think it does if someone else made a commit after your last update.

  5. Click OK to complete the merge.

It is a good idea to have a look at the merge result and see if it is as you expected. Merging is usually quite complicated. Conflicts often arise if the branch has drifted far from the trunk.

When you have tested the changes and come to commit this revision, your commit message should always include the revision numbers which have been ported in the merge. If you want to apply another merge at a later time you will need to know what you have already merged, as you do not want to port a change more than once. Unfortunately merge information is not stored by SVN. For more information about this, refer to Tracking Merges Manually in the Subversion Book. Branch management is important. If you want to keep a branch up to date with the trunk, you should be sure to merge often so that the branch and trunk do not drift too far apart. Of course, you should still avoid the repeated merging of changes, as explained above.

SVN can't merge a file with a folder and vice versa - only folders to folders and files to files. If you click on a file and open up the merge dialog, then you have to give a path to a file in that dialog. If you select a folder and bring up the dialog, then you must specify a folder URL for the merge.

Merging Two Different Trees

This method covers the case when you have made a feature branch. All trunk changes have been ported to the feature branch, week by week, and now the feature is complete you want to merge it back into the trunk. Because you have kept the feature branch synchronized with the trunk, the latest versions of branch and trunk will be absolutely identical except for your branch changes. So in this special case, you would merge by comparing the branch with the trunk.

To merge the feature branch back into the trunk you need to go to a working copy of the trunk. Select Merge... from the context menu.


  1. In the From: field enter the full folder URL of the trunk. This may sound wrong, but remember that the trunk is the start point to which you want to add the branch changes. You may also click Browse... to browse the repository.

  2. Because you are comparing two different trees, make sure the Use "From:" URL check box is not checked.

  3. In the To: field enter the full folder URL of the feature branch.

  4. In both the From Revision field and the To Revision field, enter the last revision number at which the two trees were synchronized. If you are sure no-one else is making commits you can use the HEAD revision in both cases. If there is a chance that someone else may have made a commit since that synchronization, use the specific revision number to avoid losing more recent commits.

    You can also use Show Log to select the revision. Note that in this case you are not selecting a range of revisions, so the revision you select there is what will actually appear in the Revision field.

  5. Click OK to complete the merge.

In this case you will not need the feature branch again because the new feature is now integrated into the trunk. The feature branch is redundant and can be deleted from the repository if required.

Previewing Merge Results

If you are uncertain about the possible outcome of a merge operation, you may want to preview what will happen before you allow it to change your working copy. There are two additional buttons to help you in this respect.

Unified Diff creates the diff file (remember that merge is based on diff) and shows you which lines will be changed in your working copy files. As this is a unified diff (patch) file it is not always easy to read out of context, but for small scale changes it is often helpful.

Bare in mind that merge and diff are not exactly the same. Merge is smarter and knows how to take into account things like renames and moves. Diff always just shows the end result. Conceptually, they are very similar, but you cannot always just apply a unified diff to a working copy and get the same results as merge.

Dry Run performs the merge operation, but does not modify the working copy at all. It shows you a list of the files that will be changed by a real merge, and notes those areas where conflicts will occur. This information is shown in the SVN Console View.

Undoing changes with Merge

Another common use for merge is to roll back a change that has already been committed. Suppose you are coding in a working copy of /calc/trunk, and you discover that the change made way back in revision 303, which changed integer.c, is completely wrong; it never should have been committed. You can use merge to undo the change in your working copy, and then commit the local modification to the repository. All you need to do is to specify a reverse difference:

$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk 
U integer.c 
$ svn status 
M integer.c 
$ svn diff ... 
# verify that the change is removed ... 
$ svn commit -m "Undoing change committed in r303." 
Sending integer.c 
Transmitting file data. 
Committed revision 350. 

One way to think about a repository revision is as a specific group of changes (some version control systems call these changesets). By using the -r switch, you can ask svn merge to apply a changeset, or whole range of changesets, to your working copy. In our case of undoing a change, we're asking svn merge to apply changeset 303 to our working copy backwards.

Keep in mind that rolling back a change like this is just like any other svn merge operation, so you should use svn status and svn diff to confirm that your work is in the state you want it to be in, and then use svn commit to send the final version to the repository. After committing, this particular changeset is no longer reflected in the HEAD revision.

Again, you may be thinking: well, that really didn't undo the commit, did it? The change still exists in revision 303. If somebody checks out a version of the calc project between revisions 303 and 349, they'll still see the bad change, right?

Yes, that's true. When we talk about removing a change, we're really talking about removing it from HEAD. The original change still exists in the repository's history. For most situations, this is good enough. Most people are only interested in tracking the HEAD of a project anyway. There are special cases, however, where you really might want to destroy all evidence of the commit. (Perhaps somebody accidentally committed a confidential document.) This isn't so easy, it turns out, because SVN was deliberately designed to never lose information. Revisions are immutable trees which build upon one another. Removing a revision from history would cause a domino effect, creating chaos in all subsequent revisions and possibly invalidating all working copies.