Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
versioncontrol:svn_merging [2006/09/24 12:46] – NikClaytonversioncontrol:svn_merging [2022/10/07 03:00] (current) – Move bakeoff stuff under a single namespace KubilayKocak
Line 1: Line 1:
 +**NOTE**: This is from the VCS bakeoff.
 +
 +Please see http://www.freebsd.org/doc/en_US.ISO8859-1/articles/committers-guide/subversion-primer.html for how to merge in the %%FreeBSD%% project.
 +
 ====== Merging with Subversion ====== ====== Merging with Subversion ======
  
-**Note:** Nik's actively updating this page.  I'll remove this note when I've finished.+**NOTE**: Subversion 1.5 has //merge tracking// built-in. You no longer need svnmerge. See http://subversion.tigris.org/svn_1.5_releasenotes.html#merge-tracking for more information.
  
 ===== Background ===== ===== Background =====
Line 25: Line 29:
 ==== Repository creation ==== ==== Repository creation ====
  
-First, we need to create a repository and populate it with some files.  This example follows the suggested layout described in ["SVN Repo Layout"].  We create ''%%freebsd/src/trunk/%%'', and a ''%%projects%%'' directory, ready to be populated with two long lived projects.+First, we need to create a repository and populate it with some files.  This example follows the suggested layout described in [[/SVN_Repo_Layout|SVN_Repo_Layout]].  We create ''%%freebsd/src/trunk/%%'', and a ''%%projects%%'' directory, ready to be populated with two long lived projects.
  
 <code> <code>
Line 215: Line 219:
  * `svnmerge unblock` makes revisions blocked with `svnmerge block` available for merge again.  * `svnmerge unblock` makes revisions blocked with `svnmerge block` available for merge again.
  * `svnmerge avail` supports `--diff` and `--log` options (amongst others) that will show the available changes as a diff, or as a list of log messages, instead of the default list of revisions.  This is very handy when you want to check which change a particular rev corresponds to.  * `svnmerge avail` supports `--diff` and `--log` options (amongst others) that will show the available changes as a diff, or as a list of log messages, instead of the default list of revisions.  This is very handy when you want to check which change a particular rev corresponds to.
 + * When you run `svnmerge merge` it collects the log messages of the revisions, and stores them in a file in the current directory.  You can pass this to `svn commit` with the `-F` option to get automatically generated commit messages.  You can, of course, also write your own.
  
 == Project branch merge walkthrough == == Project branch merge walkthrough ==
Line 248: Line 253:
 Transmitting file data . Transmitting file data .
 Committed revision 13.}}} Committed revision 13.}}}
 +
 +So this change to -current was '''r13'''.
 +
 +Switch to the directory that contains the trustedbsd project, make sure it's up to date, and initialise the merge tracking property.
  
 {{{ {{{
 % cd ../../../projects/trustedbsd/trunk/ % cd ../../../projects/trustedbsd/trunk/
 % svn update % svn update
-At revision 13}}}+At revision 13 
 +% svnmerge init 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn commit -m '"svnmerge init" prop changes' 
 +Sending        trunk 
 + 
 +Committed revision 14.}}} 
 + 
 +We can make some local changes to the trustedbsd project, and commit them. 
 + 
 +{{{ 
 +% echo 'tustedbsd development' > bar 
 +% svn commit -m 'Special security changes' 
 +Sending        trunk/bar 
 +Transmitting file data . 
 +Committed revision 15.}}} 
 + 
 +And we can find out which revisions in `src/trunk` are available for merging. 
 + 
 +{{{ 
 +% svnmerge avail 
 +13}}} 
 + 
 +Merging those changes is easy (so far, this is just like doing an MFC to a -stable branch, as described previously). 
 + 
 +{{{ 
 +% svnmerge merge -r 13 
 +U    foo 
 + 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn update 
 +At revision 15. 
 +% svn commit -m 'MFC' 
 +Sending        trunk 
 +Sending        trunk/foo 
 +Transmitting file data . 
 +Committed revision 16.}}} 
 + 
 +=== Merge from project branch back to -current === 
 + 
 +This is more interesting.  Suppose that it's now time to merge changes from the project branch back to the trunk.  The basic theory is the same. 
 + 
 +First, we need to initialise merge tracking.  Previously we did this on the copy destination (`branches/8.x`, and `trustedbsd/trunk`).  This is because these were also the destination of the merges.  Now, however, `src/trunk` is going to be the destination, so that's where we need to initialise the merge tracking info. 
 + 
 +This is slightly longer winded, purely because we need to know when the branch was created.  This is so we can mark all the changes that happened before the branch as already being merged.  Subversion doesn't record quite enough metadata about branches to make this automatic. 
 + 
 +Fortunately, this only needs to be done once per merge-target, and is easy to do. 
 + 
 +To find out when the branch was created run `svn log` on the branch.  Use the `--stop-on-copy` option and the log report will stop at the revision in which the copy happened (instead of crossing over the copy).  If we do that: 
 + 
 +{{{% cd ../../../ 
 +% svn update 
 +At revision 16. 
 +% cd freebsd/src/trunk 
 +% svn log --stop-on-copy ../../../projects/trustedbsd/trunk 
 +------------------------------------------------------------------------ 
 +r16 | nik | 2006-09-22 22:12:24 +0100 (Fri, 22 Sep 2006) | 1 line 
 + 
 +MFC 
 +------------------------------------------------------------------------ 
 +r15 | nik | 2006-09-22 22:11:21 +0100 (Fri, 22 Sep 2006) | 1 line 
 + 
 +Special security changes 
 +------------------------------------------------------------------------ 
 +r14 | nik | 2006-09-22 22:10:44 +0100 (Fri, 22 Sep 2006) | 1 line 
 + 
 +"svnmerge init" prop changes 
 +------------------------------------------------------------------------ 
 +r12 | nik | 2006-09-22 22:09:20 +0100 (Fri, 22 Sep 2006) | 1 line 
 + 
 +Start the trustedbsd project 
 +------------------------------------------------------------------------}}} 
 + 
 +we see that the trustedbsd project was branched from the trunk at r12. 
 + 
 +Now we can run `svnmerge init`.  There are two changes here.  First, we need to include a `-r` option that specifies the revisions that have already been merged.  That's `1-12` in this instance. 
 + 
 +We also need to specify where we're merging changes from.  This is going to the `trustedbsd/trunk` direectory. 
 + 
 +{{{ 
 +% svnmerge init -r 1-12 ../../../projects/trustedbsd/trunk 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn commit -m '"svnmerge init" prop changes' 
 +Sending        trunk 
 + 
 +Committed revision 17.}}} 
 + 
 +Now the merge tracking information is initialised we can find out whether there are any revisions to merge. 
 + 
 +{{{ 
 +% svnmerge avail 
 +14-16}}} 
 + 
 +This doesn't look quite right.  r14 was running `svnmerge init` on the trustedbsd trunk.  r15 was an actual change.  r16 consisted of merging a change from current (r13) on to the branch.  `svnmerge` calls these ''reflected'' revisions, and they can be removed from the list by specifying the `-b` option. 
 + 
 +{{{ 
 +% svnmerge avail -b 
 +15}}} 
 + 
 +As you can see, that's generated the correct output.  r15, which was an actual change on the trustedbsd branch, is the only rev shown.  It can easily be merged back to -current. 
 + 
 +{{{ 
 +% svn merge merge -r 15 
 +U    bar 
 + 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn commit -m 'Merge r15 from trustedbsd project' 
 +Sending        trunk 
 +Sending        trunk/bar 
 +Transmitting file data . 
 +Committed revision 18.}}} 
 + 
 +=== Merging from multiple project branches === 
 + 
 +That's demonstrated how to merge from -current to a project branch, and also from a project branch back to -current.  What happens if you have more than one project branch? 
 + 
 +Start by creating a second project branch, and using `svnmerge init` to initialise merge tracking for that branch. 
 + 
 +{{{ 
 +% cd ../../../ 
 +% svn update 
 +At revision 18. 
 +% svn copy freebsd/src/trunk projects/geom 
 +A         projects/geom/trunk 
 +% svn commit -m 'Create GEOM project' 
 +Adding         projects/geom/trunk 
 + 
 +Committed revision 19. 
 +% cd projects/geom/trunk 
 +% svnmerge init 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn commit -m "svnmerge init" prop changes' 
 +Sending        trunk 
 + 
 +Committed revision 20.}}} 
 + 
 +Now go and make changes in three places -- in the geom project, in the trustedbsd project, and in -current. 
 + 
 +{{{ 
 +% echo 'A geom change' > baz 
 +% svn commit -m 'Change baz to support geom' 
 +Sending        trunk/baz 
 +Transmitting file data . 
 +Committed revision 21. 
 +% cd ../../trustedbsd/trunk 
 +% svn update 
 +At revision 21. 
 +% echo 'A trustedbsd change' > bar 
 +% svn commit -m 'Change bar to support trustedbsd' 
 +Sending        trunk/bar 
 +Transmitting file data . 
 +Committed revision 22. 
 +% cd ../../.. 
 +% svn update 
 +At revision 22. 
 +% cd freebsd/src/ctrKtrunk 
 +% echo 'Exciting changes for foo' > foo 
 +% svn commit -m 'Update foo on -current' 
 +Sending        trunk/foo 
 +Transmitting file data . 
 +Committed revision 23.}}} 
 + 
 +With changes in both projects, lets find out which revisions are available to merge. 
 + 
 +{{{ 
 +% svnmerge avail -b 
 +22}}} 
 + 
 +That doesn't look right.  r22 was a trustedbsd change, but r21, a geom change, isn't listed. 
 + 
 +As you've probably realised, this is because the merge tracking record that says that `projects/geom/trunk` can be merged to `freebsd/src/trunk` has not yet been created. 
 + 
 +Again, we need to use `svn log --stop-on-copy` to find out when the geom project was created.  Then `svnmerge init` can be run, marking all the prior revisions as being merged in. 
 + 
 +{{{ 
 +% svn log --stop-on-copy ../../../projects/geom/trunk 
 +------------------------------------------------------------------------ 
 +r21 | nik | 2006-09-22 22:16:36 +0100 (Fri, 22 Sep 2006) | 1 line 
 + 
 +Change baz to support geom 
 +------------------------------------------------------------------------ 
 +r20 | nik | 2006-09-22 22:16:16 +0100 (Fri, 22 Sep 2006) | 1 line 
 + 
 +"svnmerge init" prop changes 
 +------------------------------------------------------------------------ 
 +r19 | nik | 2006-09-22 22:15:45 +0100 (Fri, 22 Sep 2006) | 1 line 
 + 
 +Create GEOM project 
 +------------------------------------------------------------------------ 
 +% svnmerge init -r 1-19 ../../../projects/geom/trunk 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn update 
 +At revision 23. 
 +% svn commit -m '"svnmerge init" prop ch 
 +Sending        trunk 
 + 
 +Committed revision 24.}}} 
 + 
 +With that done, `svnmerge avail -b` should print something useful. 
 + 
 +{{{ 
 +% svnmerge avail -b 
 +svnmerge: multiple heads found. Explicit head argument (-S/--head) required. 
 +The head values available are: 
 +  file:///usr/home/nik/freebsd-scm/repo/projects/trustedbsd/trunk 
 +  file:///usr/home/nik/freebsd-scm/repo/projects/geom/trunk}}} 
 + 
 +As this error explains, now that we've told `svnmerge` that two branches can be merged on the trunk we need to be more explicit with some commands, and specify which merge source we're talking about.  If we re-run this command, specifying the merge source we're interested in we get the correct answer. 
 + 
 +{{{ 
 +% svnmerge avail -S ../../../projects/trustedbsd/trunk -b 
 +22 
 +% svnmerge avail -S ../../../projects/geom/trunk -b 
 +21}}} 
 + 
 +This restriction applies to merging revisions as well.  We can merge the changes in from the branch, either in one lump, or (as in this case) one by one, but we need to specify the merge source path as well as the revision to `svnmerge merge`. 
 + 
 +{{{ 
 +% svnmerge merge -r 21 
 +svnmerge: multiple heads found. Explicit head argument (-S/--head) required. 
 +The head values available are: 
 +  file:///usr/home/nik/freebsd-scm/repo/projects/trustedbsd/trunk 
 +  file:///usr/home/nik/freebsd-scm/repo/projects/geom/trunk 
 +% svnmerge merge -r 21 -S ../../../projects/geom/trunk 
 +U    baz 
 + 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn commit -m 'Merge r21 from geom' 
 +Sending        trunk 
 +Sending        trunk/baz 
 +Transmitting file data . 
 +Committed revision 25. 
 +% svn update 
 +At revision 25. 
 +% svnmerge merge -r 22 -S ../../../projects/trustedbsd/trunk 
 +U    bar 
 + 
 +property 'svnmerge-integrated' set on '.' 
 + 
 +% svn commit -m 'Merge r22 from trustedbsd' 
 +Sending        trunk 
 +Sending        trunk/bar 
 +Transmitting file data . 
 + 
 +Committed revision 26.}}} 
 + 
 +So that's r25 (which came from geom) and r26 (which came from trustedbsd) committed.  We can now go back to those branches and see that these changes are available to merge back in. 
 + 
 +First, trustedbsd. 
 + 
 +{{{ 
 +% cd ../../../projects/trustedbsd/trunk 
 +% svnmerge avail -b 
 +23-25}}} 
 + 
 +That's correct, and we could merge those back in to this branch if we so choose.  Now for the geom branch. 
 + 
 +{{{ 
 +% cd ../../geom/trunk 
 +% svnmerge avail -b 
 +svnmerge: multiple heads found. Explicit head argument (-S/--head) required. 
 +The head values available are: 
 +  file:///usr/home/nik/freebsd-scm/repo/projects/trustedbsd/trunk 
 +  file:///usr/home/nik/freebsd-scm/repo/freebsd/src/trunk}}} 
 + 
 +That looks odd.  The geom branch isn't merging directly with the trustedbsd branch, so why is it showing up in this list? 
 + 
 +Recall that the geom branch was copied from trunk '''after''' trunk had been configured to accept merges from trustedbsd.  That information has persisted in the geom branch, even though it's no longer relevant. 
 + 
 +Now there's nothing technically wrong with this.  The information might be redundant (if we're not planning on doing merges from trustedbsd to geom), but it just means that we need to add `-S` to some commands.  This is a bit tedious, so we can fix this. 
 + 
 +Recall that this information is recorded in properties.  We can use Subversion's commands to inspect the properties, and edit them. 
 + 
 +First, we can find out the properties that are set here. 
 + 
 +{{{ 
 +% svn proplist 
 +Properties on '.': 
 +  svnmerge-integrated}}} 
 + 
 +Now we can find out the value of the `svnmerge-integrated` property. 
 + 
 +{{{ 
 +% svn propget svnmerge-integrated 
 +/freebsd/src/trunk:1-18 /projects/trustedbsd/trunk:1-12,15}}} 
 + 
 +That shows that r1-18 from `src/trunk` are integrated, as are r1-12 and r15 from trustedbsd.  By removing the trustedbsd entry we effectively undo the `svnmerge init` that was inadvertently copied. 
 + 
 +{{{ 
 +% svn propset svnmerge-integrated /freebsd/src/trunk:1-18 . 
 +property 'svnmerge-integrated' set on '.' 
 +% svn commit -m 'Remove bogus record of integration with trustedbsd branch' 
 +Sending      trunk 
 + 
 +Committed revision 27}}} 
 + 
 +And now `svnmerge avail` prints the correct list of revisions, without prompting for the `-S` parameter. 
 + 
 +{{{ 
 +% svnmerge avail -b 
 +23,26}}} 
 + 
 +Those revisions can be merged using `svnmerge merge`. 
 + 
 +== Conclusion == 
 + 
 +This has hopefully shown how Subversion, plus svnmerge, can be used to support all the project's merge needs. 
 + 
 + * Merge from -current to -stable. 
 + * Merge from -stable to an errata branch (which is just a special case of the above) 
 + * Merge from -current to 1..n project branches 
 + * Merge from 1..n project branches back to -current 
 + 
 +Remember, since Subversion doesn't make any distinction between branches and HEAD, with everything being just a directory, it's entirely possible to set up more complicated merge tracking scenarios if necessary.  For example, you could have a project branch that merged to another project branch, which then merged to `src/trunk`.  Or, with per-developer directories in the repo, a ports committer could keep their ports in their `user/` directory, make changes there, and, when ready, easily merge the changes back in to the correct `freebsd/ports/...` directory.
  
 </code> </code>
  
  • versioncontrol/svn_merging.1159102010.txt.gz
  • Last modified: 2006/09/24 12:46
  • by NikClayton