(Warning, long chat about cvs, branching and merging will follow)
> With two trees you can still see that they are 'one'
source tree because
> you can do
> cd xemacs-21.2; cvs tag start_myfix INSTALL; <edit INSTALL>
> cvs commit -m "Corrected configure instructions" INSTALL
> cd ../xemacs-22.0; cvs -q update -jstart_myfix -jrelease-21-2 INSTALL
> cvs commit -m "merged fixes from 21.2 branch to 22.0 branch"
> instead of re-implementing the changes in the second branch.
Cute. I've never been brave[1] enough to try out stuff like that. Will
it still work after a lot of changes have been committed? ie. after
divergence has set in?
It will work, unless the changes are conflicting (think 'changes to the
same lines or very near them'). It will fail if you do major things
like e.g. sort all the functions in one branch, do modifications, then
do modifications in the other branch, *then* merge. However, if you
don't mess up too badly then merging branches will work much better than
you would imagine. It also helps a lot if people can stay away from
things like e.g. 'fixing' up the indentation to their liking whenever
they touch a file.
I manage a 100MB source tree with many branches with up to 15 active
developers, and occasionally I merge *whole* branches this way. This works
fine most of the time (of course you'll always have to look through the
changes too, because 1) cvs can't handle logical changes in one branch which
make other changes in another branch invalid, and 2) cvs will occasionally
do the merging incorrectly, although this is usually because somebody
"bypassed" cvs and applied the same change to two branches). There's
always
some amount of conflict fixes, but usually that's easy to resolve IF the
ChangeLog file is used *always*! (I read through nine months of postings
from the mail archive during Christmas and I noticed that discussion about
"to ChangeLog or not to ChangeLog trivial fixes". I used to agree with those
who argued that it shouldn't be necessary to add a ChangeLog entry to
spellfixes or other simple things (having commit logs and all), however
after working with CVS and branch-merging full-time for a long time now
I have completely changed my mind. To have some kind of ChangeLog entry
which at least indicates what was changed and maybe why, is *essential*
to a successful merge between branches. It makes all the difference.)
I'm going through some real hard merges quite often because I try to keep
two repositories in synch (I have to because a 9600 bps GSM phone on
international rates is not what you want for a net-accessed repository :-)
I'm also doing a lot of merges in another tree with three branches, with
only one repository (this is what you want :-), and it's a breeze. It goes
very smoothly. Of course it helps to plan for it, and do the merges before
things diverge too much. You must also not be afraid of adding tags whenever
it's a possibility it could come in handly later. A good naming convention
for tags will help a lot (I encourage people here to add 'private' tags
whenever they feel for it, and create their own little branches to work
out things instead of working off-line with their new stuff (in this way
we only have to do the daily backups on the repository only and not all the
home directories, and people can version control their work-in-progress
without having to resort to e.g. local sccs or rcs. I only tell them to
prefix their "private" tags and branches with their initials. We use
other conventions for "public" tags).
Hmmm. The man page says a date may be used instead of tag. That
sounds cleaner if it works.
I recommend against it. First, I'm never getting the versions I expect
when I use dates (I'm never guessing right about which midnight exactly
a date refers to, and if it will include or start after the date I gave it),
and secondly, if you merge several files (or the whole tree) then you can
easily end up with pieces here and there left out ('holes') when you do
your next merge. The only way to get things right is to use tags, and
then continue from the previous tag (but see below) when you do the next
merge -- unless you want to pick out something very specific and merge only
that. In that case you should tag it specifically:
cvs tag ta_thread_support_start; <do some work>
cvs commit; cvs tag ta_thread_support_end; <move over to other branch>
cvs update -jta_thread_support_start -jta_thread_support_end
cvs commit -m"Merged thread support (maybe mentioning the tags) from
the other branch"
BTW, here's a painless way to do tagging, branching and merges (with my own
naming convention, the important thing is just to have a convention):
cvs checkout -r release-21-0 xemacs
cd xemacs
cvs tag release-21-2_bp
cvs tag -b -r release-21-2_bp release-21-2
'bp' means branchpoint, you should always tag the root of the branch.
Now we have a branch, and we know the root of it. The tip of the branch
is of course the branch tag itself.
cvs tag -rrelease-21-2_bp v21-0_last_to_v20
cvs tag -rrelease-21-2_bp v21-0_last_to_v21-2
cvs tag -rrelease-21-2_bp v21-2_last_to_v21-0
.. add more as needed. The tags with 'last_to' are *movable tags*. They come
in convenient later. You don't really have to add them until after the
first merge, but doing it right away means that you can *always* use the
exact same commands for the merges later. The 'v' in 'v21' is just
because
cvs tags have to start with a letter. And using 'release' just makes for
very long tag names.. I usually shorten them a bit for this, keeping just
enough to make sure that I can identify the last_to tags.
Now I'm going to merge the last bug-fixes of 21-0 to 21-2 (this way of
working works best if you are doing all the development on the 21-2 branch,
and only bugfixes and the occasional improvements on 21-0. Then you just
merge those fixes/improvements to the development (21-2) branch afterwards.)
cd xemacs-21.2
cvs -q update (to make sure that I'm up to date)
cvs tag -r release-21-0 ta_gonna_merge_now
I'm adding a help tag because I want to make sure that it doesn't matter
if somebody else is working on the 21-0 branch while I'm doing my merging.
However, I *have* to coordinate with the others so that nobody else is
trying to merge the whole three at the same time -- although you will
usually want to have a particular person (and possibly a backup person)
to be responsible for managing the 'last_to' tags and the public branch
merges.
Ok here's the merge:
cvs -q update -j v21-0_last_to_v21-2 -j ta_gonna_merge_now
(I could have used just -j release-21-0 instead of ta_gonna_merge_now,
but if somebody checks in something there before I get to move the
v21-0_last_to_v22-0 tag then I will move it to the wrong place. This way
instead is bullet proof.)
Now I fix the conflicts:
xemacs `cvs -q -n update | grep 'C ' | cut -d" " -f1`
Check what's updated by the merge, and look at it:
cvs -q -n update
cvs -q diff -u | more
Commit the changes (nothing has happened to the repository until this:)
cvs -q commit -m"Merged release-21-0 to release-21-2 990104"
Move the movable tag:
cvs -q tag -F -r ta_gonna_merge_now v21-0_last_to_v21-2
(-F moves the tag)
Delete the temporary tag. It's better to have many tags than too few,
so maybe add the first optional line:
cvs -q tag -r ta_gonna_merge_now v21-0_to_21-2_990104
cvs -q tag -d ta_gonna_merge_now (-d deletes the tag)
The good thing about this scheme is that you can do the merges the same
way every time, this makes it *much* less complicated. Here are all the
commands collected:
cd <to the tree I want to merge *to*, in this case 21-2)
cvs -q update
cvs tag -r release-21-0 ta_gonna_merge_now
cvs -q update -j v21-0_last_to_v21-2 -j ta_gonna_merge_now
xemacs `cvs -q -n update | grep 'C ' | cut -d" " -f1`
cvs -q -n update
cvs -q diff -u | more
cvs -q commit -m"Merged release-21-0 to release-21-2 990104" (fix the date)
cvs -q tag -F -r ta_gonna_merge_now v21-0_last_to_v21-2
*cvs -q tag -r ta_gonna_merge_now v21-0_to_21-2_990104 (fix the date)
cvs -q tag -d ta_gonna_merge_now
(* - optional)
You could in fact create some scripts to do the routine part. Without
movable tags it's much more of a mess, and too easy to forget some important
step so that you don't know what's merged and what's not merged. Even I
have to look things up every time I merge even though it's my job. You
get more confident when you use the same well-proven procedure whenever
possible. The above scheme is so simple that I can almost skip my notes :-)
(moving tags around are of course considered a big no-no in configuration
management, but for this very particular use they're *good* for CM).
From what I can see there are no tags for the root of the branches in
the xemacs tree, but this is no diaster. And the last_to tags can be
created at any time of course, it's just to define some point from where
you want to start doing merges instead of manual synching.
Note that the above method works equally fine when you just want to merge a
single subdirectory or even just a single file, this is actually how I work
most of the time (you should however make sure that the last_to tags are in
place for the *whole* tree before you begin, even if you plan to do merges
for just a subdirectory for some time). It's also nice to do merges on small
parts just to get the feel for it (in particular when you work with a 'live'
tree and not just some experimental test repository :-)
It should be mentioned again that it helps a lot to have some plan for
what kind of work should be done to which branch.
> For people with only read access (e.g. like me) the fact that the
two
> versions exist in the same source tree at the repository is of no big
> importance (except for the fact that it's good to know :-)
> (jumping in with too many cvs comments maybe.. it's a habit I guess, I'm
> responsible for the cvs stuff where I work)
Please keep it up. It's a pity you weren't around in December of
1996 when things were first being set up.
I was around, and I commented on a few CVS things back then, but the
process wasn't too public (or I didn't really have anything useful to say)
and in any case I have got most of my experience with branch handling these
last eighteen months.
I had to unsubscribe from the list last year because I was on a *very*
low-bandwidth connection (I spent one year in Italy with a GSM phone and
a laptop), and I wasn't able to keep up with my mailbox. The xemacs list
was very active so I kept only the announce list (and I couldn't continue
my SGI beta testing either of course).
Footnotes:
[1] And I'm less brave now after 4 successive 1.10 releases that
don't pass regression tests ... :-(
The good thing is that you *have* regression tests, it would be worse
if you didn't :-)
- Tor