Working with branches

NOTE: The rosegarden svn URL on sourceforge has changed. This page has only been partially updated to reflect that. Usually it is simply a matter of replacing all

 https://<user>@rosegarden.svn.sourceforge.net/svnroot/rosegarden

with

 svn+ssh://<user>@svn.code.sf.net/p/rosegarden/code

Keep this in mind while reading this page…

When to branch?

To branch or not to branch?

The decision whether to branch or not is not really something that follows a strict formula, but you should consider doing your work in a branch if it:

  • involves disabling a lot of code in order to work through a problem step by step until it is finally solved
  • is an experimental idea that might not be an improvement, or might not be workable after all
  • is something big and new that might require design modification before everyone can agree on including it in trunk/
  • is anything likely to interfere with another developer's work while you tinker with it
  • if you ever plan to commit code in a broken, non-working state during your development process

Of these, the only really critical and absolute rule is that you must always exercise all possible caution to try to avoid breaking trunk/, and if you ever anticipate committing half-working code, you should almost certainly do this in a branch.

Moving existing code into a branch

The best practice is to think everything out before you begin, realize that you will need to work in a branch, create that branch, and do all your work in there from the beginning.

In reality, it is very common for a developer to begin some project without thinking all of this through for one reason or another. Perhaps what was supposed to be simple has turned out to be much more complicated than expected. Maybe a quick hour of code to knock something out is going to turn into a week or more before all the unexpected problems can be sorted out. Sometimes, you will even begin working from and committing to trunk/ without realizing that your work really should have been done in a branch first, and someone will ask you to branch and complete your work there; merging it after whatever controversy is resolved to everyone's satisfaction.

This is simple to deal with, if this every happens to you. Simply take a patch of your current working copy before you proceed with creating a branch and checking it out.

svn diff > <patch_my_branch>

Note: Replace <patch_my_branch> with a real filename of your choosing

To avoid causing yourself problems down the line, now that you have taken this patch to use later, you should revert these changes from your working copy of trunk/ before continuing.

patch -R -p0 < <patch_my_branch>

You can double check that everything worked properly by running

svn diff

This should produce no output.

Note This technique works very well if all of your modifications were to files that were already under version control. If you have already started adding new files, but have not yet put any of them under version control, they will not be included in your patch, and you will need to keep up with them and move them into your working copy of your new branch later on. Unfortunately, svn diff is of no help in this situation.

Creating a new branch

Whether you are beginning completely from scratch, or you are creating a branch out of existing work you began in trunk/, the next step in this process is to create the branch itself in the Subversion repository.

Create a new branch by copying trunk/. For example, for a branch called <my_branch>, do the following (as a single one-line command):

svn copy svn+ssh://<user>@svn.code.sf.net/p/rosegarden/code/trunk/rosegarden \
         svn+ssh://<user>@svn.code.sf.net/p/rosegarden/code/branches/<my_branch>

You can see what branches already exist (so as to get ideas for a new name, perhaps) using

svn ls http://svn.code.sf.net/p/rosegarden/code/branches/

(Or you can browse the online Subversion repository at http://sourceforge.net/p/rosegarden/code/)

Note: Replace <user> with your SourceForge username and <my_branch> with your branch name.

Checking out a branch

svn co <my_branch>

The full command to checkout my_branch using username is:

svn checkout svn+ssh://<user>@svn.code.sf.net/p/rosegarden/code/branches/<my_branch> <my_branch>

Note: Replace <user> with your SourceForge username and <my_branch> with your branch name.

After the checkout completes, take note of the revision number for later, so you don't have to dig it back up when it comes time to merge. The last message from Subversion will tell you this piece of information, for example:

Checked out revision 10745.

Applying your patch

If you took a patch of the work you began in trunk/ then now is the time to apply that patch to your new working copy of your new branch. Simply use

patch -p0 < <patch_my_branch>

Note: Be sure not to use the -R option in the patch command this time. Replace <patch_my_branch> with the real filename you selected earlier.

If you created any files that were not yet under version control, and were not included in that patch, now is the time to move them across into this directory.

Now you are ready to commit the beginning of your new branch, and get to work in here!

Committing changes to the branch

Working with branches is as easy as working with the trunk. Commit the changes from the root directory of the branch.

cd <my_branch>
svn commit -m "Text which describes the updates."

Merging changes from a branch to trunk

For most branches, you want to keep the merge as simple as possible, and only do this once. Chris Cannam recommends ignoring trunk/ until you are ready to merge, and then doing the merge starting by taking a temporary working copy of trunk/ to get started:

$ svn co https://rosegarden.svn.sourceforge.net:/svnroot/rosegarden/trunk/rosegarden \
  tmp-working-copy

Then change into tmp-working-copy/, and using the revision at which you branched (which you took note of earlier) and the name of your branch, do something like:

$ cd tmp-working-copy
$ svn merge -r<10208>:HEAD
https://rosegarden.svn.sourceforge.net:/svnroot/rosegarden/branches/<my_branch>

Note: Replace <my_branch> with your branch and and <10208> with revision number of the branch noted earlier. Resolve conflicts, build, test… Then run

svn diff

to make sure what you're about to commit looks sane. Then fire away with

svn commit

Merging changes from trunk to the branch

If you are going to be working on the branch for a long time, you may wish to reduce the number of conflicts you may eventually have to resolve by periodically merging from trunk/ into your branch, and then merging the branch back at the end of its life cycle.

You may check the Last Changed revision of the branch with command

svn info

Let us suppose that the last changed svn version was 8114. Then you would like to merge all changes since svn version 8115. You may do it with command

svn merge -r 8115:HEAD https://rosegarden.svn.sourceforge.net/svnroot/rosegarden/trunk/rosegarden

If there are no conflicts, you may continue by committing the changes to the branch.

svn commit -m "merge from trunk"

Note that such a committing does not work if you had conflicts, therefore, resolve conflicts before committing changes.

Resolving conflicts

A conflict occurs when you try to update your working copy from a repository that has conflicting changes in it. This can happen during the normal course of development, when two different people happen to work in the same place. (One common circumstance is that developer C commits broken changes, and both developers A and B rush in with two slightly different, conflicting fixes.)

During a merge, this happens when your branch changes some part of the code that also changed in trunk/, and Subversion cannot decide how to put all the pieces together.

When you experience a conflict (such as the real conflict upon which I'm basing this example), recent versions of Subversion will prompt you what to do:

Conflict discovered in 'data/rc/rosegardenui.rc'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (h) help for more options:

Chris recommends that you just choose p to postpone conflict resolution. (For binary conflicts, you will also get tf and mf for “theirs full” and “mine full” respectively. Which to choose will depend entirely on the circumstances.)

        (h) help for more options: p
--- Merging r10774 through r10874 into 'data/rc':
C    data/rc/rosegardenui.rc

After the conflict, you wind up with several files, similar to these:

file description
rosegardenui.rc original file with alternatives written in
rosegardenui.rc.merge-left.r10773 changes from the left revision (-r[left]:[right])
rosegardenui.rc.merge-right.r10874 changes from the right revision (-r[left]:[right])
rosegardenui.rc.working your previous working copy

Chris works with the plain .c file, which is the original file with the conflicts given in an “alternatives” diff-like form, such as this excerpt:

    <Action name="file_revert"/>
  </enable>
</State>

<<<<<<< .working
<State name="have_project_packager">
  <enable>
    <Action name="file_import_project"/>
        <Action name="file_export_project"/>
  </enable>
</State>

=======
>>>>>>> .merge-right.r10874
<State name="have_segments">
  <enable>
    <Action name="move"/>

In this case, I apparently removed some code from part of the file that simultaneously changed in trunk/ and Subversion got confused. I can't remember what I did where, or who did what, so while Chris recommends working only with the plain .c file, I have found I can't figure out what I'm looking at in this case.

I decided to have a look with Kompare.

kompare rosegardenui.rc.merge-left.r10773 rosegardenui.rc.merge-right.r10874

I find the visual presentation easier for getting a real sense of what's going on, although the particular example I happened to have chosen to present here (because it was the first one I had at hand) is not particularly good. This conflict is easy to resolve.

In any case, once you have discovered what is going on to your satisfaction, edit the file until you're happy with it, then run

svn resolved <filename>

to tell Subversion that you have resolved the conflict.

Test and commit.

Closing a branch

When a branch is finished with, we usually either delete it if it was very short-lived and uninteresting,

svn rm https://<user>@rosegarden.svn.sourceforge.net/svnroot/rosegarden/branches/uninteresting

or else move it to the branches/obsolete directory on the Subversion server. If in doubt, do the latter:

svn mv https://<user>@rosegarden.svn.sourceforge.net/svnroot/rosegarden/branches/my_branch \
       https://<user>@rosegarden.svn.sourceforge.net/svnroot/rosegarden/branches/obsolete/

Example of a planned and focused branch

 
 
dev/branching.txt · Last modified: 2013/07/02 12:55 (external edit)
Recent changes RSS feed Creative Commons License Valid XHTML 1.0 Valid CSS Driven by DokuWiki