See "Keeping a Reintegrated Branch Alive" in the Svn Book here: http://svnbook.red-bean.com/en/1.6/svn-book.html#svn.branchmerge.advanced.reintegratetwice.
Simple Use Case
Here's a diagram showing a typical feature-branch work flow and the step we want to eliminate.
Rev |
A |
B |
Commit |
r10 |
X |
|
|
r20 |
|
X |
New branch B from A |
r30 |
|
X |
Modify B |
r40 |
M |
|
Reintegrate B to A |
r45 |
|
R |
Keep-alive record-only merge A@40 to B |
r50 |
X |
|
More work in A |
r60 |
|
M |
Sync merge A to B |
The sync merge r60 should take r50 but not r40.
Ways to make it easier
(in order from easiest to implement to best for the user):
- Make it easier for the user to do the record-only dance: make 'svn merge' print the required command at the end of the merging. Perhaps store info in the WC and make 'svn commit' notice and at least print a reminder. Possibly even have 'svn commit' do that keep-alive commit after the regular commit. (With the current mergeinfo design it needs to be a separate commit because it needs to reference the rev number of the first commit.)
svn merge --reintegrate ^/branches/this-branch trunk-wc --- Merging ... [...] To continue using the source branch after this reintegration, note the new revision number REV created by the commit and perform the following command in a working copy of that branch: svn merge --record-only --change REV ^/trunk .
- Provide some way for the user to mark a revision as merged without requiring a working copy. I'm not suggesting to tell people to 'svn propedit' the svn:mergeinfo property directly, but to have a way to achieve the desired effect with 'svn merge'. For instance, we could allow --record-only merges on URL targets. [Idea from stsp.]
- Make the reintegrate command optionally commit the result if there are no conflicts (which is typically the case, if the branch was up to date and the trunk isn't too busy). After the reintegrate command commits the reintegration, make it do the keep-alive commit directly in the repo. It would require a clean WC so that it knows this reintegration is the only thing it is committing. This would not allow running regression tests prior to commit.
svn merge --reintegrate --commit ^/branches/this-branch trunk-wc --- Merging ... [...] --- Committing ... [...] Committed revision 1234. --- Committing a mergeinfo adjustment to keep the source branch alive ... [...] Committed revision 1235.
- Make a no-WC reintegrate command, that performs the reintegrate and commits it, and then does the record-only straight into the repo. This work-flow is possible because typically there should be no conflicts when reintegrating; bail out if there are. It might be hard without a WC, might need some Subversion library re-architecting.
- Make the "sync merge" code recognize the reintegration revision without having to record-only it on the branch. Either store a special marker in the svn:mergeinfo at reintegrate time, or deduce the fact at sync-merge time. Difficult I know.
Complex Use Case
In the final sync merge in this more general use case, the interesting question is what to do with r11.
A@1---r4---r5---r6---r7----------------r11-----------> |\ ^ | | \ | | | \ reintegrate | | V | | | A_COPY_2-----------------r9---r10--- | | ^ sync merge | / | | cherry-pick merge of r8 | V / V A_COPY-------------------r8------------------------->
We can see that part of r11 is "new" and should be merged (the part that came from r10), but another part of r11 is a change we already have (the part that came from r8). What are the options?
- Try to merge r11 into A_COPY (and record it as merged), accepting that (in principle) it will conflict.
- Don't merge r11 into A_COPY (and don't record it).
- Instead of taking r11 as a whole change, find its constituent parts and merge the required parts. Then record r11 as merged.
- Stop and report the problem.
Option (1) is the current (<=1.7) behaviour. Merging r11 will (in general) produce conflicts because the part of the change that originated as r8 will be re-played onto A_COPY which already has r8. Some of the conflicts might be "physical" conflicts, detected and reported by Subversion, while others might be automatically resolved by Subversion, while still others might be logical conflicts that cannot be detected automatically. Because we know that the merge will confilct (and can determine it algorithmically), we should at least display a diagnostic message that gives details of which change(s) being merged include some changes that are already present.
Option (2) leaves the user to decide whether and how to fill in the missing bits. Like option (1) we should at least display a diagnostic message that gives details. A disadvantage is that the revisions from the source branch end up being merged out of order: the current merge will proceed with the later revisions, and then if the user wants to merge the relevant parts of the skipped revision those parts will be merged later.
Option (3) could be done in several different ways. Examples:
- Reverse-merge r8 from A_COPY and then merge r11.
- Just merge r10 into A_COPY.
- Reverse-merge r9 from a temporary copy of A@11 and then merge the resulting {r11 minus r9} into A_COPY.
The best way to perform this partial merge would depend on the relationships between the branches, such as how similar each one is to each other one. There is no single Right Way, and there is no way to perform such a merge that would never produce conflicts. Designing a partial-merge algorithm would advance the merge tracking capability into a significantly more sophisticated model.
Option (3) is too complex and so is not under consideration here.
Option (4) has the advantage that the user can take action such as performing other merges (especially onto the source or target branch of the interrupted merge) before continuing. This may be better than (2) because the source revisions would be merged in order.
I would propose that Subversion give users the ability to specify in advance or interactively what action to take when encountering a partially-merged revision. The backward-compatible default would be option (1) plus a diagnostic message. The options would be (1), (2) and (4).