CVS allows you to isolate changes onto a separate line of
development, known as a branch. When you change files on a branch, those
changes do not appear on the main trunk or other branches.
Later you can move changes from one branch to main trunk (or from main
trunk to the branch) by merging. Merging involves first running cvs
update -j, to merge the changes into the working directory. You can then
commit that revision, and thus effectively copy the changes
onto another branch.
When to create a new branch
For NetBeans/Forte I see two possible reasons for creating a new branch:
Official branch for a new release. Such a branch will be created by
an experienced person who knows what he is doing and therefore it
might be expected that there won't be any problem.
Private branch(es) created by a developer. Such branches are
typically used for unstable code that will be merged into the main
trunk as soon as it will became stable. This document presents
some recommendations that should be followed when someone will create
a private branch.
Do not use any CVS expandable keywords ($Id$, $Log$, etc.), as these
interact poorly with merges. For example, suppose that you have used
$Revision$ in your code. And that you have two versions of the file
with revisions 1.2, 188.8.131.52. Then you might get the following results
from a merge:
If you *really* need to use CVS keywords, please, consult CVS
documentation or (better) ask someone who knows how to do it.
Make a tag (cvs tag) whenever you do anything at all interesting
(esp. before and after any merge); it never hurts and it may save you
later. Remember that tags are global, so choose them descriptively so
they will not conflict. For example unstable_rmi_merged_on_Sep_6
can be used.
It may be useful for example if you perform more sequential merges.
Suppose you have an branch R1fix and you have completed the first step
of your unstable development. You want to merge it into the main trunk
and then continue development in unstable branch. After some time you
will repeat merging, etc.
If you just use the cvs update -j R1fix m.c command again,
CVS will attempt to merge again the changes which you have already
merged, which can have undesirable side effects.
If you tag R1fix branch after every merge into the trunk, it is
possible to use the new tag in merge command and merge only what was
changed since the last merge.
When you make modifications and check them in, change as few lines as
possible (e.g. do not reindent the whole file just for fun), and don't
mix unrelated changes in a single commit; these will make merging go
more smoothly and reduce the chance of error.
Use branches if you need to do some unstable development - it is good
for you because you can store all your versions and CVS server is
probably backed up, it is good for other people because your code
doesn't break builds. But do not use a lot of local unstable branches,
because they may be hard to keep track of. If you need to do some
unstable development for a while and need a branch, then use one.
How to work with branches
create a new branch
cvs tag new_branch_name_root cvs tag -b -r new_branch_name_root new_branch_name
it creates a tag for main trunk (before the merge) and then it
creates a branch based on the current revisions in the working
copy, assigning that branch the name `new_branch_name'.
Example: cvs tag rmi_root cvs tag -b -r rmi_root unstable_rmi
creates a new unstable branch for rmi module to main trunk
cvs tag -r some_existing_branch new_branch_root cvs tag -b -r new_branch_root new_branch_name
-r new_branch_root says that this branch should be rooted at
the revision that corresponds to the tag new_branch_root. It need not be
the most recent revision -- it's often useful to split a branch off
an old revision (for example, when fixing a bug in a past release
otherwise known to be stable).
Example: cvs tag -r boston boston_rmi cvs tag -b -r boston_rmi unstable_rmi_boston
creates a new unstable branch for rmi based on current boston
Note: difference between tag and rtag is that
tag command adds a tag to checked out version of files
whereas rtag uses the most recent versions in the repository.
These can have different effects, e.g. if someone checks in new
stuff while you are working.
access to an existing branch
cvs checkout -r branch_name
Example: cvs checkout -r boston
cvs update [-r branch_name]
the above command switches to the specified branch name - it merges
Note: do not use update -r. It is potentially very
confusing (although it does do exactly what it says, usually you
don't really want to do that). Always check out branches into
separate, clearly labeled directories. For example, ~/src/boston for
boston branch, ~/src/jaga for main trunk, etc. Make a fresh checkout of
the whole repository, with most stuff on the trunk and just your
unstable code on the branch.
merges all changes since specified merge to the main trunk,
tags it and commit to CVS.
Example: cd jaga/rmi cvs tag before_merge_Sep_10 cvs update -j unstable_rmi_merged_on_Sep_6 -j unstable_rmi cvs rtag -r unstable_rmi unstable_rmi_merged_on_Sep_10 cvs commit -m "merged a new feature"cvs tag after_merge_Sep_10
It is also possible to merge main trunk into a branch. This is
conceptually probably harder, but follows the same principles.
Suppose an example that you are working on unstable branch and
someone else has been checked some fixes into the main trunk. You
want to integrate these fixes into your code too but not to
affect the main trunk with your unstable code and later to merge your
unstable code to the main trunk.
## create an unstable branch cvs rtag unstable_root my_module cvs rtag -b -r unstable_root unstable my_module mkdir unstable cd unstable cvs checkout -r unstable my_module
## some work in the branch whereas someone else has fixed trunk
## merge the trunk to the branch cvs rtag main_trunk_fixed my_module cvs tag unstable_before_merging_main_trunk_fixed cvs update -j unstable_root -j main_trunk_fixed
[resolve conflicts and commit] cvs tag unstable_after_merging_main_trunk_fixed
## some work in both main trunk and the branch
## finally, merge the branch to the trunk cd stable cvs checkout my_module cvs tag before_merge_unstable cvs update -j main_trunk_fixed -j unstable
[resolve conflicts and commit] cvs tag after_merge_unstable
Numbers are changes (revisions) made by user. Suppose that every
revision is stored as a diff to previous revision.
M1 is a result of merging the trunk (rev. 4) to the branch.
M2 is a result of merging the branch (rev. 5)to the trunk.
So current status at M1 is root+1+2+3+4, status at 5 is
root+1+2+3+4+5 and status at 7 is root+3+4+6+7.
Finally M2 is created (cvs update -j 4 -j branch) as <status at 7>
+ (<status at 5> - <status at 4>) = root+3+4+6+7 +
(root+1+2+3+4+5 -(root+3+4)) = root+3+4+6+7 + (root+1+2+3+4+5 - root-3-4))
= root+3+4+6+7 + (+1+2+5) = root+1+2+3+4+5+6+7
In practice, hovewer, update -j -j literally takes the two revisions you
asked for, and more or less runs diff3 on them and your working file.
It does not know or care what changes you made where--that is your job.
cvs update always runs a single merge, it does not do anything in steps.
The example above show how one can check whether result of merging would
be what he wants.