Task Branch
You need place work that facilitates the use of feedback mechanisms such as testing and Code Review to help you merge with confidence so that you can have consistently working code on the Main Line. 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.
Balancing Isolation and Collaboration
A typical development workflow includes the following steps:
- Pulling the current state of the code from the Main Line.
- Making changes to the code.
- Getting feedback on the change from team members and/or tools
- Merging the work into the _Main Line.
It’s typical to code and test in your private workspace before sharing your changes with the rest of the team. Unless you work in a communal workspace (which would be challenging), there is always a period of time when your changes are isolated from the Main Line. While this means that your work isn’t always up to date, having no isolation can become chaotic as the number of contributors increases.
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.
![](taskBranch-workspace-branch.png height=“1.5 in”)
There are a few options for managing this isolated work stream. Each option differs in:
- How visible it is to other team members
- The ability to use the mechanisms of your version management system to have more freedom to experiment.
- How much you can leverage your shared CI workflow.
A good solution will allow you 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.
Some of the ways you can manage the code in your workspace before integrating with the Main Line are:
- Push directly to the Main Line from your workspace.
- Create a branch locally that you don’t push, and push the 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).
A good solution will allow you 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 steps during the coding process. Some of the disadvantages of this approach are:
- Limited ability to get feedback using the tools available in a Continuous Integration Environment before you merge
- Making it more complicated to get input from team members who are not co-located (temporally or geographically) because your work-in-progress code is invisible to other team members
- An increased possibility of losing work in progress due to the lack of version and tooling support in a shared repository
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 issues regarding lack of transparency and tooling support workspace-only approach.
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 a Continuous Integration Environment, opening up more potential for automation, information sharing, and collaboration without the right expectations. However, working on a branch can encourage slower, asynchronous interactions.
![Task Branch Forces](task-branch-context-forces.png height=“1.5 in”)
Using branches can cause problems when teams encourage working on a long-lived branch—such as a Feature Branch—until work is complete. While this seems to offer some superficial advantages, especially if the work is isolated from the rest of the code base, the cost of a longer gap between integration easily outweighs any potential advantage. The longer the delay, the higher the risk of merge conflicts and errors.
![](taskBranch-branchedBased-workflow.png height=“1.5 in”)
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 depends on the developer’s skill and speed, and the task size
- Time between work being complete and merging
- This depends on the dynamics of the feedback cycle
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. The branch ends when the task is merged. The meaning of “Merging quickly” can vary by team, but 1 day is a good target.
A Task Branch enables a developer to:
- Have a backing store for work in a workspace related to a Small Development Task.
- Maintain flow.
- Experiment
- Obtain Feedback
Using short-lived Task Branches is consistent with rapid integration to a Main Line. In Accelerate {Forsgren et al., 2018 #92987} the authors say:
Following our principle of working in small batches and building quality in, high- performing teams keep branches short-lived (less than one day’s work) and integrate them into trunk/master frequently.
A “Task,” which is described in more detail in Small Development Task can be a User Story {Cohn, 2004 #260909} or an intermediate step for a user story. The main attribute is that it is a small, coherent unit of work. Small can vary by team, but a typical goal is to be able to integrate at least daily.
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.
Example
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.
- Delete the Task Branch
The goal is to integrate the work into the _Main Line_quickly.
Cautions
Don’t confuse a Task Branch with a Feature Branch. A Task Branch is shorter and allows for incremental work. A Feature Branch often represents a larger unit of work that survives until the “feature” is complete, at which point the code merges to the Main Line. Feature branching is rarely a useful pattern to follow; use Task Branches for any work in progress.
Individuals and teams should minimize the number of active task branches {Forsgren et al., 2018 #92987}:
Our research also found that developing off trunk/master rather than on long-lived feature branches was correlated with higher delivery performance. Teams that did well had fewer than three active branches at any time, their branches had very short lifetimes (less than a day) before being merged into trunk and never had “code freeze” or stabilization periods.
Be mindful of:
- Merge Conflicts: To minimize the risk of merge conflicts causing delays at the end, pull from the Main Line periodically to simplify later merges and identify possible design divergence early.
- Task Branches that last a long time. Gather data (either metrics or heuristics) to identify when Task Branches take a long time to merge. Discuss these at Retrospective to evaluate if the long branches were problematic and, if so, how to fix the underlying issues.
- Overly restrictive Codeline Policies for the mainline that require a slow Code Review process.
Using a Task Branch can make these problems more obvious (since the SCM tooling makes the parallel work stream visible), but that doesn’t mean that the branching policy is the cause of the problem. These issues can also manifest when doing a no-branch directly from the workspace workflow. The causes of long integration times are often related to problems external to the code line flow, such as planning and prioritization.
Aside: Branch Reuse
One approach to balancing the overhead of branch creation with frequent integration is to create one branch for a larger task, but merge multiple times during the branch’s lifetime. If your policy if to delete the (remote) branch after a merge, this is conceptually the same as multiple task branches. The team should decide if there is any value to creating uniquely named branches for each merge. It’s conceptually simpler to think of each merge are coming from a new branch.
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.
References
- Cohn, Mike. 2004. User Stories Applied: For Agile Software Development. Boston: Addison-Wesley.
- Forsgren, Nicole, Jez Humble, and Gene Kim. 2018. Accelerate: The Science Behind Devops: Building and Scaling High Performing Technology Organizations. Portland, Oregon: IT Revolution.