Chapter 4. Mainline

Mainline

Photo by John Vachon. Library of Congress, Prints & Photographs Division, FSA-OWI Collection, Reproduction Number: LC-USF34-064602-D DLC.

On the main line. Bowdle, South Dakota, February 1942.

When you are developing a software application as part of a team effort, you often have to reconcile parallel development efforts. Your version control tool provides branching and merging facilities. You can use branches to isolate parallel efforts, but this can have a cost. This pattern shows you how to manage your codeline to minimize the integration effort that branching and merging require.

Note

Mainline

How do you keep the number of currently active codelines to a manageable set and avoid growing the project's version tree too wide and too dense? How do you minimize the overhead of merging?

Generically, a branch is a means to organize file versions and show their history (White 2000). More specifically, a branch is a configuration of a system that is derived from, and developing independently of, the base configuration. For example, a branch can consist of a snapshot of the system at release time and all patches that you apply to the release. A branch can also be used to keep a subset of files that when merged with the main system, produce a unique variant, such as a platform-specific version or a customer variant.

Branching is a powerful mechanism for isolating yourself from change. You can branch to isolate changes for a release, for a platform, for a subsystem, for a developer's work—just about anytime you have work that goes off in a different direction. Whenever branches need to be integrated, you need to merge the changes—for example, when you must integrate a bug fix for the last release into the current release. This isolation from change can have a cost. Even with good tools, merging can be difficult because it is possible to make two changes that conflict with each other (because of the intent of the change, if for no other reason), and you have no way of resolving the conflict without knowing the intention of the authors. You may have to make the change manually in both codelines. Any work you thought you would save by branching can be more than compensated for in the effort of a messy merge. Figure 4-1 illustrates this.

A Merge Can be Messy.

Figure 4-1. A Merge Can be Messy.

Separate codelines seem like a natural way to organize work in some cases. As your product evolves, you may want to create more codelines to isolate and organize changes. This is helpful because it is easy to allow the codelines to evolve in their own way. More codelines may mean more merging though, and more merging means more synchronization effort, and the practical costs of the merge may outweigh the apparent improved organization.

Some codelines are naturally derivative. It may be natural to think of each release using the prior release as a starting point, following a promotion model. This will give you a staircase codeline structure that can make it hard to determine where code originated, and making an urgent fix to a release without interrupting new development can be difficult with this structure. Figure 4-2 shows this case. But with this structure, the policy of the codeline will change from being active to development, and it requires developers to relocate work in progress to another codeline (Wingerd and Seiwald 1998).

Staircase branching (or a cascade)

Figure 4-2. Staircase branching (or a cascade)

Another use of a branch is to allow a subset of the team to work on a change with far-reaching consequences. If they work on the branch, they do not have to worry about breaking existing code or about problems other people's changes can cause. The branch isolates each group from changes another makes. This works well when you integrate back with the main body of code as quickly as possible, but if you branch simply to defer integration, the merge will be difficult, and you are just putting off the inevitable.

Some argue for resisting the temptation to ever delay integration. Extreme Programming advocates continuous integration because the effort of integration is exponentially proportional to the amount of time between integrations (Fowler and Foemmel 2002), but sometimes parts of the code base really are evolving in different directions, and independent lines of evolution make sense.

If you want to branch, creating a branch can be a simple matter with the right tools, but a branch is a fairly heavyweight thing. A branch of a project can be all the components for a release and some of their dependents. So creating that branch has serious consequences if you need to integrate any changes from the original codeline into it.

If you don't branch, you lose the isolation a branch gives you, and your code all needs to work together for anyone to get anything done. But in most cases, your code needs to work together in the end anyway. You need to balance the transient freedom that branching gives you with the costs that you will encounter when you need to resynchronize.

You want to maximize the concurrency on your codelines while minimizing problems that deferred integration can cause.

Simplify Your Branching Model

Note

Simplify Your Branching Model

When you are developing a single product release, develop off of a mainline. A mainline is a “home codeline” that you do all your development on except in special circumstances. When you do branch, consider your overall strategy before you create the branch. When in doubt, go for a simpler model.

The reason for a mainline is to have “a central codeline to act as a basis for subbranches and their resultant merges” (Vance 1998). The mainline for a project generally starts with the code base for the previous release or version. If you are doing new development, you start with only one codeline, which is your mainline by definition.

Doing mainline development does not mean “do not branch.” It means that all ongoing development activities end up on a single codeline at some time.

Don't start a branch unless you have a clear reason for it and the effort of a later merge is greatly outweighed by the independence of the branch. Favor branches that won't have to be merged often—for example, release lines. Branching can be a powerful tool, but like any tool, it should be treated with respect and understanding. Do most of your development work off of a mainline. Use good build and development practices to ensure that what is checked in to the mainline is usable, but realize that the tip of the mainline is a work in progress and will not always be of release quality.

Do most of your work on one codeline. The mainline need not be the root of the version control system. It can be a branch that you are starting a new effort on. The key idea is that all the work done on a release will be integrated quickly into one codeline.

You need to ensure that the code in the mainline always works reasonably. It is to your advantage to maintain a continually integrated system anyway because “big-bang” integration costs almost always exceed expectations.

When the time comes to create a codeline for a new major release, instead of branching the new release line from the previous release line, merge the previous release line back to the mainline branch and branch the new release line from there. Have a shallow branching model, such as shown in Figure 4-3.

Mainline development

Figure 4-3. Mainline development

Mainline development offers the following advantages.

  • Having a mainline reduces merging and synchronization effort by requiring fewer transitive change propagations.

  • A mainline provides closure by bringing changes back to the overall workstream instead of leaving them splintered and fragmented.

There are still reasons to branch. You should branch toward the end of a release cycle to isolate a stable version of the code base at that revision level. This will enable you to fix bugs on that branch without introducing new features and other work in progress to the already released codeline.

Limit branching to special situations, including the following.

  • Customer releases. This allows bug-fix development on the release code without exposing the customer to new feature work in progress on the mainline. You may want to migrate bug fixes between the release branches and the mainline, but depending on the nature of the work on each line, this too may be limited.

  • Long-lived parallel efforts that multiple people will be working on. If this work will make the codeline more unstable than usual, create a Task Branch (19). This works best when the mainline will have only small changes done on it.

  • Integration. When you create customer release lines, instead of doing a code freeze, create an integration branch on which your developers will do all their work. This allows progress to continue on the mainline. Bug fixes in the integration line need to be integrated into the mainline, but this should not be too difficult because the release should be close to what is currently active.

Some situations will still require a branch. But generally you should think hard before branching; ask yourself if the work really requires a branch. Branches have many uses, but you want to avoid long-lived branches that must be merged later.

To do mainline development:

  • Create a codeline (e.g. /main) using the current active code base as a starting point.

  • Check in all changes to this codeline.

  • Follow appropriate precheck-in test procedures to keep this mainline useful and correct.

Mainline development can greatly simplify your development process. Wingerd and Seiwald report that “90% of SCM 'process' is enforcing codeline promotion to compensate for the lack of a mainline” (Wingerd and Seiwald 1998).

Unresolved Issues

Once you decide to have a mainline, you need to figure out how to keep the mainline usable when many people are working on it. Active Development Line (5) describes how to manage this.

Further Reading

  • SCM tool manuals, such as those for CVS and ClearCase, describe how to manage mainline and release line development. You can download and find out about CVS at http://www.cvshome.com/.

  • Open Source Development with CVS (Fogel and Bar 2001) describes how to use the popular open source tool CVS.

  • Software Release Methodology, by Michael Bays (Bays 1999), has a good discussion about branching strategies and issues for merging.

  • Software Configuration Management Strategies and Rational ClearCase (White 2000) discusses branching strategies. Although the book focuses on ClearCase, there is also good generic information in the book.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset