📜 ⬆️ ⬇️

Basics of branching for parallel development

Introduction

As Fred Brooks rightly pointed out, there is no silver bullet capable of hitting the beast of software development. While new requirements arise, ideas and new bugs are found, programs are living and changing. The path that code travels from version to version can be extremely complicated and tortuous. Many people are involved in its creation: developers, testers, business analysts, customers, etc. Despite the fact that there are many different types of development - outsourcing, product development, open-source, etc., the problems facing the team remain about the same. Software is a complicated thing, the consumer wants to get it as quickly as possible (and cheaper). The quality should be acceptable. The development team is faced with a serious task - to establish effective interaction. One of the most important means of collaboration within the development team is the code that they write.

At the moment, distributed version control systems ( DVCS) are widely distributed on the market. However, the lion’s share of the market is kept by traditional and easier-to-use centralized systems, such as, for example, SVN. A version control system, or rather its competent use, plays a key role in ensuring effective interaction. Remember how long you read a book about your VCS? A team in which there are no people capable of building competent interaction through VCS, based on the needs of the project, will not be envied.
')
Release Management

Let's imagine the perfect release management. The release manager can evaluate the status of the code and select the implemented functionality to be included in the release. This functionality should be ready and tested. Also, the release manager can include bug fixes from the previous release. The unavailable, unstable and untested functionality should not be released. If QA-specialists receive information on the instability of a particular functional, the release manager should be able to remove it from the release. Often there is a need to transfer defect fixes to the version that is already working for the end user, because for some reason it cannot switch to a new one.

If you change the point of view a little and look at the process of working on the code by the developer, he should sit in his sandbox and not be influenced by destabilizing commits by his colleagues. Ideally, developers should only exchange complete and stable sets of changes. So it's easier to understand what has been done, right? However, commits should not dictate to the developer the style of his work, and he should always be able to insert only partially completed functionality.
The problems described above have several solutions. One of them is the right choice and proper use of the project version control system. One more thing is an understanding of possible brunching (branching) strategies and the price you have to pay for all this luxury.

The use of branching allows us to kill two birds with one stone: to stabilize the release version (a process better known as bug fixing) and at the same time to extend the application with new functionality for the next release. These are the two main, though not the only, ways of using branching on a project.

Retreat about code versioning

As a rule, version control systems store a history of changes in the form of a line (centralized) or a graph (distributed). A branch (brunch) is simply a line of code development that has a common history with other branches and exists in parallel with them. Jeff Atwood in his blog compares branches with parallel universes. In such a universe, at some point, the story went differently relative to others. This gives us limitless possibilities that are balanced by the limitless complexity of our universes.

As a rule, one of our stories is the main one and wears the proud name of a trunk or mainline. By analogy with a tree, other branches depart from it. Sooner or later, ready-made (or not quite) functional and error fixes fall into this thread.

Branch per release

Consider the first of these cases, when a separate branch is created for each release. This is done in order to correct defects found after the release of the release or during its testing. This process is usually called stabilization. At the same time, the fixes themselves (bugfixes) do not remain only in the release branches, but are transferred to the mainline (if the release history and the mainline are not too diverged), making it more stable. The code in the release branch is isolated from the destabilizing effect of developing new functionality and does not block it. By itself, the release branch provides an easy way to support the release version. When release support stops, its branch is frozen. In the meantime, the project goes on, mainline continues its development, being the point at which new functionality accumulates for the next releases.

In the same way, you can support releases for different customers, highlighting a branch for each, if for some reason they cannot deliver the same version. I want to note that the support of different variations of the same version is a laborious task and should be avoided as far as possible.



Branch per feature

The next case is the allocation of a separate branch for the development of a new functional . As a rule, it is one logically complete functional area, or just a feature. The new functionality is merged with the main branch only after it is fully completed, which allows you to avoid the negative impact of unfinished work on other lines of development. After the new functionality is ready and merged with the main branch, other development branches should be integrated with the mainline so that the delayed integration effect does not accumulate. The use of branches for releases and development allows us not to wait until the testing and release stabilization ends, but to immediately start developing the functionality for the next one.



You can also create sub-branches for release and development branches, if you still need isolation levels. In all cases, the creation of a new branch should understand the price of its support, which will be mentioned a little later.

Integration between branches

The main branch (mainline, trunk) is the main integration point using code. Anyway, all the changes made by the developers get here. However, it should not turn into a dump of unstable and unfinished code. That is why it is recommended to develop new features in a separate branch, integrate it with the main one, test it and only then merge the changes. In other words, the mainline should contain a fairly complete code that can serve as the basis for the stabilization release branch. Also, bug fixes from the release branches, after passing through the mainline, fall into the branches for development, thus, work is being done on a more stable code. The good rule is that we should not give unstable changes to other branches and that we should accept stable changes from other branches.



Consider the situation depicted in the picture:



In assessing the pros and cons of this approach, one should take into account:


Integration via Mainline is not the only way to integrate - integration is possible directly between branches. Martin Fowler calls this method Promiscuous Integration . For this integration method, communication within the project team is very important.

Branch stability

Such a model has a gradation of stability, where the most stable release branches are, the mainline is less stable, and the most unstable are the development branches. As a rule, in the diagrams the most stable branches are displayed above all, and unstable - below all.



Branching overhead

The following costs are associated with branching:



Types of dependencies between branches and how to solve them

The following dependencies may occur between branches:



There are several typical solutions for working with such dependencies:



Conclusion

It is important to understand that a competent modular design of an application can greatly reduce or negate the need for branching and is a powerful tool for solving problems associated with parallel development.
Branching allows us to simultaneously conduct two types of development: stabilization and implementation of new functionality. However, this is not the only way to use it. For example, individual branches can be allocated to separate iterations or to isolate different commands.
The correct choice of branching strategy depends on the needs of the project and the possibilities / limitations of the version control system used (which, however, no one forbids changing). Real-world constraints that are imposed on a process are often impossible to solve without the possibility of parallel development. However, illiterate understanding and use of branching often leads to anti-patterns that complete this material.

Anti branching patterns:

Source: https://habr.com/ru/post/170589/


All Articles