Software Configuration Management // Version Control
Hello again.
I continue to publish a series of articles on SCM - software configuration management.
3 previous notes can be read in the same blog .
Today I’ll talk about what most readers work with - version control.
The following will describe the main techniques implemented in the vast majority of version control systems. How they are implemented in applications that the reader uses, will be left at the mercy of numerous user guides, how-to, FAQ, and other documents that can be easily found. The main thing is to understand by what principles and why it works that way.
Version control system is software that allows you to create versions of elements and work with these versions as independent elements. English sources use the term version control systems , abbreviated VCS. Working with versions involves both creating the versions themselves and the structure for storing them. As a rule, these are either chains or trees.
Before working with elements and their versions, you need to create these elements, i.e. instruct the version control system to take existing real-world objects and place them under their control. Together with the element itself, its first version is always created.
Most often, as elements for version control are:
As already mentioned, control systems should provide structures for storing versions. The most common representation of this structure is the version tree . This is such an organization of versions of an element in which, based on any version of a configuration element, several sets of sequences of its versions can be created. In this case, a separate set of versions originating from an arbitrary version is called a branch . And since the branch contains versions, each of the versions can be a source for creating other branches. In short, a tree.
The name of the model speaks for itself: the plants (elements) appear buds and leaves (versions), of which, in turn, branches. On branches - leaves (other versions) and other branches. Again, the same vegetation grows on them. As a result, a tree grows in which the crown is many versions. One element - one tree.
Why is this whole construction needed? Is it really impossible to simply build versions one by one? Of course you can. However, this will immediately limit the use of such a system. If the versions appear one by one, then at one point in time only one of the users working with the system will be able to create a new version, the rest will have to wait. Moreover, when a new version appears, everyone will need to combine their changes with current developments. And so - until all comers put their best practices into the version chain. In this case, everyone will have to make sure that the merging of versions did not lead to a system breakdown. And, in addition, until all changes are put in such a way under control, all of those waiting will have to save intermediate results somewhere locally, without confusing with what is currently in work. And alright if a couple of people work on a dozen elements - they can always agree. And if the scale is much larger? Add a dozen people (without even increasing the number of elements) - and such simple chains will completely hinder the work. In general, the linear structure of versions gives rise to many complexities.
So, it’s clear that you can’t do without branches. But do not grow the same branch for the smallest sneeze of the developer? Let's see in what cases branches grow. Typical examples of branches are as follows:

Scheme 1. Version tree of element.c
Figure 1 shows an example version tree. An element.c file has a release branch release_1.x, where stable versions of this element (1-5) are added. To save the delta, a separate branch with a special name format is created for each change request. In our case, the format is rec <record_number> _ <username>, where record_number is the ID of the change request in the tracking system. To combine deltas from different developers, integration branches with names of the form int_ <username> _ <suffix> are created, where the suffix stores the integration description or the number of the stabilized configuration. You can also see the branch for debugging, most often they are referred to as dbg_ <username> _ <arbitrary_comment> - on it are laid out verification options for changes.
More information about growing each branch from the example will be described below.
Each project can have its own ways of creating and naming branches, but the main ones are listed above. If product lines are used, then it becomes necessary to use all of these types.
The version tree is growing and expanding, and sooner or later it is necessary to combine the results of work. For example, a developer sprouted a branch from one of the elements to work on a change request. He put several versions on it, and the latter is the one that contains debugged and tested code. At the same time, there is a release branch, where are the versions released as part of the basic configurations and stable releases. It is necessary to combine the results. Version merge
mechanism is used for this.. As a rule, it means creating a new version of an element for which the base version is taken on the selected branch (base), and the changes contained in the selected third-party version (source) are applied to it. In English sources, the term merge is used .
A branch with a source version can be grown both from the source version and from its earlier ancestors. Existing VCS allow you to merge both manually and automatically. Moreover, the second method is the main one. Manual merging is requested only in case of conflict.
Merge conflictsoccur if the same fragment changes in both versions of an element. This situation occurs when the ancestor of the source version is not the version from which the new version will grow. A typical example of such a conflict is the revision history, which is added to the top of the source file so that in each version you can immediately see who changed last and what was done. In the case of merging versions grown from different sources, this line will definitely cause a conflict, and it is solved only by inserting both lines in the story. When a more complex case arises, the developer or expert in the affected code must carefully manually make the necessary changes.
To the question of common ancestors and the merging of changes: in addition to manual and automatic, merging can be done in a two-position and three-position way. On-off merging is done by simply comparing the two versions and adding up their deltas (the difference between the element versions). The algorithm works on the principle of diff'a or close to it: take the delta and insert / delete / change the necessary lines.
Three-position merger takes into account the “ common ancestor»Of both versions and calculates the delta based on the history of the element in the corresponding branches. Accordingly, in the event of a merger conflict, the developer is offered 3 versions of the element - a common ancestor and 2 options, what happened to this ancestor over time and changes. This approach helps to assess the degree and importance of the delta on both branches and make a decision about the need to integrate a conflict piece often even without the participation of the authors of the changes.
After the merger is completed, information about it should be saved, if possible. As a rule, most mature VCS have the ability to save “merge arrows” - meta-information about where, where and at what point in time the changes merged and who did it.
Consider an example - a tree of versions of an element in diagram 2, demonstrating the order of growing and merging branches on it. As you can already guess, the whole tree is taken from Scheme 1, but merge arrows are added to it.

Scheme 2. An example of merging changes between different branches
So, the project produces a certain product, which includes the element.c file. In order to store stable versions, the team agreed that all stable or base versions are stored on the release_1.x branch. This will be called the " release branch ." Our element is no exception, and the initial version 1 is created on the release branch.
For simplicity of notation, we will describe the branches as if they were directories on the disk. Accordingly, the first version will be called /release_1.x/1.
Further, one of the managers in the change request tracking system (hereinafter we will call this system simply “bugtracker”) started record number 98, where he described the new functionality required by the product. And, of course, I appointed one of the users responsible for this task - let it be user2. user2 thought a little and started to solve this problem, and after some time decided to put the resulting source code under version control. According to the naming standards adopted by the project (CM-policies), the branch for making changes to our project is called rec <record-number> _ <user> [_ <comments>]. Therefore, the new branch was named rec98_user2, and its creator refrained from commenting. The work is in full swing, the version of /release_1.x/rec98_user2/1 appears, and then /release_1.x/rec98_user2/2.
On this, let us leave the user2 developer, let him think about the task. After all, while he was working, in the bugtracker, a record (CR) was registered under number 121, in which they described a new error found by testers. This record was assigned to user user1, and he began to successfully correct the error described. As he corrected, he decided to start a branch to save the results. According to the project policies, the user named the new branch rec121_user1. Note that at the time of starting work and creating the branch, someone already added the next stable version to the release branch - /release_1.x/2. Therefore, the branch grows from the last version at that time (the second). A branch is created - you can add versions. The end result is version /release_1.x/rec121_user1/2.
What's next? The error has been fixed, tested (we will leave this plane of work behind the scenes) - it’s time to make these changes part of a stable configuration and, possibly, a new basic configuration. This is where the CM engineer or the team member who performs this role begins to work. Using thecrowbar and sledgehammer of the merger team, he creates a new version on the release branch - /release_1.x/3. Pay attention to the arrow with number 1 - it displays just the process of merging.
Let's go back to user2 - he just decided to make some changes for his task, but he decided to whip up first what was going to happen and let his colleagues look at their solution. To do this, he creates a debug branch. The CM policy of the project says that it should be called dbg_ <user> [_ <comment>]. Accordingly, the new branch will be called /release_1.x/rec98_user2/dbg_user2. On it, the user creates the version /release_1.x/rec98_user2/dbg_user2/1. It was decided to take the resulting solution into the main code, so the author merged the new delta and the version from which the branch grew. At the same time, the user cleaned and optimized the code so that it would not be embarrassing to give it for integration - the result was the version /release_1.x/rec98_user2/3.
However, user2 finds out that during his work a serious error was fixed, which CR # 121 was wound up on. And this fix may affect the functionality of the new functionality. A decision is made to connect both deltas and see what happens. The merge of the versions /release_1.x/rec98_user2/3 and /release_1.x/rec121_user1/2 is done to form the version /release_1.x/rec98_user2/4. Well, the merger arrow number 3 also appears. This new version is checked for performance and errors, and a decision is made - it is necessary to integrate! Again, the CM engineer takes his tools and makes the version /release_1.x/4, drawing the corresponding arrow number 4 to it (any coincidence of numbers is random).
However, life does not stand still. While our two developers contributed and merged the delta together, the other team members had already changed the same file. Two CRs were opened - 130 and 131, then assigned to user3. He successfully completed them and made two branches - one per record. Since the tasks were set and solved at different times, the branches for their solution grew from different versions on the release branch. The result is the versions /release_1.x/rec130_user3/1 and /release_1.x/rec131_user3/1, spaced from the version /release_1.x/3.
There are changes - it is necessary to combine them, stabilize and make the basic configuration, if everything is fine. For this purpose, a CM engineer, who runs under the operational alias user7 in the version control system, creates an integration branch that looks like int_ <user> _ <future-release-number> in this project. Therefore, the branch /release_1.x/int_user7_1.5 appears. Both deltas merge together on it. First, the changes for record 130, with the formation of the version /release_1.x/int_user7_1.5/1. Then - for recording 131, version 2 is created for it on the same branch. For all operations, merge arrows are drawn.
The final chord of the CM engineer is to merge the version /release_1.x/int_user7_1.5/2 onto the release branch to form the version /release_1.x/5. Subsequently, this branch will become part of the basic configuration of the product.
Here is such a rather big description of a small picture. One picture is worth hundreds of words - they say the truth.
An attentive reader probably has a question in his head - if everything is done through branches and merge arrows, where did the /release_1.x/2 version come from? After all, not a single arrow from any branch leads to it! Natural question. The answer is also natural. Yes, there are situations when changes are made directly to the release branch. For example, a terrible mistake was found, made with the first version - they forgot to make a comment in the revision history section about who made the changes! Of course, this is a joke, no one will violate politics for such trifles. However - and this happens. The main thing is to know exactly who created the new version and why he did it. Best of all, if the version control system allows you to limit the rights to create versions for each branch separately. In this case, we will additionally secure the project by that we will only give the CM engineer permission to add versions on the release branch. At least with a similar restriction it will be easier to find the last one :).
After the above, is it necessary to say that the ability to work with branches is actually the basic functionality of any mature version control system? Without branches, a version control system can be considered as such only from a formal point of view - simply because it can store and issue versions, but no more.
So, the version tree is growing, the team’s work is taking its course. There is a need to stabilize the results of work and determine the basic configuration, which at any moment any team member can take from the version control system. Stabilization is done by merging versions - this will be discussed below. But on the establishment of the basis we dwell in more detail.
Obtaining a basic configuration is essentially identifying a set of stable versions and determining how to uniquely identify them. For these purposes, version control systems have a “tagging” mechanism. A label is a alphanumeric designation that uniquely identifies a configuration. Having a label, you must always be able to accurately and unequivocally highlight the configuration.
In English sources, the terms label and tag are mainly used .
If the label is a designation for the configuration, then each version of the configuration must be uniquely identified by this label. Thus, the label will select the element in that version, which is marked as necessary.
The implementation of the concept of labels may vary across systems. In some (CVS to ClearCase), a label is an attribute of an element's version. For example, in diagram 2, the label would be hung directly on one of the versions, i.e. would be just a tag next to the circle. In other systems (Subversion), a label is understood to be just one of the varieties of branches. To each - his own, the main thing is that the invested meaning remains the same.
What else I would like to note: one configuration can be marked with several labels. For example, the components discussed in the first part of the article can be tagged with both component labels (to determine the basic configurations of components) and product labels in order to officially become part of the basic configuration of a product. It turns out that the basic configuration of each component is marked at least twice - once with a component label, the second with a product label.
In general, labels are a means of indicating configurations, so for the most part they are a tool for CM engineers. Developers only use the tags already made in order to regularly receive a basis for further work.
It was shown above what basic functions any version control system has. How they are implemented in specific applications - everyone can see in the system that he personally uses.
Take a look at your tools again with an all-round look and compare with what is described.
By tradition - a list of recommended materials for independent thoughtful reading.
To complete the picture of the use of version control systems, it remains to talk about the distribution of this control between development teams located in different geographical locations. But more about that in the next note.
To be continued.
PS I publish in "Project Management", and not in "Version Control Systems", just to publish the entire cycle of notes in a uniform manner.
I continue to publish a series of articles on SCM - software configuration management.
3 previous notes can be read in the same blog .
Today I’ll talk about what most readers work with - version control.
Disclaimer
The following will describe the main techniques implemented in the vast majority of version control systems. How they are implemented in applications that the reader uses, will be left at the mercy of numerous user guides, how-to, FAQ, and other documents that can be easily found. The main thing is to understand by what principles and why it works that way.
What are you talking about?
Version control system is software that allows you to create versions of elements and work with these versions as independent elements. English sources use the term version control systems , abbreviated VCS. Working with versions involves both creating the versions themselves and the structure for storing them. As a rule, these are either chains or trees.
Before working with elements and their versions, you need to create these elements, i.e. instruct the version control system to take existing real-world objects and place them under their control. Together with the element itself, its first version is always created.
Most often, as elements for version control are:
- Files
- directories
- hard and softlinks.
Branching and merging versions
As already mentioned, control systems should provide structures for storing versions. The most common representation of this structure is the version tree . This is such an organization of versions of an element in which, based on any version of a configuration element, several sets of sequences of its versions can be created. In this case, a separate set of versions originating from an arbitrary version is called a branch . And since the branch contains versions, each of the versions can be a source for creating other branches. In short, a tree.
The name of the model speaks for itself: the plants (elements) appear buds and leaves (versions), of which, in turn, branches. On branches - leaves (other versions) and other branches. Again, the same vegetation grows on them. As a result, a tree grows in which the crown is many versions. One element - one tree.
Why is this whole construction needed? Is it really impossible to simply build versions one by one? Of course you can. However, this will immediately limit the use of such a system. If the versions appear one by one, then at one point in time only one of the users working with the system will be able to create a new version, the rest will have to wait. Moreover, when a new version appears, everyone will need to combine their changes with current developments. And so - until all comers put their best practices into the version chain. In this case, everyone will have to make sure that the merging of versions did not lead to a system breakdown. And, in addition, until all changes are put in such a way under control, all of those waiting will have to save intermediate results somewhere locally, without confusing with what is currently in work. And alright if a couple of people work on a dozen elements - they can always agree. And if the scale is much larger? Add a dozen people (without even increasing the number of elements) - and such simple chains will completely hinder the work. In general, the linear structure of versions gives rise to many complexities.
So, it’s clear that you can’t do without branches. But do not grow the same branch for the smallest sneeze of the developer? Let's see in what cases branches grow. Typical examples of branches are as follows:
- branch for the request for changes - it is started for versions created during work on the request for change ("development", or "syarny", branch);
- integration branch - serves as an intermediate storage for the stabilization process;
- release branch - for laying out versions while stabilizing the configuration (see the corresponding section of the first part of the article). Some versions on the branch can be later declared part of the basic configuration;
- debugging ("debit") branch - for short-term storage of versions, mainly for the purpose of checking any decisions.

Scheme 1. Version tree of element.c
Figure 1 shows an example version tree. An element.c file has a release branch release_1.x, where stable versions of this element (1-5) are added. To save the delta, a separate branch with a special name format is created for each change request. In our case, the format is rec <record_number> _ <username>, where record_number is the ID of the change request in the tracking system. To combine deltas from different developers, integration branches with names of the form int_ <username> _ <suffix> are created, where the suffix stores the integration description or the number of the stabilized configuration. You can also see the branch for debugging, most often they are referred to as dbg_ <username> _ <arbitrary_comment> - on it are laid out verification options for changes.
More information about growing each branch from the example will be described below.
Each project can have its own ways of creating and naming branches, but the main ones are listed above. If product lines are used, then it becomes necessary to use all of these types.
The version tree is growing and expanding, and sooner or later it is necessary to combine the results of work. For example, a developer sprouted a branch from one of the elements to work on a change request. He put several versions on it, and the latter is the one that contains debugged and tested code. At the same time, there is a release branch, where are the versions released as part of the basic configurations and stable releases. It is necessary to combine the results. Version merge
mechanism is used for this.. As a rule, it means creating a new version of an element for which the base version is taken on the selected branch (base), and the changes contained in the selected third-party version (source) are applied to it. In English sources, the term merge is used .
A branch with a source version can be grown both from the source version and from its earlier ancestors. Existing VCS allow you to merge both manually and automatically. Moreover, the second method is the main one. Manual merging is requested only in case of conflict.
Merge conflictsoccur if the same fragment changes in both versions of an element. This situation occurs when the ancestor of the source version is not the version from which the new version will grow. A typical example of such a conflict is the revision history, which is added to the top of the source file so that in each version you can immediately see who changed last and what was done. In the case of merging versions grown from different sources, this line will definitely cause a conflict, and it is solved only by inserting both lines in the story. When a more complex case arises, the developer or expert in the affected code must carefully manually make the necessary changes.
To the question of common ancestors and the merging of changes: in addition to manual and automatic, merging can be done in a two-position and three-position way. On-off merging is done by simply comparing the two versions and adding up their deltas (the difference between the element versions). The algorithm works on the principle of diff'a or close to it: take the delta and insert / delete / change the necessary lines.
Three-position merger takes into account the “ common ancestor»Of both versions and calculates the delta based on the history of the element in the corresponding branches. Accordingly, in the event of a merger conflict, the developer is offered 3 versions of the element - a common ancestor and 2 options, what happened to this ancestor over time and changes. This approach helps to assess the degree and importance of the delta on both branches and make a decision about the need to integrate a conflict piece often even without the participation of the authors of the changes.
After the merger is completed, information about it should be saved, if possible. As a rule, most mature VCS have the ability to save “merge arrows” - meta-information about where, where and at what point in time the changes merged and who did it.
Branching and Merging Example
Consider an example - a tree of versions of an element in diagram 2, demonstrating the order of growing and merging branches on it. As you can already guess, the whole tree is taken from Scheme 1, but merge arrows are added to it.

Scheme 2. An example of merging changes between different branches
So, the project produces a certain product, which includes the element.c file. In order to store stable versions, the team agreed that all stable or base versions are stored on the release_1.x branch. This will be called the " release branch ." Our element is no exception, and the initial version 1 is created on the release branch.
For simplicity of notation, we will describe the branches as if they were directories on the disk. Accordingly, the first version will be called /release_1.x/1.
Further, one of the managers in the change request tracking system (hereinafter we will call this system simply “bugtracker”) started record number 98, where he described the new functionality required by the product. And, of course, I appointed one of the users responsible for this task - let it be user2. user2 thought a little and started to solve this problem, and after some time decided to put the resulting source code under version control. According to the naming standards adopted by the project (CM-policies), the branch for making changes to our project is called rec <record-number> _ <user> [_ <comments>]. Therefore, the new branch was named rec98_user2, and its creator refrained from commenting. The work is in full swing, the version of /release_1.x/rec98_user2/1 appears, and then /release_1.x/rec98_user2/2.
On this, let us leave the user2 developer, let him think about the task. After all, while he was working, in the bugtracker, a record (CR) was registered under number 121, in which they described a new error found by testers. This record was assigned to user user1, and he began to successfully correct the error described. As he corrected, he decided to start a branch to save the results. According to the project policies, the user named the new branch rec121_user1. Note that at the time of starting work and creating the branch, someone already added the next stable version to the release branch - /release_1.x/2. Therefore, the branch grows from the last version at that time (the second). A branch is created - you can add versions. The end result is version /release_1.x/rec121_user1/2.
What's next? The error has been fixed, tested (we will leave this plane of work behind the scenes) - it’s time to make these changes part of a stable configuration and, possibly, a new basic configuration. This is where the CM engineer or the team member who performs this role begins to work. Using the
Let's go back to user2 - he just decided to make some changes for his task, but he decided to whip up first what was going to happen and let his colleagues look at their solution. To do this, he creates a debug branch. The CM policy of the project says that it should be called dbg_ <user> [_ <comment>]. Accordingly, the new branch will be called /release_1.x/rec98_user2/dbg_user2. On it, the user creates the version /release_1.x/rec98_user2/dbg_user2/1. It was decided to take the resulting solution into the main code, so the author merged the new delta and the version from which the branch grew. At the same time, the user cleaned and optimized the code so that it would not be embarrassing to give it for integration - the result was the version /release_1.x/rec98_user2/3.
However, user2 finds out that during his work a serious error was fixed, which CR # 121 was wound up on. And this fix may affect the functionality of the new functionality. A decision is made to connect both deltas and see what happens. The merge of the versions /release_1.x/rec98_user2/3 and /release_1.x/rec121_user1/2 is done to form the version /release_1.x/rec98_user2/4. Well, the merger arrow number 3 also appears. This new version is checked for performance and errors, and a decision is made - it is necessary to integrate! Again, the CM engineer takes his tools and makes the version /release_1.x/4, drawing the corresponding arrow number 4 to it (any coincidence of numbers is random).
However, life does not stand still. While our two developers contributed and merged the delta together, the other team members had already changed the same file. Two CRs were opened - 130 and 131, then assigned to user3. He successfully completed them and made two branches - one per record. Since the tasks were set and solved at different times, the branches for their solution grew from different versions on the release branch. The result is the versions /release_1.x/rec130_user3/1 and /release_1.x/rec131_user3/1, spaced from the version /release_1.x/3.
There are changes - it is necessary to combine them, stabilize and make the basic configuration, if everything is fine. For this purpose, a CM engineer, who runs under the operational alias user7 in the version control system, creates an integration branch that looks like int_ <user> _ <future-release-number> in this project. Therefore, the branch /release_1.x/int_user7_1.5 appears. Both deltas merge together on it. First, the changes for record 130, with the formation of the version /release_1.x/int_user7_1.5/1. Then - for recording 131, version 2 is created for it on the same branch. For all operations, merge arrows are drawn.
The final chord of the CM engineer is to merge the version /release_1.x/int_user7_1.5/2 onto the release branch to form the version /release_1.x/5. Subsequently, this branch will become part of the basic configuration of the product.
Here is such a rather big description of a small picture. One picture is worth hundreds of words - they say the truth.
An attentive reader probably has a question in his head - if everything is done through branches and merge arrows, where did the /release_1.x/2 version come from? After all, not a single arrow from any branch leads to it! Natural question. The answer is also natural. Yes, there are situations when changes are made directly to the release branch. For example, a terrible mistake was found, made with the first version - they forgot to make a comment in the revision history section about who made the changes! Of course, this is a joke, no one will violate politics for such trifles. However - and this happens. The main thing is to know exactly who created the new version and why he did it. Best of all, if the version control system allows you to limit the rights to create versions for each branch separately. In this case, we will additionally secure the project by that we will only give the CM engineer permission to add versions on the release branch. At least with a similar restriction it will be easier to find the last one :).
After the above, is it necessary to say that the ability to work with branches is actually the basic functionality of any mature version control system? Without branches, a version control system can be considered as such only from a formal point of view - simply because it can store and issue versions, but no more.
Tags
So, the version tree is growing, the team’s work is taking its course. There is a need to stabilize the results of work and determine the basic configuration, which at any moment any team member can take from the version control system. Stabilization is done by merging versions - this will be discussed below. But on the establishment of the basis we dwell in more detail.
Obtaining a basic configuration is essentially identifying a set of stable versions and determining how to uniquely identify them. For these purposes, version control systems have a “tagging” mechanism. A label is a alphanumeric designation that uniquely identifies a configuration. Having a label, you must always be able to accurately and unequivocally highlight the configuration.
In English sources, the terms label and tag are mainly used .
If the label is a designation for the configuration, then each version of the configuration must be uniquely identified by this label. Thus, the label will select the element in that version, which is marked as necessary.
The implementation of the concept of labels may vary across systems. In some (CVS to ClearCase), a label is an attribute of an element's version. For example, in diagram 2, the label would be hung directly on one of the versions, i.e. would be just a tag next to the circle. In other systems (Subversion), a label is understood to be just one of the varieties of branches. To each - his own, the main thing is that the invested meaning remains the same.
What else I would like to note: one configuration can be marked with several labels. For example, the components discussed in the first part of the article can be tagged with both component labels (to determine the basic configurations of components) and product labels in order to officially become part of the basic configuration of a product. It turns out that the basic configuration of each component is marked at least twice - once with a component label, the second with a product label.
In general, labels are a means of indicating configurations, so for the most part they are a tool for CM engineers. Developers only use the tags already made in order to regularly receive a basis for further work.
Total
It was shown above what basic functions any version control system has. How they are implemented in specific applications - everyone can see in the system that he personally uses.
Take a look at your tools again with an all-round look and compare with what is described.
By tradition - a list of recommended materials for independent thoughtful reading.
- en.wikipedia.org/wiki/Comparison_of_revision_control_software - a great comparison of existing version control systems
- www.cmcrossroads.com/bradapp/acme/branching is a good article on branch policies, many different branch patterns are considered that are suitable for different projects.
- www.infoq.com/articles/agile-version-control - an explanatory article on how to organize the growth of brunches and their merging using agile methods. Thanks sse for the link.
To complete the picture of the use of version control systems, it remains to talk about the distribution of this control between development teams located in different geographical locations. But more about that in the next note.
To be continued.
PS I publish in "Project Management", and not in "Version Control Systems", just to publish the entire cycle of notes in a uniform manner.