Description

Branches are normally used in two places in FreeBSD.

First, release branches, used for taking code from HEAD and preparing for a release. These are typically under the control of the release engineer. These branches are expected to last for the lifetime of the project (not just the life time of the release).

Second, developer branches. These may be shorter lived, and provide a mechanism to allow developers to carry out intrusive changes (more intrusive than normally happen on -current) in an out-of-the-way location, prior to (probable) eventual integration back on to the HEAD.

Current Implementation

Release branches are created using CVS' branch creation commands. Creating a branch is a time consuming operation, and also requires a tag to be laid down (a _BP tag). While this is happening the repository is locked.

Developer branches are created in Perforce, so that developer branch creation does not impact on the normal repository operation.

SVN Implementation

Subversion does not implement a first-class branch operation.

Instead, branches are treated as copies of the source directory (or file). Copies in Subversion are cheap, taking a constant time to complete, and using very little extra repository space. You can think of them as being copy-on-write operations.

Branches are presented through Subversion's filesystem interface. Accordingly, there are no special "show branch" commands, as branches appear in the filesystem.

A consequence of this is, although given a branch, you can see where and at what revision it was copied from, you can not, given the source of a branch, easily answer the question "To what locations has this directory been branched?"

See SVN_Repo_Layout for a suggested repository layout that shows this model.

Hg Implementation

There are two classes of branches in Hg:

  1. branches created by hg clone: it is in fact cloning the entire repository, it is the main way to creating branches. The parent repository is remembered by the child in .hg/hgrc -- see hg paths so latter hg pull will do the right thing.

  2. multiples heads within a single repository/branch created through hg pull and hg merge. When you pull from a remote repository, the changesets are merge in another head then merge with your working directory when hg update is used. This intents to reduce merge conflicts.

cloning

        hg clone http://hg.fr.freebsd.org/src-head my-src-head

gives you a entire copy of the repository including the working area. If you only want a copy of the history, add -U to clone. When you clone on the same filesystem, by default files within .hg are hardlinked to speed up cloning and save disk space.

hg pull by default takes all non-present changesets from the parent so there is no problem with repeated merges.

You can have multiple heads within a repository without merging but it is a bit more complicated.

Pushing is as simple as running hg push because the parent - if any - will also be used by default for pushing.

Git Implementation

Branches are cheap, with:

git branch <branchname> [commitid]

This just creates a new 41-byte file pointing at the sha1 of the commit that is the head of the branch.

When you do a merge, for example:

git pull . new-branch

the commit for the merge will have two (or more) parents recorded instead of one. A parent reference is a sha1 of a commit -- an identification of the entire history. So, repeated merges are simple -- the tool walks down to a shared parent then plays the new commits of one against the other to get the new tree. Various replay strategies may be used if you have a difficult merge to do.

Branches in git may be pushed easily and relatively efficiently (The receiver tells the sender what heads it has, which therefore tells about all the objects it has. Then, the sender creates a pack of whatever new stuff needs to be sent and new head updates). So, one mechanism we might use for short-lived developer branches is personal repositories on freefall. A user would set it up with:

git-clone -l -s /git/src ~/src

This creates a clone of the repository with no objects yet that says "if you can't find an object here, look in /git/src". Then, I could push my new branch to it with:

git push git+ssh://freefall.freebsd.org/~anholt/src new-branch:new-branch

Which creates just the new objects and the head on the remote end -- not a full copy of the repository.

Monotone Implementation

Supported (also see monotone:FeatureLightweightBranches)

Monotone's implementation of branches is extremely lightweight, and quite different to that in many other systems.

Revisions can be in multiple branches (or none). Revisions can be added to branches long after they are first committed, perhaps after testing or code review to determine that they are suitable. Monotone separates completely the concept of a file's history (which is important for merging) from the concept of a branch (which is important for developers keeping track of the purpose of a particular development effort and view of the code). The monotone:BranchAnalogy describes the separation of these concepts.

Example Usage

To commit some changes in a workspace to a new branch:

 <edit files>
 $ mtn commit -b com.example.new-branch-name

VCSFeatureBranch (last edited 2008-06-17 21:38:10 by localhost)