[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: RFC: revised text for "svn help merge"

From: Paul Burba <ptburba_at_gmail.com>
Date: Mon, 1 Nov 2010 12:15:32 -0400

On Fri, Oct 29, 2010 at 11:57 AM, Stefan Sperling <stsp_at_elego.de> wrote:
> Our current help texts explain syntax of commands quite well,
> but they don't really explain the semantics. This makes svn help
> fairly useless for people who just want to get going with their
> first steps in Subversion.
>
> The Subversion book on the other hand explains the semantics very well,
> but it literally takes pages upon pages for doing so. It is quite
> detailed and often provides too much information (and verbiage) for
> people who just want to get going. Many people end up coming to the #svn
> IRC channel looking for help, only to be told to read the book anyway.
>
> I think "svn help" should cover more middle ground. To illustrate what
> I'd like to do, I've rewritten the help text for "svn merge", because
> its current form is a particularly bad example of virtually useless help
> text for people who just want to get started.
>
> In Subversion courses and workshops I give during my work at elego,
> I usually introduce the merge functionality of Subversion based on
> use cases people will need to deal with. I've found that people have
> little difficulty working with "svn merge" after being given a short
> use-case focused introduction.
>
> So the proposed help text below centers around the most common use cases.
> It is longer than the old help text, but leaves out many details covered
> in the book. Note that I've also changed the order in which the various
> merge types are presented. The current help text starts out explaining
> the syntax of 2-URL merges, which are rarely needed these days, and the
> most difficult to understand at the semantic level.
>
> I'd like to revise help texts for other subcommands in a similar manner.
> Eventually, I'd like svn help will point out in which order the subcommand
> help texts can be read to receive a small introductory tutorial on svn.
> But it would also refer people to the book for more information.
>
> Of course, good texts present just the right amount of information
> with as little words as possible. I don't think the below text is as
> good as it can get yet, but I got tired of tweaking it for today.
>
> Thoughts? Comments?
>
> Thanks,
> Stefan

Hi Stefan,

Disregarding the other questions on this thread re how to store the
help text and whether to introduce a two-tier --verbose help option
(which seems reasonable), I like the basic concept.
Comments/suggestions are inline:

> merge: Apply the differences between two sources to a working copy path.
> usage: 1. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]
> 2. merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]
> 3. merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]

Minor nit, but 2 and 3 should align with 1.

> 1. The first form is called a "sync" merge, or "cherry-pick" merge:
> svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]
>
> A sync merge is used to merge into a branch any unmerged changes
> made on its immediate ancestor branch.
>
> A cherry-picking merge is used to merge into a branch selected
> changes made on another branch.

     A cherry-picking merge is used to merge specific revisions from one
     branch to another.

> In both cases, SOURCE is a URL. If REV is specified, it is used as
> the peg revision for SOURCE, i.e. SOURCE is looked up in the repository
> at revision REV. If REV is not specified, the HEAD revision is assumed.

I'd remove the line "In both cases, SOURCE is a URL." because it's a
bit unclear. Are we saying "*IF* source is a URL, then *something*"
or "SOURCE *must* be a URL", or something else?

> The source can also be specified as working copy path, in which case
> the URL of the merge source is derived from the working copy.

This is not entirely true since a sync merge requires a URL as the source:

>svn merge trunk branch
  ..\..\..\subversion\svn\merge-cmd.c:222: (apr_err=195002)
  svn: A working copy merge source needs an explicit revision

This comment from merge-cmd.c sums up why not:

  /* Catch 'svn merge wc_path1 wc_path2 [target]' without explicit
     revisions--since it ignores local modifications it may not do what
     the user expects. Forcing the user to specify a repository
     revision should avoid any confusion. */

So we should probably go with something like this:

     The source of a cherry pick merge can also be a working copy path, in
     which case the corresponding URL of the path is used.

> TARGET_WCPATH is a working copy of the branch the changes will
> be applied to.
>
> '-r N:M' specifies a revision range to be merged. The difference
> between SOURCE_at_REV as it existed at revision N, and SOURCE_at_REV at
> it existed at revision M, is merged into TARGET_WCPATH.
> If no revision range is specified, the default range of 0:REV is used.
>
> If mergeinfo within TARGET_WCPATH indicates that revisions within the
> range were already merged, changes made in those revisions are not
> merged again. If needed, the range is broken into multiple sub-ranges,
> and each sub-range is merged separately.
>
> If N is greater than M, the range is a "reverse range". Such a range
> can be used to undo changes made to SOURCE between revisions N and M.
>
> '-c M' is equivalent to the range '-r <M-1>:M'.
> '-c -M' does the reverse: '-r M:<M-1>'.
>
> Multiple '-c' and/or '-r' options may be specified, and mixing of
                                                        ^
That comma seems unnecessary (and yes, I probably put it there :-)

> forward and reverse ranges is allowed.
>
>
> - Sync Merge Example -
>
> A feature is being developed on a branch called "feature".
> The feature branch is regularly synced with trunk to keep up with
> changes made there.
>
> feature +------------------------o-----
> / ^
> / /
> / .............../
> trunk ------+------------L--------------R------
> r100 r200
>
> In the above diagram, L marks the "left" side of the merge (trunk_at_100),
> and R marks the "right" side of the merge (trunk_at_200).
> The difference between the left and right side is merged into the target.
>
> To perform the merge, check out a working copy of the feature branch
> and run the following command in the top-level directory of the working
> copy:
>
> svn merge ^/trunk
>
> The default revision range is -r0:HEAD, so any unmerged changes will
> be merged. To merge only a specific range of revisions, specify a
> revision range:
>
> svn merge -r100:200 ^/trunk

I'd remove the preceding section starting at "To merge only a specific
range", because in my book "svn merge -r100:200 ^/trunk" *is* a cherry
pick (i.e. cherry picking doesn't imply one cherry, it might be 200
cherries!).

> - Cherry-picking Merge Example -
>
> A bug has been fixed on trunk on revision 50. This fix needs to
> be released in the next release of the line of 1.x releases.
> The fix needs to be merged from the trunk into the release branch.

The line "This fix needs to be released in the next release of the
line of 1.x releases." seems superfluous, I think just this conveys
what we need here:

     A bug has been fixed on trunk on revision 50. This fix needs to be
     merged from the trunk into the release branch.

> 1.x-release +-----------------------o-----
> / ^
> / |
> / |
> trunk ------+--------------------------LR-----
> r50
>
> In the above diagram, L marks the left side of the merge (trunk_at_49)
> and R marks the right side of the merge (trunk_at_50).
> The difference between the left and right side is merged into the target.
>
> To perform the merge, check out a working copy of the feature branch
> and run the following command in the top-level directory of the working
> copy:
>
> svn merge -c50 ^/trunk
>
> If several commits to trunk were related to the fix, multiple revisions
> to can be merged:
>
> svn merge -c50,54,60 ^/trunk
>
>
> 2. The second form is called a "reintegrate merge":
> svn merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]
>
> SOURCE is the URL of a branch to be merged back into (usually) its
> immediate ancestor branch. If REV is specified, it is used as the peg
> revision for SOURCE, i.e. SOURCE is looked up in the repository at
> revision REV. If REV is not specified, the HEAD revision is assumed.
>
> TARGET_WCPATH is a working copy of the branch the changes will
> be applied to.
>
> The source can also be specified as working copy path, in which case
> the URL of the merge source is derived from the working copy.

Actually the reintegrate source can't be a WC path; you'll get the
same 'svn: A working copy merge source needs an explicit revision' I
mentioned above. But unlike the previous case you can't get by this
by specifying a revision range, since --reintegrate doesn't support
that:

>svn merge feature trunk --reintegrate -r0:HEAD
  ..\..\..\subversion\svn\main.c:2357: (apr_err=205000)
  svn: Try 'svn help' for more info
  ..\..\..\subversion\svn\merge-cmd.c:64: (apr_err=205000)
  svn: -r and -c can't be used with --reintegrate

> - Reintegrate Merge Example -
>
> A feature has been developed on a branch called "feature".

If we add some language like this, "The feature branch started as a
copy of trunk_at_W", it will make explaining one of the reintegrate
requirements below a lot easier.

> Work on the feature has completed and it should be merged back
> into the trunk.
>
> The feature branch was last synced with its immediate ancestor,
> the trunk, in revision X. So the difference between trunk_at_X and
> feature_at_HEAD contains the complete set of changes related to the feature,

I know it is somewhat redundant, but I would say "the feature branch"
rather than "the feature" above.

> and no other changes. This diff is applied to the trunk.
>
> feature +-------------------------------R
> / . \
> / .............. \
> / . v
> trunk ------+--------------------L------------------o
> rW rX
                      ^^
                   Add this

> In the diagram above, L marks the left side of the merge (trunk_at_X),
> and R marks the right side of the merge is (feature_at_HEAD).
                                              ^^
                                           Remove "is"

> The difference between the left and right side is merged into the target.
>
> To perform the merge, check out a working copy of the trunk, and run
> the following command in the top-level directory of the working copy:
>
> svn merge --reintegrate ^/feature
>
> To prevent unnecessary merge conflicts, the reintegrate merge requires
> that TARGET_WCPATH is not a mixed-revision working copy, and has no
> local modifications, and has no switched subtrees.

A bit cleaner?

     To prevent unnecessary merge conflicts, reintegrate merges require
     that TARGET_WCPATH is not a mixed-revision working copy, has no
     local modifications, and has no switched subtrees.

> It also requires
> that all changes which were merged into the reintegrate source have
> also been merged into the target.

This last requirement is tough to explain both briefly and in a way
that will be properly understood by the majority of users. How does
this sound?

     Reintegrate merges also require that the reintegrate source be fully
     synced with the target since their common branch point. In the above
     example this means that all of the changes made on trunk between
     revision W and revision X are fully merged to the feature branch before
     it can be reintegrated back to trunk.

> After the reintegrate merge, the feature branch cannot be synced to
> the trunk again without merge conflicts. If further work must be done
> on the feature branch, it should be deleted and then re-created.

Do we want to raise the other option of using a record-only merge to
work around this limitation? Or do we save that for --really-verbose
;-P ?

> 3. The third form is called a "2-URL merge":
> svn merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]
>
> Two source URLs are specified, together with two revisions N and M.
> The two sources to be compared at the specified revisions, and the
> difference is applied to TARGET_WCPATH, which is a path to a working
> copy of another branch.
>
> The revisions default to HEAD if omitted.
>
> If TARGET_WCPATH is omitted, a default value of '.' is assumed, unless
> the sources have identical basenames that match a file within '.';
> In which case, the differences will be applied to that file.
>
> The sources can also be specified as working copy paths, in which case
> the URLs of the merge sources are derived from the working copies.
>
> This is the most flexible type of merge, but also the most difficult
> to use. It can be used to merge the differences between two (possibly
> ancestrally unrelated) branches into a working copy of another branch.
> This type of merge should be used very carefully because the probability
> of merge conflicts is quite high. If possible, avoid doing 2-URL merges.

Maybe replace this "If possible, avoid doing 2-URL merges" with "In
most use cases, a sync, cherry-pick, or reintegrate merge is
sufficient and reduces the chances of mistakes"?

>
> - 2-URL Merge Example -
>
> A feature has been developed on a branch called "feature".
> Development for the upcoming 3.0 release has happened in parallel on
> the "3.x-release" branch. There is huge demand for having the feature
> in the upcoming 3.0 release, so it has been decided to merge it into the
> 3.x-release branch.

"There is huge demand for having the feature in the upcoming 3.0
release, so it has been decided to merge it into the 3.x-release
branch." --> "The work on the feature branch must be merged to the
3.x-release branch"

> However, the feature branch and the 3.x-release
> branch are not directly related, so a 2-URL merge is needed.
> The feature branch was last synced with its immediate ancestor,
> the trunk, in revision 500.

Are you saying the sync *done* in r500 or was the sync *up to* r500
from trunk, but done in some subsequent revision? I assume you mean
the latter, in which case you'll need to tweak your diagram:

                   3.x-release +-----------------------------------o
                               / ^
                              / /
                             / /
         trunk ------+------+-----------_at_r500-L---------> /
                      \ \ . /
                       \ \ . /
                        \ \ ......... /
                         \ \ . /
                 feature +---------------------o-----------R
                                              r501???

> So the difference between trunk_at_500 and
> feature_at_HEAD contains the complete set of changes related to the feature,
> and no other changes. This diff is applied to the 3.x-release branch.
>
> 3.x-release +-----------------------------------o
> / ^
> / /
> / /
> trunk ------+------+------------------L----- /
> \ . /
> \ ........... /
> \ . /
> feature +---------------------o-------------R
> r500
>
> In the diagram above, L marks the left side of the merge (trunk_at_500),
> and R marks the right side of the merge is (feature_at_HEAD).
> The difference between the left and right side is merged into the target.
>
> To perform the merge, check out a working copy of the 3.x-release
> branch and run the following command in the top-level directory
> of the working copy:
>
> svn merge ^/trunk_at_500 ^/feature
>
> Before performing a 2-UL merge, it is a good idea to preview the changes
> which will be merged. This can be done with the svn diff command:
>
> svn diff ^/trunk_at_500 ^/feature_at_HEAD

Do we want to say that the above example in no-way guarantees a clean merge?

> The following applies to all types of merges:
>
> For each merged item a line will be printed with characters reporting
> the action taken. These characters have the following meaning:
>
> A Added
> D Deleted
> U Updated
> C Conflict
> G Merged
> E Existed
> R Replaced
>
> Characters in the first column report about the item itself.
> Characters in the second column report about properties of the item.
> A 'C' in the third column indicates a tree conflict, while a 'C' in
> the first and second columns indicate textual conflicts in files
> and in property values, respectively.
>
> NOTE: Subversion will only record metadata to track the merge (mergeinfo)
> if the two sources are on the same line of history -- if the first source
> is an ancestor of the second, or vice-versa. This is guaranteed to be the
> case when using sync merges and reintegrate merges.
> The --ignore-ancestry option overrides this, forcing Subversion to regard
> the sources as unrelated and not to track the merge.

Reworked this a bit to convey the idea that mergeinfo is used two
important ways: To consider what to merge and then to describe what
just got merged.

  NOTE: Subversion uses the svn:mergeinfo property to track merge history.
  This property is considered at the start of a merge to determine what to
  merge and it is updated at the conclusion of the merge to describe the merge
  that took place. Mergeinfo is used only if the two sources are on the same
  line of history -- if the first source is an ancestor of the second, or
  vice-versa. This is guaranteed to be the case when using sync merges and
  reintegrate merges. The --ignore-ancestry option prevents merge tracking
  and thus ignores mergeinfo, neither considering it nor recording it.

Paul
Received on 2010-11-01 17:16:09 CET

This is an archived mail posted to the Subversion Dev mailing list.