5. Branching and merging
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 another branch
(or the main trunk) by merging. Merging involves first
5.1 What branches are good for
Suppose that release 1.0 of tc has been made. You are continuing to develop tc, planning to create release 1.1 in a couple of months. After a while your customers start to complain about a fatal bug. You check out release 1.0 (see section 4.4 Tags--Symbolic revisions) and find the bug (which turns out to have a trivial fix). However, the current revision of the sources are in a state of flux and are not expected to be stable for at least another month. There is no way to make a bugfix release based on the newest sources.
The thing to do in a situation like this is to create a branch on the revision trees for all the files that make up release 1.0 of tc. You can then make modifications to the branch without disturbing the main trunk. When the modifications are finished you can elect to either incorporate them on the main trunk, or leave them on the branch.
5.2 Creating a branch
You can create a branch with
This splits off a branch based on the current revisions in the working copy, assigning that branch the name `rel-1-0-patches'.
It is important to understand that branches get created in the repository, not in the working copy. Creating a branch based on current revisions, as the above example does, will not automatically switch the working copy to be on the new branch. For information on how to do that, see 5.3 Accessing branches.
You can also create a branch without reference to any
working copy, by using
`-r rel-1-0' says that this branch should be rooted at the revision that corresponds to the tag `rel-1-0'. 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).
As with `tag', the `-b' flag tells
So, the full effect of the command is to create a new branch -- named `rel-1-0-patches' -- in module `tc', rooted in the revision tree at the point tagged by `rel-1-0'.
5.3 Accessing branches
You can retrieve a branch in one of two ways: by checking it out fresh from the repository, or by switching an existing working copy over to the branch.
To check out a branch from the repository, invoke `checkout' with the `-r' flag, followed by the tag name of the branch (see section 5.2 Creating a branch):
Or, if you already have a working copy, you can switch it to a given branch with `update -r':
It does not matter if the working copy was originally on the main trunk or on some other branch -- the above command will switch it to the named branch. And similarly to a regular `update' command, `update -r' merges any changes you have made, notifying you of conflicts where they occur.
Once you have a working copy tied to a particular branch, it remains there until you tell it otherwise. This means that changes checked in from the working copy will add new revisions on that branch, while leaving the main trunk and other branches unaffected.
To find out what branch a working copy is on, you can use the `status' command. In its output, look for the field named `Sticky tag' (see section 4.9 Sticky tags) -- that's CVS's way of telling you the branch, if any, of the current working files:
Don't be confused by the fact that the branch numbers for each file are different (`1.7.2' and `1.4.2' respectively). The branch tag is the same, `rel-1-0-patches', and the files are indeed on the same branch. The numbers simply reflect the point in each file's revision history at which the branch was made. In the above example, one can deduce that `driver.c' had been through more changes than `backend.c' before this branch was created.
See 5.4 Branches and revisions for details about how branch numbers are constructed.
5.4 Branches and revisions
Ordinarily, a file's revision history is a linear series of increments (see section 4.1 Revision numbers):
However, CVS is not limited to linear development. The revision tree can be split into branches, where each branch is a self-maintained line of development. Changes made on one branch can easily be moved back to the main trunk.
Each branch has a branch number, consisting of an odd number of period-separated decimal integers. The branch number is created by appending an integer to the revision number where the corresponding branch forked off. Having branch numbers allows more than one branch to be forked off from a certain revision.
All revisions on a branch have revision numbers formed by appending an ordinal number to the branch number. The following figure illustrates branching with an example.
The exact details of how the branch number is constructed is not something you normally need to be concerned about, but here is how it works: When CVS creates a branch number it picks the first unused even integer, starting with 2. So when you want to create a branch from revision 6.4 it will be numbered 6.4.2. All branch numbers ending in a zero (such as 6.4.0) are used internally by CVS (see section 5.5 Magic branch numbers). The branch 1.1.1 has a special meaning. See section 13. Tracking third-party sources.
5.5 Magic branch numbers
This section describes a CVS feature called magic branches. For most purposes, you need not worry about magic branches; CVS handles them for you. However, they are visible to you in certain circumstances, so it may be useful to have some idea of how it works.
Externally, branch numbers consist of an odd number of dot-separated decimal integers. See section 4.1 Revision numbers. That is not the whole truth, however. For efficiency reasons CVS sometimes inserts an extra 0 in the second rightmost position (1.2.4 becomes 126.96.36.199, 188.8.131.52.12 becomes 184.108.40.206.0.12 and so on).
CVS does a pretty good job at hiding these so called magic branches, but in a few places the hiding is incomplete:
You can use the
It only works if at least one revision is already committed on the branch. Be very careful so that you do not assign the tag to the wrong number. (There is no way to see how the tag was assigned yesterday).
5.6 Merging an entire branch
You can merge changes made on a branch into your working
copy by giving the `-j branchname' flag
The branch 1.2.2 has been given the tag (symbolic name) `R1fix'. The following example assumes that the module `mod' contains only one file, `m.c'.
A conflict can result from a merge operation. If that happens, you should resolve it before committing the new revision. See section 10.3 Conflicts example.
If your source files contain keywords (see section 12. Keyword substitution), you might be getting more conflicts than strictly necessary. See 5.10 Merging and keywords, for information on how to avoid this.
It should be noted that
5.7 Merging from a branch several times
Continuing our example, the revision tree now looks like this:
where the starred line represents the merge from the `R1fix' branch to the main trunk, as just discussed.
Now suppose that development continues on the `R1fix' branch:
and then you want to merge those new changes onto the main
trunk. If you just use the
So instead you need to specify that you only want to merge the changes on the branch which have not yet been merged into the trunk. To do that you specify two `-j' options, and CVS merges the changes from the first revision to the second revision. For example, in this case the simplest way would be
The problem with this is that you need to specify the 220.127.116.11 revision manually. A slightly better approach might be to use the date the last merge was done:
Better yet, tag the R1fix branch after every merge into the trunk, and then use that tag for subsequent merges:
5.8 Merging differences between any two revisions
With two `-j revision' flags, the
will undo all changes made between revision 1.3 and 1.5. Note the order of the revisions!
If you try to use this option when operating on multiple files, remember that the numeric revisions will probably be very different between the various files. You almost always use symbolic tags rather than revision numbers when operating on multiple files.
Specifying two `-j' options can also undo file removals or additions. For example, suppose you have a file named `file1' which existed as revision 1.1, and you then removed it (thus adding a dead revision 1.2). Now suppose you want to add it again, with the same contents it had previously. Here is how to do it:
5.9 Merging can add or remove files
If the changes which you are merging involve removing or
adding some files,
After these commands are executed and a `cvs commit' is done, file `a' will be removed and file `d' added in the main branch.
Note that using a single static tag (`-j tagname') rather than a dynamic tag (`-j branchname') to merge changes from a branch will usually not remove files which were removed on the branch since CVS does not automatically add static tags to dead revisions. The exception to this rule occurs when a static tag has been attached to a dead revision manually. Use the branch tag to merge all changes from the branch or use two static tags as merge endpoints to be sure that all intended changes are propogated in the merge.
5.10 Merging and keywords
If you merge files containing keywords (see section 12. Keyword substitution), you will normally get numerous conflicts during the merge, because the keywords are expanded differently in the revisions which you are merging.
Therefore, you will often want to specify the `-kk' (see section 12.4 Substitution modes) switch to the merge command line. By substituting just the name of the keyword, not the expanded value of that keyword, this option ensures that the revisions which you are merging will be the same as each other, and avoid spurious conflicts.
For example, suppose you have a file like this:
and your working directory is currently on the trunk (revision 1.2). Then you might get the following results from a merge:
What happened was that the merge tried to merge the
differences between 1.1 and 18.104.22.168 into your working
directory. So, since the keyword changed from
Here is what happens if you had used `-kk':
What is going on here is that revision 1.1 and 22.214.171.124 both
expand as plain
There is, however, one major caveat with using `-kk' on merges. Namely, it overrides whatever keyword expansion mode CVS would normally have used. In particular, this is a problem if the mode had been `-kb' for a binary file. Therefore, if your repository contains binary files, you will need to deal with the conflicts rather than using `-kk'.
This document was generated by Derek
Robert Price on December, 27 2002 using texi2html