GitButler Logo
Features

Stacked Branches

Create a queue of dependent branches to be reviewed and merged in order.

Overview

GitButler allows you to create an ordered stack of branches where each branch depends on (and is based on) the previous one. The application also supports creating the appropriate stacked Pull Requests (when used with a GitHub remote). This is useful when you have multiple changesets that depend on each other but it is desirable to have them reviewed and merged separately (and in sequence).

All of the Pull Request stack orchestration is done locally in the client, which means that your repo content is not shared with a cloud service.

Use cases

Using stacked branches (Pull Requests) can be helpful for shipping smaller changes changes more frequently.

Breaking up a larger change into smaller ones

Consider a scenario where you are implementing a medium/large feature in your software project. In the course of implementation you end up performing the following sub-tasks:

  1. Refactor a part of the codebase to accommodate the new feature
  2. Implement an API endpoint supporting the feature
  3. Implement the frontend part of the feature consuming the API

While the feature is considered complete only when all of the subtasks are implemented, reviewed and merged, in many cases it is considered beneficial to ship each stage of the feature on it's own, potentially behind a feature flag. Not only the risk of merge conflicts with colleagues is reduced, but also eventual bugs are easier to track down / revert / fix as compared to a single large change.

More granular (easier) review process

On GitHub at least, code reviews are performed on per-branch basis. While it is possible to view individual commits in a Pull Request, it is not possible to approve and merge a subset of commits from the PR.

Utilizing stacked pull requests, means that the sub-tasks of a larger change are in their own PRs. This way it is possible to approve and merge the initial part of a stack (e.g. a refactor) while still iterating on the remaining sub-tasks.

Comparison to Virtual Branches

Stacking and Virtual Branches are similar in that they allow you to separate code changes / commits into different branches. In both cases, the changes are available in your working directory.

The main difference is that Virtual Branches are independent from one another, while stacked branches depend on the branch that precedes it. Because of this, the two features are not mutually exclusive but rather complementary. For example a bugfix change that is unrelated to a feature being developed can be put in a separate virtual branch. On the other hand a change that depends on a previous change can be put in a stacked branch above the one it depends on.

In fact GitButler implements stacked branches as Virtual Branches that are split into multiple dependent branches which makes for a flexible workflow.

Workflow

By default, virtual branches in the app are simply stacks of one. With version 0.14.0 or newer you can create a new dependent branch within a lance with the + button above the branch name.

The workflow below assumes a GitHub remote. If you are using a different forge, you can still use this functionality but will need to manually create/update the Pull/Merge Requests

  • Creating a new dependent branch forms a new stack within the virtual branch
  • New commits land in the topmost branch of the stack
  • Pushing is done for the stack as a whole
  • Pull request creation has to be done from the bottom of the stack upwards
  • The PRs will contain a footer with stack information and as you add more PRs it will keep all up to date
  • You can drag changes into commits to amend them (e.g. incorporating review feedback)
  • You can drag commits between the branches in the stack
  • If a change in your stack is independent (e.g. an unrelated bugfix) it can be moved to a different virtual branch (or stack1)
  • Review/merge your PRs starting from the bottom up
  • After a PR/branch from your stack has been merged, it is reflected in the Stack
  • When all branches of a stack have been merged, the stack is complete

GitHub configuration for stacked PRs

TLDR:

  1. Enable automatic branch deletion automatic branch deletion on GitHub
  2. If possible, consider using the the "Merge" strategy when merging PRs.

Automatic branch deletion

On GitHub, in the "Files changed" and "Commits" tabs of a PR that is part of a stack you will see only the changes that are part of that branch in the stack. However, in pure Git terms, a stacked branch will contain all the changes from the branches below it.

In order to show the 'expected' diffs each PR is created to target the branch below it in the stack. This is true for all but the bottom-most branch in the stack, which targets the default branch of the repository as usual. //: # "TODO: Screenshot of both"

Every branch in the stack contains the commits from the branches below it.

When the bottom-most branch is merged on GitHub, if the PR branch is deleted, GitHub will automatically update any PR that used to target it to target the default branch instead.

For this reason it is highly recommended to enable on GitHub the automatic deletion of branches after merging.

NB: If you merge the first PR but the branch is not deleted and then merge the second PR, the app can still recover from this, see Troubleshooting.

Merge strategy

The app will support any merge strategy you wish to use - "Merge", "Rebase" or "Squash". However, due to the nature of merge, the GitButler will be able to create a slightly better experience if the "Merge" strategy is used.

Troubleshooting

Firstly, if you run into any issue with the app (stacking or not), you can always reach get in touch either on Discord or via the in-app feedback feature. With that said, here are some workarounds for common issues.

Accidentally merged a stack branch into an already merged branch before it

Accidentally merged a branch into a branch before it (not integrated into main/master yet)

Last updated on

On this page

Edit on GitHubGive us feedback