Develop on multiple trunk branches
Learn how to develop against multiple trunk branches with the Graphite CLI.

Some codebases don't have a single trunk branch (e.g. all commits go to main), but rather multiple longer-lived trunk branches. Some reasons for this workflow may be release/deploy branches, long-lived feature branches, or staging branches. In these setups, creating branches and PRs off the correct trunk branch is critical for many reasons:

  • Developing: The output of gt ls will be clearer, e.g. running gt ls on main will show stacks based on main.

  • Reviewing: Requirements like CI status will be evaluated against the trunk branch's branch protection rules on Graphite's PR page. This is especially useful for upstack PR's, where Graphite evaluates requirements like CI against trunk.

  • Merging: Graphite's "merge all" feature for stacks will merge down to the correct trunk branch.

    • Note: Merge when ready is only supported for merges into the default branch of your repo. Make sure you are enabling merge when ready only for PRs that you intend to merge into the default branch.

The guide below shows you how to use Graphite for such projects.

Your CLI version should be >= 1.4.0. If you are on a lower version, update your CLI version to get the latest first-class support for multitrunk workflows.

You should be familiar with how to:

The trunk branch is the root of your stack that you open PRs against and eventually merge into. When you first initialize the CLI in a repo, Graphite will ask you to select a trunk branch. In the following tree, main is the trunk and all the stacks are based off it. Each branch has a single dependency so each stack can only have a single trunk.

Terminal
◯ bug-fix
│ ◯ feature1-frontend
│ ◯ feature1-backend
◉─┘ main

In order to create a PR off a different trunk branch, you need to configure the branch you want to base off of as another trunk. Then you can check out that other trunk branch and create new branches off it. When you submit PRs for the branches based off other trunks, they will be based off these other trunks. The Graphite workflow is the same across trunks and Graphite now makes working with multiple trunks easy.

For example, say you had a release branch release-v10 that you needed to merge a bug fix into. You would first need to add release-v10 as a trunk branch. Then you can checkout the new trunk with gt checkout release-v10. Once you've implemented your fix, you can use gt create to create a branch for it in the same way as any other branch. You can then submit a PR for the bug fix which will open a PR against the trunk release-v10. Your state will now look like the following:

Terminal
◯ bug-fix-1
│ ◯ feature1-frontend
│ ◯ feature1-backend
◯─┘ main
◉ bug-fix-2
◯ release-v10

To switch back to working off of main, simply checkout main again with gt checkout main. Graphite supports easily switching between branches, even across trunks.

The next sections go into detail about how to add additional trunks and work with multiple trunks.

When you first initialize the CLI in a repo, Graphite will ask you to select a trunk branch.

Terminal
Welcome to Graphite!
? Select a trunk branch, which you base branches on - inferred trunk main (autocomplete or arrow keys)
❯ main
release-v10
green

After initial set up, you can then interactively configure what trunk branches you have configured via gt config:

Run gt config:

shell
gt config

Select Repository-level settings then Trunk branches:

Terminal
? What would you like to configure? › - Use arrow-keys. Return to submit.
❯ Repository-level settings
Branch naming settings
Submit settings
Restack settings
Default utilities
Tips
Yubikey reminders
Exit
Terminal
? Repo-level configuration › - Use arrow-keys. Return to submit.
❯ Trunk branches
PR Templates
Remote repository
Back
Exit

See your currently configured trunk branches, and the different options for configuring trunk branches:

Terminal
? Configured trunks:
main
release-v10
› - Use arrow-keys. Return to submit.
❯ Add additional trunk branch
Remove configured trunk
Configure a target trunk to open PRs against
Back
Exit

From the interactive menu, select Add additional trunk branch:

Terminal
? Configured trunks:
main
release-v10
› - Use arrow-keys. Return to submit.
❯ Add additional trunk branch
Remove configured trunk
Configure a target trunk to open PRs against
Back
Exit

Select the branch you want to configure as a trunk:

Terminal
? Select a trunk branch, which you base branches on (autocomplete or arrow keys)
main
develop
❯ release-v10

Note that removing a configured trunk may un-track all branches based locally on this trunk.

From the interactive menu, select Remove configured trunk:

Terminal
? Configured trunks:
main
release-v10
› - Use arrow-keys. Return to submit.
Add additional trunk branch
❯ Remove configured trunk
Configure a target trunk to open PRs against
Back
Exit

Select the configured trunk you would like to remove:

Terminal
? Which configured trunk would you like to remove? ›
❯ main
deploys

This is a not a common workflow and usually only used in workflows where you work off a branch locally (i.e. green) that is strictly a descendant of the branch they merge into (i.e. main). Targeting a different branch on remote than the one you have locally can otherwise have unknown consequences in the Graphite CLI.

By using this setup, you are choosing to open PRs against a different trunk than the one you work on locally. This means that you can base your branches off green locally and have all PRs submitted through Graphite open PRs against another branch, main.

From the interactive menu, select Configure a target trunk to open PRs against:

Terminal
? Configured trunks:
main
release-v10
› - Use arrow-keys. Return to submit.
Add additional trunk branch
Remove configured trunk
❯ Configure a target trunk to open PRs against
Back
Exit

Select the local trunk you would like to set a target trunk for:

Terminal
WARNING: You are about to configure Graphite to open PRs against a different remote branch than the one you are based on locally.
WARNING: This is an uncommon workflow since most users develop locally based off the same branch they are merging PRs into.
WARNING: This workflow is only recommended if your local branch is a descendant of the remote target.
? Which configured trunk would you like to set a target trunk for? ›
❯ green
release-v10

Select the remote branch you would like to open PRs against on remote (by default, Graphite opens PRs against the same trunk you have set locally):

Terminal
? For branches based on main, which remote branch should Graphite open PRs against?
By default, PRs will be opened against main on remote. ›
green (default)
❯ main
release-v10

By default, all Graphite commands assume you are working off a single trunk. For times when you want to do things across multiple trunks, some commands have a --all flag to see/perform actions across all configured trunks. Everything else should work normally.

gt trunk will print out the trunk your current branch is based off of:

Terminal
> gt trunk
main

gt trunk --all will print out all your configured trunks:

Terminal
> gt trunk --all
main
deploys

gt log [short] will show you your stacks on your current trunk:

Terminal
> gt log short
◉ bug-fix
│ ◯ feature1-frontend
│ ◯ feature1-backend
◯─┘ main

gt log [short] --all will show you all your stacks across all your configured trunks:

Terminal
> gt log short --all
◉ bug-fix-1
│ ◯ feature1-frontend
│ ◯ feature1-backend
◯─┘ main
◯ bug-fix-2
│ ◯ bug-fix-3
◯─┘ release-v10

gt checkout {branch_name} will work with any Graphite tracked branch, regardless of the trunk it is based off of.

In the interactive selector, gt checkout will by-default only show you options based off your current trunk.

Terminal
> gt checkout
? Checkout a branch (autocomplete or arrow keys)
❯ ◯ bug-fix-1
│ ◯ feature1-frontend
│ ◯ feature1-backend
◯─┘ main

Add the --all flag to see all branches across all configured trunks.

gt checkout --all:

Terminal
> gt checkout --all
? Checkout a branch (autocomplete or arrow keys)
❯ ◯ bug-fix-1
│ ◯ feature1-frontend
│ ◯ feature1-backend
◯─┘ main (trunk)
◯ bug-fix-2
│ ◯ bug-fix-3
◯─┘ release-v10 (trunk)

Similar to checkout, gt move --onto {branch_name} will work with any Graphite tracked branch, regardless of the trunk it is based off of. Add the --all flag to see all branches across all configured trunks.

By default, gt sync will only update the trunk you are currently based off of and sync branches based off this current trunk. To update all your trunks and sync branches based off all your trunks at once, pass the --all flag.

PR is targeting the wrong trunk. You can fix this by simply moving the branch onto the correct trunk: gt move --onto {trunk}. After that, you can submit your stack to reflect the changes remotely. Learn more about tracking branches with gt track.

Before 1.4.0, Graphite only supported working off a single trunk at a time. So to switch trunk branches, you had to re-initialize the CLI with a different trunk every time you needed to switch which trunk you were working off of:

Terminal
gt init --trunk <trunk-name>

There was no real support for working on multiple trunks simultaneously.

Graphite
Git stacked on GitHub

Stacked pull requests are easier to read, easier to write, and easier to manage.
Teams that stack ship better software, faster.

Or install our CLI.
Product Screenshot 1
Product Screenshot 2