Design notes, plans and ideas by JulianFoad
Guiding Users into Simple and Safe Merging
Aim
Make it much harder to merge the “Wrong Way” by accident.
My goal in one sentence is to stop people accidentally messing up by not understanding what they're doing. I believe one of the main reasons people get their mergeinfo into a mess (from our point of view as developers) is by running Subversion merges without having the correct understanding of what those commands are doing, and by not having a good enough view (reporting) of what they have done. In other words, we make it too easy for users to execute silly merges and not notice until it's too late. We should steer them towards the most common cases and display feedback that indicates whether they're doing something "simple and expected" or something "wierd" that they might not have meant.
Identify the typical merging tasks, which may vary depending on the requirements of the user’s team. Make the typical merging tasks easy to perform; look at TortoiseSVN and other existing GUIs for examples. Clearly distinguish tasks that have different meanings but may currently have similar or identical syntax, to reduce the risk of a user performing a merge that produces the desired output now but will adversely affect future merges. Make it harder to accidentally specify merges that are unusual and not well supported.
Implement these measures by building onto Subversion’s existing library API, command-line UI, client-server interface and/or any other suitable level. If this requires knowledge of the user’s branching model and rules, provide a simple way to configure this and provide one or more typical configurations.
A pre-requisite for designing and implementing such guidance is a clear statement of what merging scenarios Subversion supports. See the document Supported Merge Scenarios.
Pitfalls & Quick Fixes
The aim here is to list things that users might do in Subversion that are not Right — that is, things that will not lead to consistent and useful results in merging later on — that could be avoided by some high-level checks or by better informing the user.
Using branch naming terminology defined in BranchingMergingTerminology.
On a feature branch, attempting to merge to parent without “--reintegrate” is wrong, (except perhaps for a cherry-pick, and that would be unusual). Catch this case. Possibly with hook script? Need awareness of what kind of branch ‘this’ is.
- Catch other cases from the ‘Branching and Merging Policy’ section below.
- On any branch, a reverse-merge of a merge in this branch’s own history will not do what we expect, I think, in that it won’t be recorded. The correctness of that depends on whether the user’s intention was to temporarily roll back that merge (but still intend to do it later) or to record that undoing as a deliberate and permanent change that should be carried through to other branches. The other way to roll back a merge is to reverse-merge the original changes from the source branch. That gives the corresponding mergeinfo update, but it has at least two significant drawbacks: it will hit all the conflicts that were hit and resolved when it was merged the first time; and the exact reverse merge to perform is non-obvious unless the original merge was from a trivial source revision-range.
If you cherry-pick from a feature branch to its trunk, that’s valid for an original change but not if the change that you’re picking is itself a merge (at least if it’s a merge from trunk). We can detect this by seeing whether that change includes a mergeinfo diff.
Common misconceptions
- That merging from branch A to branch B will make B look like A.
- A client said “I merged A to B, then modified B, and now need to revert the change on B; maybe I could do that by merging A to B again”. In that case, I think the merge from A to B was a “reintegrate” which does indeed pretty much make B look like A. (Source: WD support ticket #3013.)
To help avoid this, ‘merge’ should display messages about what it’s doing, using terminology that makes clear that changes are being merged rather than state.
Not realizing that to reintegrate “my” branch I first have to obtain and be “in” a WC of the parent branch.
It’s easy to think “a catch-up merge pulls changes from the parent, so a reintegrate will push changes to the parent”.
- In a typical recommended work flow when the branch is fully caught up and the parent branch is not too busy, a reintegrate will not have any conflicts nor need any further testing, so there should is no logical reason (in those cases) for the user to expect that a WC of the target (parent) branch should be needed.
Reporting -- What “svn merge” Should Say
“svn merge” should first of all give a summary of what it is about to do, using words that make sense to the user. Consider stopping to ask for confirmation (unless --no-interactive). Some of the output should be a summary of what is calculated as needing to be merged. That is not only a chance to check the user’s expectation, but in a merge that involves significant calculating of source revisions, it is also a chance for the user to see that Subversion has been doing something useful up to this point and is about to move on to the next stage of actually merging those revisions.
So for example:
$ svn co $URL/branches/dev1 wc1 $ cd wc1 $ svn merge --reintegrate ^/branches/feature2 Reintegrating '/branches/feature2' into working copy of '/branches/dev1'
and then a summary of the current merging status:
Previous merges from ‘/branches/feature2’ into ‘/branches/dev1’ 4 source changes (latest: r144) in 2 merges (latest: r145)
and any warnings:
warning: working copy contains modifications (all in ‘docs/’)
warning: working copy is not up to date
warning: ‘/branches/feature2’ is not up to date with ‘/branches/dev1’: 2 changes (latest: r166) have not yet been merged. Run ‘svn mergeinfo’ for details.
Reporting -- What “svn mergeinfo” Should Say
In order for a user to understand what merges they have done and need to do, it would be most helpful if Subversion could tell them the current state of a branch with regard to merges. The 1.7 “svn mergeinfo” command is near useless for such understanding: it just outputs a list of revnums without saying what that means in terms of whether the target is fully caught up or not; it doesn’t report anything meaningful about subtree merges and doesn’t even notice them by default; it doesn’t check that you specified a sensible source branch and simply says nothing if you accidentally specified the target branch.
See MergeinfoCommand.
Diff of Mergeinfo Only (feature)
After doing a merge into my working copy, I wanted to know what changes Subversion thinks it has merged. My current option seems to be "svn diff" and manually try to filter out everything except mergeinfo changes. It would be good to have a dedicated way to show mergeinfo changes.
- Main use case: show all changes (from all source branches) that are locally merged into this WC.
- Generalization: show merge info changes (only), for any supported "diff" targets.
- Specializations (e.g. only merges from a specific source branch) are possible but not necessary initially.
UI suggestions:
- svn mergeinfo (--diff? or something)
- svn diff (-g|--use-merge-history?)
It's probably more useful for plain "svn mergeinfo" (with no source branch specified) to default to this kind of behaviour than to default to displaying info about merges from (only) the default source branch. If that doesn't fit the specification of the "svn mergeinfo" command very well and it continues to be able to display info about merges from a specific source branch, then perhaps "svn mergeinfo" should continue to require a source branch to be specified and not choose a default source branch.
Mergeinfo Diff (bug)
Diff, when displaying an added mergeinfo property on a sub-tree, should diff against the previously inherited mergeinfo, not say that all this new mergeinfo represents merges that have just been done. Similarly for a deleted prop.
Discussed in this email thread.
Mergeinfo command - backward compatibility
If you specify --show-revs={eligible|merged} you'll get the old simple list of revs, and if you don't specify either of those then you'll get the new summary instead. Discussed in this email thread.