Continuing from Main Line
Note there is an Updated Version of this Pattern
Task Branch
You want consistently working code on the Main Line. You need a place to do work where you can use feedback mechanisms such as testing and Code Review to help you merge with confidence. This pattern describes a codeline structure that enables your team to work in parallel to deliver multiple changes to the Main Line quickly while preserving the integrity of the Main Line and maintaining focus.
A typical development workflow includes the following steps:
Pulling the current state of the code from the Main Line.
Making changes to the code.
Making sure the change does what you expect and has a minimal risk of introducing an error into the Main Line
Merging the work into the Main Line.
A typical pattern is to code and test with some degree of isolation before sharing your changes with the rest of the team. Unless you are working in a shared workspace with all of the other developers on your team, there is always a period of time when your changes are in a separate workstream from the Main Line. While divergent work streams add overhead and delay integration, having no isolation can become chaotic as the number of contributors increases.
When working in a workspace, you need to decide how to organize the work. Some options are:
Push directly to the Main Line from your workspace.
Create a branch locally that you don’t push, and push the end result to the Main Line
Create a branch for your work and push it to the shared repository. When complete, merge this branch to the Main Line (directly or via a Pull Request mechanism).
In all cases, you have an isolated workstream; the difference is how visible it is to other team members and how much you can leverage your shared CI workflow. The challenge is to work in a way that yields the benefits of (brief) isolation while minimizing the time until the code is merged into the Main Line.
A workspace without a backing branch is straightforward to manage because it requires fewer interactions with the SCM tool. However, you cannot easily track incremental steps during the coding process. For this simplicity, you also trade off the ability to get feedback using the tools available in a Continuous Integration Environment before you merge, which makes it slightly more complicated to get feedback from team members who are not co-located (temporally or geographically). Your code is invisible to other team members. This lack of version and tooling support might encourage smaller units of work — out of fear of losing work in progress, but there are other ways to achieve the small units of work goal,
A workspace with a local branch lets you track changes locally and experiment easily (see the Private Versions Pattern from SCM Patterns). However, this approach has the same lack of transparency and tooling support issues as the workspace-only approach.
A workspace, with or without a local branch, is a parallel work stream, much like a shared branch, but without the transparency and automation support branching enables.
Using a branch, you can collaborate on a feature with other developers and get the advantage of quickly testing the code in the branch in the context of a Continuous Integration Environment, but at the cost of some added complexity. A shared branch also makes the possibility of a larger unit of work more appealing— more people can potentially collaborate and give feedback. This can add complexity to the process and can slow integration.
While a branch opens up more potential for automation, information sharing, and collaboration without the right expectations, working on a branch can encourage asynchronous and slower interactions. Working on a long-lived branch—such as a Feature Branch—until work is complete seems to offer some advantages, especially if the work is isolated from the rest of the code base, but the advantages can be outweighed by the cost of a longer the gap between integrations. The longer the delay, the higher the risk of merge conflicts and errors.
In all cases, you want to enable collaboration and reliable testing while also working to minimize the length of time between starting work and merging, which includes:
Time between work starting and code being completed.
This is dependent on the developer’s skill, rate of work, and size of the task
Time between work being complete and merging
This is dependent on the dynamics of the feedback cycle
You want to avoid long-lived streams of unintegrated work.
Branch for Tasks, Merging Quickly
For each development task, work off a Task Branch. A Task Branch represents a small coherent unit of work that can be done reasonably quickly. Merge into the Main Line as quickly as possible
A Task Branch starts from the Mainline. Its purpose is to provide a backing store for work—typically by one developer or a pair—in a workspace related to a Small Development Task. This branch ends when the task is merged.
A Task Branch enables a developer to:
Maintain flow.
Experiment
Obtain Feedback
A “Task” can be a user Story or an intermediate step for a user story. The main attribute is that it is a small, coherent unit of work. What this means can vary by team and project, but some guidelines are:
Length of work: about a day or less.
Longer opens you to the risks of the conflict issues we describe above
Shorter means more overhead for working on each of the branches, though this overhead can be minimized, and there are benefits to multiple smaller commits during work.
Coherence: Something that will add some incremental value, which can be tested or demonstrated, if only with a unit test.
If the work on the task branch could be exposed to an end user before it is fully usable, consider mechanisms to hide it in a production context until it is fully complete.
Structure and Workflow
A Task Branch follows a familiar workflow:
Check out the Main Line
Create a Task Branch
Make code changes, including tests. This can include multiple commits
Push changes to the shared repository periodically.
Get feedback.
Merge the completed work.
The key goal is to integrate the work into the Main Linequickly.
Cautions
Don’t confuse a Task Branch with a Feature Branch. A Task Branch is shorter and allows for incremental work. A Feature Branch (rarely a useful pattern to follow) often represents a larger unit of work that survives until the “feature” is complete, at which point the code merges to the main line.
Be mindful of:
Merge Conflicts: To minimize the risk of merge conflicts causing delays at the end, pull from the Main Lineperiodically, at reasonable points, to simplify later merges and identify possible design divergence early.
Task Branches that last a long time. Gather data (either metrics or heuristics discussed at a Retrospective) to identify when Task Branches take a long time to merge,
Overly restrictive Codeline Policies for the mainline that require a slow Code Review process.
Note that while using a Task Branch can make these issues more obvious (since the SCM tooling makes the parallel work stream visible), they can also manifest themselves when doing a no-branch direct from the workspace. The issues that result in long times to integration are often due to underlying issues beyond tool use.
Next Steps
To integrate a task branch quickly while minimizing the risk of errors, you need to:
Ensure that tasks are the right size to complete quickly and well-defined enough to know when they are done. Identify Small Development Tasks that support completing work quickly.
Have a Code Review process to support shared understanding and identify likely errors.
Use an Integration Build in a CI environment to ensure that a consistent set of checks is run on the code.
Getting to Task Branch from Feature Branching
Using a Task Branch model approach is mostly a matter of identifying units of work that can be completed quickly and building processes and styles that encourage quick collaboration and integration. If you are currently in the habit of using long-lived feature branches:
Consider the estimated duration of the task before branching; aim for work that can be completed in a day or less.
Track (with tools or in an ad-hoc fashion) how long a branch takes to merge
At Retrospectives, discuss time-to-integration and what changes you need to make to speed up the process.
The rest of the pattern language provides more details about how to do this.