Branching and Merging Strategies
Branching and merging you've heard of it, perhaps you somehow feel
like you need it (or at least ought to understand it better), and you've
listened to many stories about it, some good, some not so good. Nevertheless,
if you are like many folks, you are not particularly comfortable with it.
Below, we present a simple way to understand branching and merging, we look at
typical uses of branches, and we examine strategies to avoid, or reduce the
cost of, branching and merging.
Understanding Branching and Merging
A co-worker once suggested that one could simplify one's thinking
about version control by ignoring efficiency and envisioning the process in
terms of simple operations on files and directories. His suggestion enabled us
to focus on what we wanted to accomplish from a conceptual standpoint rather
than from the vantage point of how to go about it. When applied to tagging,
branching and merging, this strategy results in great simplification. Consider
these tasks and how simply a basic file copy accomplishes each:
- Task: Preserve the state of the project files.
Simple Action: Make a copy of the project file hierarchy to be
preserved.
- Task: Make changes to the project files without
immediately making them visible to all others on the team.
Simple Action:
Make a private copy of the project file hierarchy to be modified then
incorporate the changes into the private copy.
- Task: Share private changes with other users.
Simple Action: Copy the changed files from your private copy to a public
copy.
- Task: Get changes from another user for your
use.
Simple Action: Copy the changed files from the public copy to your
private copy.
From this example, we see that the version control operations of
preserving, isolating and merging (or sharing) changes are variations of the
basic copy operation. Yet while they all involve copying, their details and
purposes vary.
These four operations (preserve, isolate, publish and subscribe, or
more traditionally tag, branch, release and merge) provide a higher-level
language to describe the nature of the copy. However, even these four
operations are often performed at a lower level than we want.
In the next section, we look at higher-level ways of looking at
branches.
Abstracting Branches
We define a branch as a copy of the project, one that was created for
a purpose. A branch is not made in a vacuum but rather as a copy of an existing
branch. In the making of the copy, we establish a relationship between the
original and the new branches. Types of relationships include parent-child and
sibling-sibling. Several uses of branches are listed and discussed below.
- Private Branch: A private branch provides a
means of working on changes for an extended period of time, allows for regular
check-ins and yet keeps the changes private until they are ready for use by
others. A private branch benefits a user by providing both stability from
external changes and isolation of intermediate changes from the rest of the
team. The cost of a private branch is primarily the expense of merging team
changes into the private branch as well as rebuilding, retesting and then
publishing the tested changes to the public branch. Typically, the private
branch is created as a child of the original (public) branch, and merging and
publishing occur with the parent.
- Shared Branch: Conceptually similar to a
private branch, a shared branch allows multiple users to coordinate their work
while still keeping it private from the whole team. Like a private branch, a
shared branch is typically created as a child. Since there can be multiple
levels of sharing in a large team, shared branches are often nested.
- Release Branch: A release branch preserves
a release state for future reference. Typically, release branches are locked or
frozen to prevent any further changes, although they can be copied to create
new branches where changes can be made. Release branches are often
created as siblings of the original branch, with relationships to previous and
future release branches.
- Patch Branch: A patch branch is used to
create, test and deploy a patch to a release branch. Typically, a patch branch
is created from a release branch as a sibling, with a relationship showing that
the patch is base-lined from the release. Once the patch is complete, it is
also typical to merge patch branches into a future release branch to ensure
that the fixes are integrated into the main product stream.
- Integration Branch: Integration branches
allow integrating and testing of changes from multiple individuals or teams.
They also delay modification of the parent branch until it is stable.
Integration branches are typically children of release branches. Unlike shared
branches, they are not typically used for development.
- Build Branch: Build branches allow for
capturing of a project version for the purposes of building. By building from
the branch, we know exactly what was used in the construction. Build branches
are often created by a nightly build script as children of the to-be-built
branch and are given date-containing names. Milestone build branches can be
renamed and saved as release branches, while other daily build branches can be
cleaned up automatically.
As you can see, there are a number of uses for branches. Understanding
these high-level branch concepts will help you create an effective branching
strategy for your specific needs.
Branching Advice
Branching adds complexity and overhead to development. Frequently,
that overhead enables activities that justify the added complexity and expense.
And many times, the branching overhead is actually less expensive than its
alternatives. In either case, there are sometimes steps you can take to further
reduce your branching overhead. Here are some you should consider.
- Don't branch. If a co-worker has a file locked,
rather than making parallel changes, you could simply ask when he will be
finished. By serializing changes, the branching and merging overhead is
avoided. For small changes, this strategy often works best.
- Set double locks. When locking files in a branch,
also lock the same files in the parent (or target) branch. By simultaneously
locking both the branch files and the parent files (and assuming that the files
haven't yet diverged), the merge task becomes trivial.
- Update frequently. Frequent branch updates are
smaller, and your chances of branching and needing to merge a file that is
being changed by another are less likely when you apply the latest file
revision before changing it yourself.
Your Solution
How does your solution compare? Can you easily branch, merge and
compare branches? Can you easily make release branches, patch branches, etc?
Are you scared to branch because you fear merging? Do you wish this anxiety
were not so?
SnapshotCM delivers a visual environment where project-level branching
is trivial and where project-level comparison and merging are fast and
efficient. Many of our customers have dozens or even hundreds of branches and
releases. They all rely on SnapshotCM to keep it simple for them. Check us out
by taking advantage of our free evaluation. Go to
http://www.truebluesoftware.com/
for all the details.