This FAQ is an attempt to gather together the common wisdom for
how developers (both internal and external to Digital Creations)
work with the Zope sources in CVS.
I know nothing about CVS. How do I start?
A good place to start would be the
Introduction to CVS .
There is also an online verion of
Open Source Development with CVS
that provides good background information.
Another handy thing for CVS users is the
CVS Quick Reference .
For doing CVS over SSH, see TargetedWritePublicCvsUsage.
How do I check out Zope?
To check out a copy of the Zope sources (the main trunk), use:
cvs co Zope2
The above works if the repository is local. To check out Zope
remotely, use:
cvs co :ext:amos@korak.digicool.com:/cvs-repository Zope2
But see TargetedWritePublicCvsUsage for instructions on using SSH
as the remote shell for the :ext: remote CVS access. klm 6/16/00
What do you mean by "the trunk"?
The trunk is the main line of development in CVS from which major
Zope releases are made. It is very important that the trunk remain
stable so that releases can be made on short notice. To keep the
trunk from becoming unstable, all work is done on branches in CVS
and when the work has stabilized it can be merged into the trunk.
For more information on this see the
Zope release policy document, which talks more about how our
releases are made and why it is important for the trunk to remain
stable.
So does that mean I shouldn't check things directly into the trunk?
Right - we are using the "activity branch" model for coordinating
work on the Zope core. This means that you make a new branch to
work on a given "activity" (like add a set of features or fixing
bugs). When the work is complete, tested and stable the changes
in that activity branch are merged into the trunk (and possibly
into another branch from which third-dot bug fix releases are
made).
More information on the activity branch pattern (as well as a
lot of good info on configuration management in general) is
available at Streamed Lines.
Ok, so when am I supposed to make a branch?
Any discrete activity that will result in code changes should
have its own branch. For example, "adding FTP and DAV support
to SQLMethods" is a feature-adding activity and a branch should
be made for it. "Fixing bugs in MailHost" is an example of a
bug-fixing activity that should be done on a branch. Even "fixing
collector issue #2020" can be an activity that is on a branch.
What? Make a branch for a single bug fix? Are you licking toads?
It may seem like overkill, especially if you are new to using
branches to coordinate a large amount of activity in a codebase,
but you find in practice that this will actually make your life
easier, not harder. Why? Suppose there is this bug that you want
to fix. You cannot just check out the trunk, commit the fix and
forget it. The reason you can't is that there is usually another
branch besides the trunk that incremental bug-fix releases are being
made from, and that branch needs to get the bug fix too.
Technically you could check out a sandbox on the current major-release
branch and commit the fix on that branch by hand just like you did
for the trunk. In practice it is very easy to make mistakes doing
it this way. Once you get the hang of working on branches and merging
your work into other branches you will find that it is much faster
and much less error-prone to make even small changes by doing them in
an activity branch.
Can I work on both bug-fixes and features in the same activity
branch?
It is almost always best to seperate bug-fix and new feature work
into separate branches. The reason is that new features (once they
are tested and stable) should be merged into the trunk only. Bug
fixes need to be merged into both the trunk and the current release
branch (so that subsequent incremental bug-fix releases will include
them). While it is not impossible to do selective (file-by-file)
merging to make sure that bugs and features get merged into the right
places, it is much easier to just use separate branches.
How do I find out what the current release branch is?
A new "release branch" is created when a new-feature release of
Zope goes into its first beta. The name of the release branch
created is based on major and minor version numbers of the release.
For example, when Zope 2.2 goes into beta a branch named
Zope-2_2-branch
is created and subsequent releases in the 2.2 line
are created from the Zope-2_2-branch
branch. You can usually do a
cvs log
on a file in your sandbox and see the highest Zope-x_x-branch
tag listed to figure out the current release branch. If you are not
sure, ask someone!
So how do I make a branch for my work?
To create a sandbox on an activity branch, first check out a normal
(trunk) sandbox and cd into it. Next, we will tell CVS that we want
to create a branch rooted at the version of the trunk we've just
checked out. To do that, use:
cvs tag -b my_project-branch
This will create the branch in CVS called my_project-branch
. Note
that the previous command will not automatically update the current
sandbox to be on that branch. To do that, use:
cvs update -r my_project-branch
That will put your current sandbox on that branch.
How should I name branches I create?
The convention that we want to use is that your name, a
descriptive element and the suffix -branch
be used in branch names.
Ending branch names with -branch
makes it easier to tell which CVS
tags are branch tags, and using your name or login id as part of your
branch tag names will help avoid name collisions. Some examples of
good branch names:
brian-dav_level2_support-branch
amos-new_help_system-branch
jim-zclass_armegeddon-branch
How do I check out a sandbox on an existing branch?
You can use the -r
argument to CVS to check out a new sandbox
on a given (pre-existing) branch. For example, this will check
out a sandbox on the brian-dav_level2_support-branch
branch into
the directory dav_work
:
cvs co -d dav_work -r brian-dav_level2_support-branch Zope2
How do I do my work on the branch?
You work in your branch in the same way you would work in any
CVS sandbox. You make your changes and use cvs commit
to
commit your changes. When you commit
on a branch, the changes
are only committed to that branch. The changes won't be visible
in the trunk or in other branches until you explicitly merge
the changes from your branch into them.
When should I merge changes I've made on a branch?
When the changes you have made are stable and tested, you are
ready to merge them to the appropriate places. Exactly where you
should merge them will depend on the nature of the activity. If
you were working on bug fixes, you will need to merge your work
into the current release branch and the trunk. If you were
working on new features you probably only need to merge into the
trunk.
Before merging anything substantial into the trunk or another
branch, make sure that you contact the person responsible for the
area you are merging into. This is very important. CVS gives us a
set of tools for coordinating things on a bit level, but communication
is key to making sure that things are coordinated in a sane way.
Bad things will happen if you don't let people know what you are
doing. If a branch owner has spent two hours reconciling the branch
with other things and you start merging in your changes in the
middle of this without telling him he is going to be very unhappy
with you :) Always coordinate your merges with the owner of the
branch you are merging into.
Ok, my changes are stable and tested and the trunk owner said
go ahead and merge them. How do I merge changes I've made on a
branch into the trunk?
First, anytime that you are ready to merge work from a branch, you
should tag the branch at that point. Do this in your branch sandbox
and use the cvs tag
command with something like:
cvs tag brian-dav_level2_support-merge-1
The reason for this is that you may want to do further work on this
branch after you merge the current batch of work to the trunk. CVS
by default will merge all changes from the root of a branch to its
tip when you perform a merge. This is ok for the first merge, but
after you do a second batch of work you won't want to merge every
change from the root of the branch, just the changes since the
first merge (and you'll need this tag to do that).
Now, assuming you've been working in a branch sandbox and have tested
and committed all of your changes there, cd to a *trunk*-based
sandbox and use:
cvs up -j brian-dav_level2_support-branch
If you cd to a trunk-based sandbox and run the above command, the
changes from the brian-dav_level2_support-branch
branch would
be merged into your working area.
When you perform a merge, be alert for CVS conflict messages. If
any conflicts arise, you must resolve the conflicts manually.
After you have done the merge and resolved conflicts, test
in the sandbox to make sure that things still work as you expect.
After testing, use cvs commit
to commit the changes to the
trunk.
Note that if you make user-visible changes to Zope, you
need to add an entry describing the new feature or bug
fix in the file CHANGES.txt
located in the /doc
directory of the Zope tree. If you are adding a feature,
you should edit the CHANGES.txt
on the trunk, which
is where the next feature release will be made from. If
you have made only bug fixes, you should have committed
the fixes to both the trunk and the current release
branch. In this case, note your bug fix in the CHANGES.txt
on the release branch (which is where the next bug-fix
release will be made from).
How would I merge the second batch of work from that branch?
Almost the same as before. Say we've done some more work in our
branch and we're ready to merge again. Like before (and at all
merge points), we'll sit in our branch sandbox and add another
merge tag:
cvs tag brian-dav_level2_support-merge-2
Now we'll change to our up-to-date trunk sandbox and use the
update command again, but this time with a second -j
argument
that tells CVS to only merge in changes from our branch since
the given tagged version. Our first merge was tagged as
brian-dav_level2_support-merge-1
, so we'll tell cvs to only
update from that version:
cvs update -j brian-dav_level2_support-merge-1 -j brian-dav_level2_support-branch
As before, we look for and resolve conflicts, test and use
cvs commit
to commit the changes to the trunk.
What if I need updates that have been made in the trunk for
the branch that I'm working in?
The "trunk" is really not particularly different from any other
branch in CVS - it can be though of as a sort of default "unnamed"
branch. It turns out that the trunk does have a name of sorts
though. The name HEAD
is used in CVS to refer to the trunk, and
can be used pretty much anywhere you would use a branch tag name.
So if you are on a branch and want to merge changes from the trunk
you use the same command you would use to merge any other branch,
but using HEAD
as the branch-tag name:
cvs up -j HEAD
This will merge changes from the trunk into your working copy on
the branch. After reconciling any conflicts, you can commit these
on your branch.
Is there a way I can see the differences between two branches?
Yes - the CVS diff
command is your friend. To see all of the changes
between the trunk and a given branch (for example brian-foo-branch
),
cd into a trunk-based sandbox and use:
cvs -q diff -c -r brian-foo-branch
This will give you a bunch of diff output showing you the changes in
the trunk vs. the branch brian-foo-branch
. If you use this command
often, you'll notice that you get a lot of spurious diffs where the
only real difference between two items is the RCS Revision or Id
keywords. You can filter these out by adding a -kk
option that
will generally disregard RCS expansion differences:
cvs -q diff -kk -c -r brian-foo-branch
Note that you can also use the -kk
option with cvs update
to
avoid spurious conflict messages (when the only things that conflict
are the RCS expansions) when you are performing merges:
cvs update -kk -d -j brian-foo-branch
Walk me through a quick example?
Ok - we're going to fix a bug. The problem is a simple type in a
docstring. We're going to make a branch since we want the fix in
both the current release branch (Zope-2_2-branch) and the trunk.
First, we'll create a trunk-based sandbox (or use an existing
up-to-date trunk sandbox). For the sake of example, we'll create
one:
cvs co -d fix_typo Zope2
Now we'll make the branch (we'll call it brian-fix_typo-branch
):
cd fix_typo
cvs tag -b brian-fix_typo-branch
Remember that adding a branch tag does not actually put the current
working copy on the branch. We'll use cvs update
to put the current
working area on the branch:
cvs update -r brian-fix_typo-branch
Now the fix_typo
sandbox is on the branch. We edit the appropriate
file to fix the typo, test the change and commit it:
cvs commit TheFile.py
Now we're ready to merge. We've made sure it's ok to merge into both
the trunk and the 2.2 branch, so now we'll tag our branch at this
merge point just in case we ever need to do more work in this branch:
cvs tag brian-fix_typo-merge-1
Now we'll need a trunk sandbox to merge into. We can either revert
our current working area to a trunk sanbox or make another one to
merge into. Lets just revert the one we're using:
cvs update -A
Now our sandbox is on the trunk. Lets do the merge:
cvs update -j brian-fix_typo-branch
Now we look for any conflicts and reconcile them if needed. When
that's done, we'll commit:
cvs commit
Now we need to move our sandbox to the 2.2 branch and do the same
thing there:
cvs update -r Zope-2_2-branch
cvs update -j brian-fix_typo-branch
(resolve conflicts)
cvs commit
And we're done (except for updating CHANGES.txt in the 2.2 branch,
which you just edit and commit in the 22 branch sandbox like normal).