Branching and Merging
There are really only two reasons to branch: to isolate changes or to create variants. The first is the more common case as it is used to support release (maintenance) branches, parallel development branches, feature branches, etc. In multiple team agile development, each sprint is generally assigned its own branch (for purposes of this article only, consider streams to be branches) under a common parent. What has not been standardized (yet) is whether bug fixes occur on the parent or on one or more branches. Personally, I have found that doing bug fixes on the parent is yields a higher quality end result due to less merging. If a sprint completes, the branch is merged back into the parent. In the case of multiple concurrent sprints, they should be merged in one at a time to minimize confusion and to hopefully allow sprint-level regression testing after each merge.
This pattern of sequential merges causes its own problems. One of the reasons for doing agile development in the first place is to minimize lost time, so having merge times and sequences dictate scheduling is not really acceptable. The figure below illustrates a simple sequential merge on the left and a similar cascading merge on the right. Cascading merges use intermediate integration branches where no work is actually performed to allow concurrent merges to take place. In this example, all of the branches could actually be initiated from the same point and the decision as to which sprint branch merges to which integration branch can be deferred to merge time. Actually, the integration branch creations themselves could be deferred until they are needed, so long as they are initiated from the same starting point as the sprint branches.
There is a third pattern of branching and merging, shown below, that allows for continuous change integration. This pattern should only be used when it is guaranteed that the changes will not be reverted. In other words, when any problem that occurs either as a result of a merge or an issue on a working branch will be fixed instead of abandoned. Even though the illustration shows both working branches merging into the CI branch, it can be that after each working branch merges into the CI branch, the updated CI branch is then merged back into each of the working branches. How and when merges occur depends on the Version Control tool being used. Tools which inherently “know” what changes have been merged in already make the use of this pattern feasible.
Variants are a much simpler case. This is where customer or platform-specific branches are created. Again, it depends on which version control tool is being used as to exactly how this performed and how difficult it is, but basically all you are doing is making variant-specific changes on the variant branch and generic changes on a “generic” branch (often the trunk). If “sparse branching” is supported, it is the view that combines the two branches that yields a buildable codebase. If only “full branching” is supported, the generic branch must be periodically merged into each variant branch.
Hardware CM is both simpler and more complicated. It is simpler in that if there are branches at all, they tend to be of the variant pattern and merging as such is generally impossible. It is more complicated in that you tend to version specifications, vendor lists and part numbers in something that ends up looking like a hybrid between version control and build management. The typical bills of material used for constructing a product are very similar to build records and the list of possible component choices is like a dependency-style build engine.