When working with Mozilla, you tend to accumulate patches which need to be reviewed, super-reviewed, and/or approved before they can be committed to the trunk. When you have only a few uncommitted patches, you can get by using cvs diff, and just editing the output to remove other patches before submitting. However, this approach quickly becomes unscalable, especially when you have different fixes in the same tree. Using a distributed versioning system like SVK takes out much of the hassle of managing your patches.
One option is to simply use your own local CVS or Subversion. However, you will likely find that it gets tiresome to merge changes to the live tree back on to patches (without a star-merge command, for example), and performance is probably an issue for trees the size of Mozilla (when it is just for you, commands need to be fast, as waiting for minutes just to manipulate basic patches gets frustrating very quickly).
Another option is GNU Arch. However, this tool also seems to suffer from severe performance issues on trees the size of Mozilla, as most operations seem to require working with tars of the source (which can take minutes to complete). Bazaar may be another option, but it is also known to suffer from performance problems.
Some people have reported success with Monotone. See Using Monotone With Mozilla CVS.
I personally have been using SVK, and it has proved fast but convenient.
Since we don't want to version control CVS or .mozconfig / .mozconfig.mk files, you need to add them to your global-ignores directive, in /etc/subversion/config or your per-user Subversion (often ~/.subversion/config) configuration file. A line like
global-ignores = *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store CVS .mozconf*
should do it.
Now lets set up our working area...
svk mkdir -m "Make project root" //mozilla svk mkdir -m "Somewhere for branches to go" //mozilla/branches svk mkdir -m "Somewhere for temporary branches to go" //mozilla/temp_branches
Note that if you have never used svk before, the first command will prompt you to create your local depot for storage (just say yes).
The next thing to do is get an initial clean Mozilla tree. Follow the normal checkout instructions for this. Put as many trees as you want in MOZ_CO_PROJECT, based on what you are likely to need.
Do the checkout, and change into the newly checked out directory. Now issue:
svk import -m "Import Mozilla from CVS" -t //mozilla/vendor
From now on, whenever you update, you should put your changes into //mozilla/vendor . In order for things to work nicely, do not commit anything to //mozilla/vendor except when it has come through CVS.
The next thing to do is to create your //mozilla/trunk, as a copy of the vendor. Your trunk will be your working area, into which you will merge all your working patches while you wait for them to get committed to CVS (in other words, your greatest-and-latest version of Mozilla).
To make this, issue:
svk cp //mozilla/vendor //mozilla/trunk
Because you used svk import -t, the original checkout directory is suitable for use as a working directory. If you are short on disk space, or like to keep everything together, it is quite possible to use this one directory for everything, and never check out another directory, just by using the svk switch command.
However, if you do this:
If you do decide to check out, use:
svk co //mozilla/trunk mozilla
and then use svk sw when you want to change onto a branch.
It may be important to your patch to stay up to date with the Mozilla tree (when the Tinderboxen are green, of course). To update your vendor tree, use a script like the following...
#!/usr/bin/perl system "svk sw //mozilla/vendor"; open STATUS,'svk status|'; while (<STATUS>) { print "Error: Tree unclean: " . $_; while (<STATUS>) { print " ... " . $_; } die "Exiting due to unclean tree.\n"; } close STATUS; system "cvs up client.mk"; system "make -f client.mk checkout"; open STATUS,'svk status|'; while (<STATUS>) { if (/\? (.*)[\r\n]+/) { print "svk add " . $1 . "\n"; system "svk add " . $1; } elsif (/\! (.*)[\r\n]+/) { # Delete pruned directories... $name = $1; @parts = split(/\//, $name); $subname = shift(@parts); if (! -e $subname) { print "svk remove $subname\n"; system "svk remove $subname"; } foreach $part(@parts) { $subname = $subname . "/" . $part; if (! -e $subname) { print "svk remove $subname\n"; system "svk remove $subname"; last; } } } }
To merge vendor changes into the trunk (after completing the above vendor update), use the command
svk smerge //mozilla/vendor //mozilla/trunk
Always make sure you get vendor on the left and trunk on the right, because you don't want to merge trunk changes into the vendor tree!
If you get a conflict, I would recommend that you abort, revert the conflicting patches on trunk, re-try the merge, and if necessary, make a new patch from the new trunk and merge any salvageable commits on the bad patch into it.
When starting work on a new patch, copy the trunk, and switch onto the branch, like this...
svk cp -m "Branch for Bug 12345: Support Foo Bar" //mozilla/trunk //mozilla/branches/bug12345 svk sw //mozilla/branches/bug12345
Now you can edit the tree as you want, and commit to save when finished.
If you want to merge changes on the trunk (including vendor changes which have been merged into the trunk. Never skip from vendor => branch, always go through trunk or your life will get difficult), use:
svk sm //mozilla/trunk //mozilla/branches/bug12345
You can merge committed changes from the branches back on to the trunk using:
svk cm //mozilla/branches/bug12345 //mozilla/trunk
Use the svk sw //mozilla/branches/bug54321 to switch to a different branch.
There are lots of different patches you can make, but for Bugzilla purposes, you generally want a cumulative one against vendor. To do this, you create a scratch branch (don't worry, these operations are fast, since copies are cheap in SVK).
svk cp -m "Create scratch branch" //mozilla/vendor //mozilla/temp_branches/bug12345_patch1
Next, do a svk log to see what changes you committed to the branch (only counting changes on the branch, not merges). Pick the changes you want, and merge them into the scratch branch as follows:
svk merge -m "Branch to scratch branch" -c revisionno //mozilla/branches/bug12345 //mozilla/temp_branches/bug12345_patch1
Repeat until all desired revisions are added. Note you can also use the form -r firstrevision:lastrevision instead of -c
Finally, do a
svk diff //mozilla/vendor //mozilla/temp_branches/bug12345_patch1
You might also want to remove the temp branch so you don't get confused (it doesn't save disk-space because the revision history is still kept, it doesn't use much either, but it makes it much cleaner if you want to list your temp branches).
For now, I would suggest just repeating the same structure but in a different directory, because I haven't found a way for SVK to know the relationship between the files. This will still allow you to do merges between different CVS branches.