Implementing simple workflows

There are many ways in which you can combine the various branch operations on the various branches, created by all the collaborators in a project. We will introduce two simple workflows suitable for small teams, which you can implement directly, or use as an example to design your own workflows when collaborating with others.

For simplicity, we will assume direct access between collaborator branches. In practice, you may have to work with remote mirrors of your collaborators' branches and use local mirrors for practical reasons. However, such technical details should not affect the main principles of the workflows.

Using independent personal branches

In this workflow, each collaborator has his or her own main personal branch that others can access in read-only mode—they can branch, merge, or pull from it, but cannot commit or push to it. Collaborators work on the project by committing their changes in their own branch, and by occasionally merging from the branches of others:

Using independent personal branches

This workflow can be suitable in very small teams with only a few members, especially in the beginning of a new project. As long as the team members merge from each other frequently, their main branches will be quite similar. Over time and as the team grows, a branch may emerge as the official, if its owner merges relatively more often from other team members, thus making the branch the most complete and up-to-date point of reference.

Merging from branches repeatedly

In this workflow, team members inevitably merge from each other's main branch repeatedly. This means that not only are there repeated merges from branchA to branchB, but at the same time there are also repeated merges in the other direction, from branchB to branchA:

Merging from branches repeatedly

In this example, there are two users, Jack and Mike, each working on a single branch, and occasionally merging from each other. The timeline of their actions is as follows:

Step no.

Jack's branch

Mike's branch

Summary after the step

1

Branched from branchX

Branched from branchX

The two branches are identical to each other and their common parent

2

Added new revisions

Added new revisions

The two branches have diverged

3

 

Merged from Jack

Jack's revisions are copied into Mike's branch

4

Merged from Mike

 

Mike's revisions are copied into Jack's branch, plus Mike's merge commit

The somewhat tricky part is what happens to "merges of merges" in step 4. In this step, Mike's branch contains all the changes of the project, including Jack's revisions. That is, when Jack performs the merge to get Mike's changes, the source branch contains his own changes too.

Bazaar handles this correctly, because in step 3 the merge operation records not just the changes in the content of the project's files, but also the unique revision IDs of the revisions by Jack. In this way, when merging from Mike's branch into Jack's branch in Step 4, Bazaar recognizes that the changes involved in Jack's revisions should not be re-applied.

Handling criss-cross merges

When two branches merge the same changes and then merge from one another, it results in a so-called "criss-cross" in the branch history. This can cause problems with the three-way merge algorithm, which is the default method in Bazaar to handle merges.

The principle of the three-way merge algorithm is finding a common base revision, in order to determine whether the differences in the two branches are due to one side adding lines or another side removing lines. In case of a criss-cross, there is no good choice for a base—selecting a recent merge point could cause one side's changes to be silently discarded, while selecting older merge points could cause more than necessary conflicts to be emitted.

The weave algorithm is not affected by this problem, because instead of using a base revision to detect the cause of differences, it uses so-called line-origin detection.

If you encounter too many conflicts with the three-way merge, it can be a good idea to redo the merge on selected files or the entire project using the bzr remerge command using the --weave flag.

For more details on how the weave algorithm works, refer to the following pages in the Bazaar documentation, and on Wikipedia:

Viewing the history from different perspectives

It is important to keep in mind that Bazaar shows the revision history from the perspective of the current branch. In other words, each collaborator in this workflow will see the history differently. For example, Mike sees the history as follows:

Viewing the history from different perspectives

While Jack sees the history as follows:

Viewing the history from different perspectives

In this example, both the branches have exactly the same content in terms of project files, but their view of the history is different. This is because Bazaar uses increasing integer revision numbers for commits in the current branch, and renames merged revisions using a dotted notation.

Also note that at this point, Jack's branch contains all the revisions of Mike's branch, but the converse is not true—revision 5 in Jack's branch does not exist in Mike's branch. The last branch that merged the other branch, will always have one revision not in the other branch—the revision that committed the merge.

At this point, Mike can pull from Jack to make the two branches identical. As a result, both branches will have Mike's perspective of the revision history. It might be a good idea to pull from each other whenever possible instead of a merge, as that would reduce the number of criss-crosses in the branch history.

Using feature branches and a common trunk

In this workflow, collaborators do all their work on dedicated feature branches. When a feature branch is completed, its owner or another team member merges it into the common trunk. For simplicity, we will assume that the common trunk is available at a central location, and all collaborators have write access to it by push operations.

Using feature branches and a common trunk

This workflow can be suitable in small- to medium-sized teams, because it is not complicated to implement, and the common trunk helps in keeping the project organized.

The workflow has several interesting features:

  • The official latest version of the project can be clearly identified as the common trunk
  • It enforces the good practice of using feature branches
  • It facilitates the good practice of "code reviews"

Merging into a common remote trunk

Since merge operations can only be applied to local branches, collaborators must keep a local mirror of the common trunk. Merging a feature branch can be performed by the following steps:

  1. Create or update a local mirror
  2. Merge from the feature branch into the local mirror
  3. Test the improvements well and commit the merge
  4. Push from the local mirror to the common remote trunk
Merging into a common remote trunk

Use the branch command when creating the local mirrors for the first time, or to recreate a pristine copy. Use the pull command to update an existing local mirror that may be out of date. If you have inadvertently changed the local branch, use the --overwrite flag with the pull command to restore its pristine state.

If the feature branch is not your own but a remote branch created by another team member, then instead of merging from it directly, it is often more practical to create a local mirror branch from it first and use that branch instead. In this way, you can run multiple branch operations on it without any data transfers over the network. For example, you may want to inspect it using the bzr missing, bzr log, and bzr diff commands, or retry the merge using different algorithms.

Before committing the merge, make sure to test the improvements well, and look for any possible regressions. If there are any problems, you may want to ask for help from the author of the changes, or ask to fix bugs first and abort the merge for now.

Finally, push the branch to the common remote trunk to make it available to your team.

Merging feature branches in lock-step

Although multiple users may have write access to the same common trunk, simultaneous write operations are not possible. If two team members try to push their two different branches at the same time, only the first will succeed. After the first push succeeds, the second will fail, because the common trunk at the remote location, and its local mirror have diverged.

The cleanest solution is to create a new local branch based upon the updated common trunk, and repeat the merge.

Alternatively, if you prefer to reuse the local mirror and don't mind throwing away the merge, then you can use the pull command with the --overwrite flag. This will discard the merge, and fetch the new revisions from the common trunk, restoring it to its pristine mirror state.

Doing "code reviews"

Although the term "code review" is used in software development, its meaning is essentially the same as "peer review", and can be applied in other kind of projects as well. The idea is to review the work done by another team member in order to find and fix the mistakes that may have been overlooked.

When using code reviews, team members never merge their own branches into the common trunk, but ask another member to do it. When performing the merge, the reviewer should review the differences carefully before committing the merge. If there are problems in the branch or room for improvement, the reviewer can either fix the problems by committing new revisions, or abort the merge and ask the original author to fix the problems and ask for a review again.

Code reviews can greatly improve the quality of a project. It also helps to spread awareness of the new changes going into the project, ensuring that there are always at least two members who understand the meaning behind a change.

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

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