===============================================================================
===
=== HOWTO: Developer branches and branch merging
===
=== Updated by: $id$
=== Last updated: $date$
===============================================================================

This document will help provide instructions on using developers branches and
merging code between the various branches.

-------------------------------------------------------------------------------
--- PREREQUISITES
-------------------------------------------------------------------------------

   *** IMPORTANT ***
   Ensure you always have the most recent version of svnmerge from the
   repotools repository.

   $ svn co http://svn.digium.com/svn/repotools/ ~/.repotools
   $ cd ~/.repotools
   $ ./configure
   $ sudo make

-------------------------------------------------------------------------------
--- BRANCH MERGING POLICY
-------------------------------------------------------------------------------

   *** IMPORTANT ***
   As of July 23, 2010 [1], the order of merging changes between branches is:

      1.4 --> 1.6.2 --> 1.8 --> trunk

   [1] http://lists.digium.com/pipermail/asterisk-dev/2010-July/045308.html

-------------------------------------------------------------------------------
--- DEVELOPER BRANCHES
-------------------------------------------------------------------------------

   *** NOTE ***
   If you have been granted access to https://origsvn.digium.com, you will have
   to read and electronically signed the Open Source Contributor License found
   at https://issues.digium.com (upon signing in). You will then been given an
   access certificate.

The SVN repositories contain a number of branches, and development team members
can have their own public and private working branches.

-------------------------------------------------------------------------------
--- USING SVNMERGE FOR CROSS-BRANCH MERGING
-------------------------------------------------------------------------------

   *** NOTE ***
   For purposes of this document 1.4, 1.6.2, 1.8 and trunk branches will be
   used.

The svnmerge script is used for handling cross-branch merging, since it makes
tracking what is available to merge easy and simple to handle. 

If you do a 'svn pl -v' while you are located in a checked out branch you will
see all the properties currently attached to the root directory of the branch.
For example, on a copy of the trunk, you will see something like this:

   $ cd ~
   $ svn co https://origsvn.digium.com/svn/asterisk/trunk asterisk-trunk
   $ cd asterisk-trunk
   $ svn pl -v
   Properties on '.':
     branch-1.8-blocked
       /branches/1.8:
     branch-1.8-merged
       /branches/1.8:1-279056,279113,279227
   ...

and on the 1.8 branch, you will see:

   $ cd ~
   $ svn co https://origsvn.digium.com/svn/asterisk/branches/1.8 asterisk-1.8
   $ cd asterisk-1.8
   $ svn pl -v
   Properties on '.':
     branch-1.6.2-blocked
       /branches/1.6.2:
     branch-1.6.2-merged
       /branches/1.6.2:1-279056,279207
   ...

In the old days, one person could use these properties via svnmerge (if they
were properly updated) to quickly merge all candidate patches into a working
branch.

The way svnmerge has been used has changed from release to release. "Back in
the day", all the fixes applied to 1.2 would be accumulated and applicable
fixes would be folded back into 1.0. As Asterisk has grown, this is a hard job
for one person to perform.

Now, each developer is expected to make sure that each fix they develop gets
applied to all supported releases. The best way to do this is to apply the fix
to the oldest applicable release, and then use svnmerge to help you update the
newer branches or trunk. This process will keep the 'merged' and 'blocked'
properties up to date and accurate. For instance, if you apply a fix to 1.4,
you will then use svnmerge to apply that revision to the 1.6.2 branch, and once
that is committed, you will then use svnmerge to apply that 1.6.2 revision 1.8
then 1.8 to trunk.

Even if the changes are radical enough, that conflicts result from the use of
svnmerge, at least you have the 'merged' revision numbers updated. You can
revert any messed up files and apply a more specific patch to make things work.
If you do not choose to use svnmerge (not recommended) to apply a specific
revision from an older tree, then you must at least use the svnmerge block
command (outlined below) to add the revision number to the 'blocked' property.

The svnmerge script will prompt for your certificate passphrase quite a few
times (possibly many, many times) during its operations. One option is to use
this 'expect'-based script which allows you to temporarily cache your password
while svnmerge runs. Another is to set the configuration variables:

   $ vi ~/.subversion/servers

   ssl-client-cert-file = /path-to-your-digium-supplied-file/username-cert.p12
   ssl-client-cert-password = mypword
   ssl-authority-files = /path-to-your-digium-supplied-cacert-file/Digium_SVN-cacert.pem

   *** IMPORTANT ***
   Developers with commit privileges are expected to do their best to avoid
   committing the following properties into the 1.4, 1.6.2, 1.8 and trunk
   branches:

   * svnmerge-integrated
   * automerge
   * automerge-email

-------------------------------------------------------------------------------
--- CREATING AND MAINTAINING A DEVELOPER BRANCH
-------------------------------------------------------------------------------

Developer branches are stored in the /team/{name} directory of each project
repository (and /team/{name}/private for private branches). Below are 2
examples for creating a branch and prepare it for future merge tracking.

Example 1: trunk branch

   $ svn copy https://origsvn.digium.com/svn/asterisk/trunk \
      https://origsvn.digium.com/svn/asterisk/team/jdoe/my-fun-branch
   $ svn co https://origsvn.digium.com/svn/asterisk/team/jdoe/my-fun-branch
   $ cd my-fun-branch
   $ svnmerge init

svnmerge will setup a custom property on your branch to indicate where it was
copied from and which revisions it already includes.

   $ svn propset automerge '*' .
   $ svn propset automerge-email 'jdoe@example.org' .

   ***NOTE***
   Enabling these properties are optional.  Your branch does not normally get
   updated on its own unless you use the 'automerge' properties. If enabled on
   the root dir of your branch, the subversion server will merge, from the
   associated trunk or branch, into your repository on a regular basis (the
   equivalent of an 'svn update' and 'svn commit' on the server).  You pull 
   these changes down into your working copy via a simple 'svn update'.

   $ svn commit -m "init and automerge"

Example 2: 1.6.2 branch

   $ svn copy https://origsvn.digium.com/svn/asterisk/branch/1.6.2 \
      https://origsvn.digium.com/svn/asterisk/team/jdoe/my-fun-branch
   $ svn co https://origsvn.digium.com/svn/asterisk/team/jdoe/my-fun-branch
   $ cd my-fun-branch
   $ svnmerge init
   $ svn propset automerge '*' .
   $ svn propset automerge-email 'jdoe@example.org' .
   $ svn commit -m "init and automerge"

-------------------------------------------------------------------------------
--- MERGING AND BLOCKING PROCEDURES
-------------------------------------------------------------------------------

   *** NOTE ***
   It is extremely important you always have an up to date version of repotools
   installed.  

Any issues should be fixed in the farthest back branch currently being
maintained. The fix should then be merged up to the last branch it is
applicable to. If a fix is not applicable to the branch it should be blocked
instead.

The following examples demonstrate how to merge r279687 from the 1.4 branch
into 1.6.2, 1.8 and finally trunk.

Step 1: 1.4 branch into 1.6.2

   $ merge46 279687
   spawn /usr/local/bin/svnmerge.real merge -P branch-1.8-merged -B branch-1.8-blocked -f ../merge.msg -r 279687
   property 'branch-1.4-merged' deleted from '.'.

   property 'branch-1.4-blocked' deleted from '.'.

   --- Merging r279687 into '.':
   U    CHANGES

   property 'branch-1.4-merged' set on '.'

   property 'branch-1.4-blocked' set on '.'

   *** NOTE ***
   The revision number (279687) is from the 1.4 branch commit.

   $ vi CHANGES
   $ svn resolved CHANGES

   *** OPTIONAL ***
   Resolve any conflicts generated by the merge process.

   $ ./contrib/scripts/ast_live configure
   $ make
   $ ./contrib/scripts/ast_live install
   $ ./contrib/scripts/ast_live samples
   $ ./live/asterisk -vvvvvc

   *** RECOMMENDED ***
   Verify Asterisk will comple, install and start.  If possible test any
   relevant changes. 

   $ svn commit -F ../merge.msg
   Sending        .
   Sending        CHANGES
   Transmitting file data ..
   Committed revision 279688.

Step 2: 1.6.2 branch into 1.8

   $ merge68 279688
   spawn /usr/local/bin/svnmerge.real merge -P branch-1.6.2-merged -B branch-1.6.2-blocked -f ../merge.msg -r 279688
   property 'branch-1.6.2-merged' deleted from '.'.

   property 'branch-1.6.2-blocked' deleted from '.'.

   --- Merging r279688 into '.':
   U    CHANGES

   property 'branch-1.6.2-merged' set on '.'

   property 'branch-1.6.2-blocked' set on '.'

   *** NOTE ***
   The revision number (279688) is from the 1.6.2 branch commit.

   $ vi CHANGES
   $ svn resolved CHANGES

   *** OPTIONAL ***
   Resolve any conflicts generated by the merge process.

   $ ./contrib/scripts/ast_live configure
   $ make
   $ ./contrib/scripts/ast_live install
   $ ./contrib/scripts/ast_live samples
   $ ./live/asterisk -vvvvvc

   *** RECOMMENDED ***
   Verify Asterisk will comple, install and start.  If possible test any
   relevant changes. 

   $ svn commit -F ../merge.msg
   Sending        .
   Sending        CHANGES
   Transmitting file data ..
   Committed revision 279689.

Step 3: 1.8 branch into trunk

   $ merge8trunk 279689
   spawn /usr/local/bin/svnmerge.real merge -P branch-1.8-merged -B branch-1.8-blocked -f ../merge.msg -r 279689
   property 'branch-1.8-merged' deleted from '.'.

   property 'branch-1.8-blocked' deleted from '.'.

   --- Merging r279689 into '.':
   U    CHANGES

   property 'branch-1.8-merged' set on '.'

   property 'branch-1.8-blocked' set on '.'

   *** NOTE ***
   The revision number (279689) is from the 1.8 branch commit.

   $ vi CHANGES
   $ svn resolved CHANGES

   *** OPTIONAL ***
   Resolve any conflicts generated by the merge process.

   $ ./contrib/scripts/ast_live configure
   $ make
   $ ./contrib/scripts/ast_live install
   $ ./contrib/scripts/ast_live samples
   $ ./live/asterisk -vvvvvc

   *** RECOMMENDED ***
   Verify Asterisk will comple, install and start.  If possible test any
   relevant changes. 

   $ svn commit -F ../merge.msg
   Sending        .
   Sending        CHANGES
   Transmitting file data ..
   Committed revision 279690.

-------------------------------------------------------------------------------
--- PRIVATE AND GROUP BRANCHES
-------------------------------------------------------------------------------

Private branches are branches that only you and the repository managers can
create, explore, modify, and access.

You can create a private branch, much like any other branch, by creating a
branch in your team/jdoe/private directory:

    $ svn copy https://origsvn.digium.com/svn/asterisk/trunk \
        https://origsvn.digium.com/svn/asterisk/team/jdoe/private/my-fun-branch
    $ svn checkout https://origsvn.digium.com/svn/asterisk/team/jdoe/private/my-fun-branch

You can grant others access to your private branch, if you send
russell@digium.com the appropiate information.

    *** IMPORTANT ***
    It's also important to note that all work placed into developer branches
    for the Asterisk, Asterisk-Addons, DAHDI and Libpri projects is covered by
    your contributer license agreement, regardless of whether you ever offer it
    for inclusion into the project's main trunk or not. In addition, the
    repository managers have a private mailing list where see all your commits
    to private branches.

Group branches are branches that everyone can see and explore, but only those
with commit privileges can modify. Group branches are for medium-/long-term
projects involving multiple developers. They are stored in the team/group area
in each repository.

You can create a group branch, much like any other branch, by creating a branch
in the team/group directory:

    $ svn copy https://origsvn.digium.com/svn/asterisk/trunk \
        https://origsvn.digium.com/svn/asterisk/team/group/my-fun-branch
    $ svn checkout https://origsvn.digium.com/svn/asterisk/team/group/my-fun-branch

-------------------------------------------------------------------------------
--- MERGING A BRANCH INTO TRUNK
-------------------------------------------------------------------------------

    *** IMPORTANT ***
    If your branch contains new functionality please make sure you have made
    the proper modifications to CHANGES or UPGRADE.txt.  Also be sure you have
    created the appropiate documentation.

If a developer has a branch that is ready to be merged back into the trunk,
here is the process:

    $ svn co https://origsvn.digium.com/svn/asterisk/trunk trunk
    $ cd trunk
    $ svn merge --ignore-ancestry https://origsvn.digium.com/svn/asterisk/trunk \
        https://origsvn.digium.com/svn/asterisk/team/jdoe/bug12345 .

    *** NOTE ***
    This is NOT using the svnmerge script; this is just a normal SVN merge.

Once this is done, the working copy will contain the trunk plus the changes
from the developer branch. If you follow the above instructions for creating
branches, you have probably introduced properties to the root of the branch
that will not be healthy for the trunk SVN repository.

To restore the properties as they normally should be in the trunk repository,
issue the command:

    $ svn revert .

If you are purposely introducing new properties, or purposely introducing new
values for existing properties, then you might do the following instead, so as
not to destroy your properties:

    $ svn pd svnmerge-integrated .
    $ svn pd automerge .
    $ svn pd automerge-email .

If everything merged cleanly, you can test compile and then:

    $ svn commit -m "commit message for bug 6754"

If not, 'svn revert -R.' will revert all the changes that the merge brought
over.

Once the contents of your branch has been merged, please use 'svn remove' to
remove your development branch from the repository. It will still be accessible
if needed by looking back in the repository history, but removing it from the
current view will make the automerge and other processes run more efficiently.

-------------------------------------------------------------------------------
--- VIEWING CROSS-BRANCH DIFFS
-------------------------------------------------------------------------------

If you would like to see the differences between two branches, you can do it
without even having any working copies. The following command shows the diff
between a developer's team branch and the trunk:

    $ svn diff http://svn.digium.com/svn/asterisk/trunk \
      http://svn.digium.com/svn/asterisk/team/jdoe/my-fun-branch > branch.diff

-------------------------------------------------------------------------------
--- AUTOMATIC UPDATING OF DEVELOPER BRANCHES
-------------------------------------------------------------------------------

Branches you create in your developer area can automatically track the branch
they are based on. To do so, follow these steps in a working copy (checkout)
of your developer branch:

    $ svn propset automerge '*' .
    $ svn propset automerge-email 'bob.smith@example.org' .
    $ svn commit

From that point on, once per hour the Subversion server will check your branch
to see if any updates need to be merged, and merge them if possible.

If conflicts occur, the merge will not be done, but the 'automerge' property
will be removed from your branch to stop any future automerge attempts until
you correct the situation. If you wish to receive an email when this occurs,
add a property called 'automerge-email' with your desired email address to your
branch, and you will get the 'svn status' output when the merge conflicts
occur.

An automerge script is run on the SVN repositories on a regular basis. All this
script does is basically run an 'svn update', and 'svn commit' on any branches
that have the 'automerge' property attached. If this script fails, or stops
running, you can hand-merge these using the 'svnmerge avail' and
'svnmerge merge' commands outlined above.

-------------------------------------------------------------------------------
--- FAQ
-------------------------------------------------------------------------------

TODO!
