Branching and Merging

From Docswiki
Jump to navigation Jump to search

Branching

A branch is created in the repository by remotely copying one of the existing development streams (e.g. trunk) as follows:

svn copy url-old url-new

where, for example, url-old is $SVN/trunk and url-new is $SVN/branches/your-new-branch-name . Since this procedure acts on the repository directly it causes a near-instantaneous commit. This means that you will have to provide a log message in some way (the command given exactly as above can act in the same way as svn commit, by opening your favourite editor for you to type the message).

Now that your branch exists in the repository you can get a working copy of it in a number of ways:

  • 'svn checkout' from an appropriate place in your local directory structure.
  • 'svn update' from an appropriate place in your local directory structure (within a directory that came from the repository at some point and from which the new branch would be a subdirectory.
  • 'svn switch' - see the SVN manual for details.

Merging

When a branch is created for the development of a new feature, the aim is for the completed changes to eventually be incorporated into the trunk as part of the mainstream evolution of the codebase. However, the trunk itself will probably have progressed since the point at which you copied it to make your branch. Just as it's important to run 'svn update' regularly to pull other people's changes made on the same branch into your working copy, you should also regularly and carefully merge the concurrent changes on trunk into your own branch.

Before merging, always make sure that your working copy of the destination branch (the one that will receive the changes) has no local modifications to files under version control and is up-to-date with respect to the repository, i.e. your working copy and the HEAD of the branch are identical. Otherwise the process of merging gets unnecessarily complicated...

Also note that the procedure for merging depends on which versions of svn you and the repository server are running: if both >= 1.5 then new functionality exists to help you (see the SVN manual for more information). If either < 1.5 (which is the case currently for us) then you have to keep track of some information 'by hand', as described below. For all versions of svn, though, a merge involves two distinct stages: the changes from the repository are made locally, to your working copy, and then those changes are committed to the branch in the repository.

An example, part 1: merging into your branch the set of changes committed to trunk between the point (say revision 30) at which you created your branch and the current HEAD of trunk (call it revision number 50).

  • From the local directory containing the working copy of your branch, run 'svn merge -r 30:50 <URL-of-trunk>'
  • Examine the changes applied locally with 'svn diff' and test them thoroughly.
  • When you're satisfied, commit the changes to your branch: 'svn commit' with a helpful log message that records the revision range you merged, followed by 'svn update' as usual.

Note that you need to tell Subversion explicitly the revision range you are merging. When the time comes to make another merge into your branch of the subsequent changes on trunk, i.e. those between revision 50 and the now-current HEAD (revision 60 say), you follow the same steps but give a different revision range, -r 50:60, in the merge command. In order to find out the revision number of the end-point for the previous merge (which is 50 in this example), you should consult the commit log. The developer should take care that Subversion is NOT asked to apply the same set of changes more than once to a branch.

An example, part 2: merging all the changes made on your branch into trunk when your development work is complete (and documented and tested!).

  • Make sure you have a working copy of trunk that has no local modifications and is up-to-date with respect to the HEAD of the repository.
  • Update your branch with the latest changes on trunk, i.e. do a final merge from trunk into your branch, as above.
  • You need to identify the revision number at which your branch was created, as the lower limit of the merge range corresponds to the initial state of the branch. This is revision 31 in our example, which came from the trunk at revision 30. You can readily find this out with the following command: 'svn log -v --stop-on-copy', which stops the log messages at the point where the copy command was issued to create the branch.
  • From the local directory containing the working copy of trunk, run 'svn merge -r 31:HEAD <URL-of-your-branch>'

With such a command you'll apparently be applying changes ported from trunk into your branch back into trunk -- Subversion should behave sensibly and leave those parts of trunk as-is (and indeed as it should be).

  • Examine the changes applied locally with 'svn diff' and test them thoroughly. You may well have to resolve some conflicts.
  • When you're satisfied, commit the changes to trunk with a helpful log message that records the merge range.

If you go through this procedure again later, after more commits have been made to your branch, the merge range should be from the number corresponding to HEAD at the time of the previous such merge to the current HEAD.

Merging summary

The merge command has a '--dry-run' option that can provide a useful overview without actually applying any changes. Also remember that changes applied after a merge are local until they are committed: they can be reverted if necessary or tweaked to resolve any incompatibilities or conflicts, etc, before the actual commit. Merging can be confusing at first: take your time over it, don't panic, and consult the manual for much more information!