Return-Path: Delivered-To: apmail-subversion-users-archive@minotaur.apache.org Received: (qmail 7745 invoked from network); 8 Mar 2011 20:35:42 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 8 Mar 2011 20:35:42 -0000 Received: (qmail 43678 invoked by uid 500); 8 Mar 2011 20:35:41 -0000 Delivered-To: apmail-subversion-users-archive@subversion.apache.org Received: (qmail 43645 invoked by uid 500); 8 Mar 2011 20:35:41 -0000 Mailing-List: contact users-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Delivered-To: mailing list users@subversion.apache.org Received: (qmail 43638 invoked by uid 99); 8 Mar 2011 20:35:41 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 08 Mar 2011 20:35:41 +0000 X-ASF-Spam-Status: No, hits=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: local policy) Received: from [192.109.42.8] (HELO einhorn.in-berlin.de) (192.109.42.8) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 08 Mar 2011 20:35:31 +0000 X-Envelope-From: stsp@stsp.name Received: from jack.stsp.name (jack.stsp.name [217.197.84.35]) (authenticated bits=128) by einhorn.in-berlin.de (8.13.6/8.13.6/Debian-1) with ESMTP id p28KZ697018902 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT); Tue, 8 Mar 2011 21:35:06 +0100 Received: from jack.stsp.name (stsp@localhost [127.0.0.1]) by jack.stsp.name (8.14.3/8.14.3) with ESMTP id p28KZ6k5017172; Tue, 8 Mar 2011 21:35:06 +0100 (CET) Received: (from stsp@localhost) by jack.stsp.name (8.14.3/8.14.3/Submit) id p28KZ6kt026504; Tue, 8 Mar 2011 21:35:06 +0100 (CET) Date: Tue, 8 Mar 2011 21:35:05 +0100 From: Stefan Sperling To: Steve Cohen Cc: "users@subversion.apache.org" Subject: Re: Understanding merging Message-ID: <20110308203505.GB19147@jack.stsp.name> Mail-Followup-To: Steve Cohen , "users@subversion.apache.org" References: <4D7675D6.9040208@javactivity.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <4D7675D6.9040208@javactivity.org> User-Agent: Mutt/1.5.21 (2010-09-15) X-Scanned-By: MIMEDefang_at_IN-Berlin_e.V. on 192.109.42.8 X-Virus-Checked: Checked by ClamAV on apache.org On Tue, Mar 08, 2011 at 12:30:46PM -0600, Steve Cohen wrote: > I work with a very senior colleague who has never always resisted > version control and would much rather do without it, but he is > forced to go along and I am the whipping boy whenever something goes > wrong. > > He poses a general but simple question that I find myself unable to > give a simple answer to. I am rephrasing it slightly but it bothers > me that I don't know the simple answer. If I found myself in this > situation I would tweak until it was as desired, but my persnickety > colleague is not satisfied with such answers and for once, I don't > blame him. > > Given two branches off a trunk that were taken at different times, > if the first is merged back to the trunk and then the second, how > may the second be merged back into the trunk so as not to override > changes from the first merge, assuming that both change sets are > desired to be in the trunk at the end? Nothing will ever be "overridden". The reintegrate merge attempts to apply the delta between the trunk and the branch and to a working copy of the merge target (i.e. the trunk). If conflicting changes exist in the merge target, they will be marked as such. It's up to the person doing the merge to resolve these conflicts. Thus, Subversion isn't making decisions about changes overriding one another. It simply provides users with tooling to carry out their own decisions. I think the other reply you got, which recommends syncing all branches to the trunk as soon as a big merge into the trunk occurred, is good advice. BTW, there is a new help text for "svn merge", which will be released in 1.7. It is also valid for 1.6. Maybe it will help your colleague as a reference (but it doesn't replace study of the merging chapters in the Subversion book at svnbook.org!). I'm quoting it below. ------ 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] 1. The first form is called a "sync", 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 specific revisions from one branch to another. SOURCE is usually a URL. The source of a cherry-picking merge can also be a working copy path, in which case the corresponding URL of the path is used. 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. '-r N:M' specifies a revision range to be merged. The difference between SOURCE@REV as it existed at revision N, and SOURCE@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". A reverse range can be used to undo changes made to SOURCE between revisions N and M. '-c M' is equivalent to the range '-r :M'. '-c -M' does the reverse: '-r M:'. Multiple '-c' and/or '-r' options may be specified and mixing of 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@100), and R marks the "right" side of the merge (trunk@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. - Cherry-picking Merge Example - 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@49) and R marks the right side of the merge (trunk@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 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 a 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. - Reintegrate Merge Example - A feature has been developed on a branch called "feature". The feature branch started as a copy of trunk@W. 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@X and feature@HEAD contains the complete set of changes that implement the feature, and no other changes. These changes are applied to the trunk. feature +-------------------------------R / . \ / .............. \ / . v trunk ------+--------------------L------------------o rW rX In the diagram above, L marks the left side of the merge (trunk@X), and R marks the right side of the merge (feature@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 trunk, and run the following command in the top-level directory of the working copy: svn merge --reintegrate ^/feature 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. 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. 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. 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. 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, up to revision 500. So the difference between trunk@500 and feature@HEAD contains the complete set of changes related to the feature, and no other changes. These changes are applied to the 3.x-release branch. 3.x-release +-----------------------------------o / ^ / / / r500 / trunk ------+------+-----------------L---------> / \ . / \ ........... / \ . / feature +-----------------------------------R In the diagram above, L marks the left side of the merge (trunk@500), and R marks the right side of the merge is (feature@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@500 ^/feature Before performing a 2-UL merge, it is a good idea to preview the changes which will be merged, because there is no guarantee that the merge will be free of conflicts. The preview can be done with the svn diff command: svn diff ^/trunk@500 ^/feature@HEAD 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 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. Valid options: -r [--revision] ARG : ARG (some commands also take ARG1:ARG2 range) A revision argument can be one of: NUMBER revision number '{' DATE '}' revision at start of the date 'HEAD' latest in repository 'BASE' base rev of item's working copy 'COMMITTED' last commit at or before BASE 'PREV' revision just before COMMITTED -c [--change] ARG : the change made by revision ARG (like -r ARG-1:ARG) If ARG is negative this is like -r ARG:ARG-1 -N [--non-recursive] : obsolete; try --depth=files or --depth=immediates --depth ARG : limit operation by depth ARG ('empty', 'files', 'immediates', or 'infinity') -q [--quiet] : print nothing, or only summary information --force : force operation to run --dry-run [--dry] : try operation but make no changes --diff3-cmd ARG : use ARG as merge command --record-only [--ro] : merge only mergeinfo differences -x [--extensions] ARG : Default: '-u'. When Subversion is invoking an external diff program, ARG is simply passed along to the program. But when Subversion is using its default internal diff implementation, or when Subversion is displaying blame annotations, ARG could be any of the following: -u (--unified): Output 3 lines of unified context. -b (--ignore-space-change): Ignore changes in the amount of white space. -w (--ignore-all-space): Ignore all white space. --ignore-eol-style: Ignore changes in EOL style. -p (--show-c-function): Show C function name in diff output. --ignore-ancestry [--ia] : ignore ancestry when calculating merges --accept ARG : specify automatic conflict resolution action ('postpone', 'base', 'mine-conflict', 'theirs-conflict', 'mine-full', 'theirs-full', 'edit', 'launch') --reintegrate [--ri] : merge a branch back into its parent branch --allow-mixed-revisions : Allow merge into mixed-revision working copy. Use of this option is not recommended! Please run 'svn update' instead. Global options: --username ARG : specify a username ARG --password ARG : specify a password ARG --no-auth-cache [--nac] : do not cache authentication tokens --non-interactive : do no interactive prompting --trust-server-cert : accept unknown SSL server certificates without prompting (but only with '--non-interactive') --config-dir [--cd] ARG : read user configuration files from directory ARG --config-option ARG : set user configuration option in the format: FILE:SECTION:OPTION=[VALUE] For example: servers:global:http-library=serf