--------------------------------------------------
From: "Stefan Sperling" <s...@elego.de>
Sent: Wednesday, April 20, 2011 6:38 AM
To: "Daniel Walter" <d2wal...@hotmail.com>
Cc: "Bob Archer" <bob.arc...@amsi.com>; <users@subversion.apache.org>
Subject: Re: duplicate merge conflict
On Tue, Apr 19, 2011 at 09:34:17PM -0400, Daniel Walter wrote:
I understand what is going on now, but this seems to indicate that I
will need to look up revision numbers from tags every time I do a
merge in SVN. Is there any automated way of doing this? It seems
like a huge step backwards to go from using symbols that mean
something to me to using numbers that only mean something to my
version control software.
Yes, any cherry-picking approach will require you to know which revision
numbers are relevant to a given bug fix.
The Subversion projects keeps a file on each branch for that purpose:
https://svn.apache.org/repos/asf/subversion/branches/1.6.x/STATUS
Where and how the mapping from bug fix to revision number is done doesn't
really matter but with cherry-picking you'll need some way of identifying
which revisions belong to which bug fix. A bug tracking interface like
Trac
or Redmine that integrates with Subversion can help here. You'll still
have to enter the data e.g. adding an entry in bug tracker item #5 to say
that revision 42 is related to bug #5. But once the data has been entered
it is nicely linked up and can be browsed easily.
Perhaps I should be using some other form of automated merging in
SVN, but none of the automated merge schemes listed is remotely like
my merge workflow. I have three versions.
4.1 on a branch
4.2 on a branch
4.3 on a trunk
I need to merge any bug fixes or changes that I make to the older
versions forward into the newer versions and then the trunk.
Currently I make a new tag on each branch whenever I merge changes
forward.
It sounds like you have something like this:
4.1.x-release +--------------------------------
/ +--- 4.3.x-release
/ /
/ /
trunk ------+---+-----------------------------+----
\
\
\
4.2.x-release +-----------------------------
You make fixes on the oldest release first, then to 4.2.x, then to trunk.
You can do this by cherry-picking the appropriate revisions from one
branch
to another:
4.1.x-release +--------LR----------------------
/ | +--- 4.3.x-release
/ | /
/ | /
trunk ------+---+--------|---o----------------+----
\ | ^
\ | /
\ v /
4.2.x-release +----o------------------------
LR
This is a good diagram of what we are doing. The word cherry-picking is
misleading though because we use this approach to periodically merge forward
everything. The only cherry-picking would be something that we specifically
didn't want merged forward and this is extremely rare. This is part of the
reason why we make the bug fixes on the branches for the earlier releases.
If you make the modifications to the trunk, you need to choose what to merge
backwards, but if you make the modifications to an earlier release, you can
generally merge everything forward.
Many projects using Subversion make trunk the initial target of bug fixes
and then merge those over to release branches using cherry-picking:
4.1.x-release +-----------------------o--------
/ ^ +--- 4.3.x-release
/ | /
/ | /
trunk ------+---+----------------------LR-----+----
\ |
\ |
\ v
4.2.x-release +-------------------o---------
If you don't want to think about revision numbers the following pattern
might help (or at least be inspiring) if you can live with (or work
around)
limitations explained below.
unstable changes maintenance mode
4.2.x-release +-----------------R---------------------R.......
/ . \ . \
/ ................ \ ............... \
/ . v . v
trunk ------+-L-----------------------o-L--+----------------o....
rW rX \
\
4.3.x-release +---------------...
unstable changes
Basically, trunk never receives direct commits but only reintegrate
merges from the release branches. Note that in this pattern release
branches
represent *future* releases you haven't already released for production.
Though maybe you did release them for testing purposes.
Trunk is always in a releasable state. It is initially your 4.1.x-release
and becomes the 4.2.x-release once the 4.2.x-release branch has been
reintegrated for the first time.
The 4.2.x-release branch now goes into maintenance mode and trunk receives
bug fixes from it via additional reintegrate merges.
(You need to use the trick described at
http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced.html#svn.branchmerge.advanced.reintegratetwice
to keep the release branch alive after reintegration.)
This pattern avoids juggling with revision numbers but has some drawbacks.
You must consider trunk to be the stable and releasable state. And you
must
stop maintaining older releases as soon as a new release hits trunk.
By the time you merge 4.2.x into trunk the 4.1.x release line has reached
end of life and will never receive additional updates.
This is an interesting pattern, but does not seem like it would apply very
well to our development because we merge forward changes on a regular basis.
This pattern works only with one future release line. You can prepare the
4.3.x release on a release branch off trunk while 4.2.x is in maintenance
mode.
The 4.3.x release branch then regularly syncs to trunk to receive bug
fixes
originally made in 4.1.x which have been reintegrated into trunk.
But in some scenarios this works quite well in spite of these drawbacks.
E.g. this pattern is being used in practice at a web shop where trunk
is deployed to production servers and release branches are deployed to
testing servers. There is no need to maintain old versions of the website
as soon as the latest release has gone live.
Thank you for the suggestions. After learning how this worked, I thought
there might be something that I am missing, but that does not seem to be the
case. I think at this point, my best solution is still to use tags and just
find the revisions for the tags before doing merges with svn info if I think
that a particular merge will generate a lot of conflicts.
Daniel