# Source: https://graphite-58cc94ce.mintlify.dev/docs/merge-pull-requests.md

## Documentation Index

> Fetch the complete documentation index at: https://graphite-58cc94ce.mintlify.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

## Merge Pull Requests

> Learn how to seamlessly merge a single PR or stack of PRs with Graphite and handle merge conflicts efficiently.

Merging a stack of PRs manually through GitHub can be time-consuming and involve a lot of context switching. You merge, rebase, wait for CI to pass, and merge again all the way up the stack—or you're forced to ditch the clean PRs you've carefully created, squashing your changes back into a single mega-PR for the sake of merge speed.

Graphite offers an automated solution that gives you the best of both worlds.

Once your PR is approved and passes CI (and any other checks or merge protections you've enabled in GitHub), you can merge it from Graphite. Just click the purple "Merge" button on the right side of the PR title bar.

## Merge a stack of PRs

Depending on which PR you are viewing in the stack, this button will behave differently:

* If you're on the first PR in the stack or are merging a stack of one, the `Merge` button will just merge that single PR.

* If you're in the middle of a stack, `Merge N` where `N` is your position in the stack and will merge all PRs up until the `N`th.

* If you're at the top of the stack, all PRs in the stack will be merged.

`Merge (N) PRs` lets you fire-and-forget merging your stack. When you click the button, Graphite automatically merges each of your PRs one-by-one.

This feature rebases PRs on an as-needed basis (to avoid merge conflicts generated by GitHub's lack of stack support). And it waits for GitHub checks to pass at each step of the way before merging.

<Tip>
  Not all PRs in the stack need to be accepted and passing checks to merge.

  For example, if only PRs 1, 2, and 3 in a stack of 5 have been accepted and are passing checks, you can still utilize `Merge all (n)` on PR 3 to merge those into trunk—just make sure you `gt sync` and `gt submit` the rest of your stack before merging again.
</Tip>

### Configure merge options

Clicking `merge` will first present you with a modal to configure your merge options before starting the merge job. In this merge modal, you have the option to:

* Select your preferred merge strategy. Graphite pre-fills with your default merge strategy from GitHub.

* Edit a custom commit title and message for your PR. Graphite will use your PR title and message as the commit title and message by default.

* Use your GitHub admin merge privileges to merge past blockers, if applicable. (Please note that admin merge is available only in repositories that do not use rulesets.)

A confirmation appears in the bottom left corner of the screen once your PR is merged.

<Tip>
  Make sure to run `gt sync` on the Graphite CLI immediately after merging a change to your remote trunk branch—this will zip through and delete your merged branches, ensuring that your local environment is up-to-date and ready for you to keep developing.
</Tip>

### Track the status of your merge on GitHub

Graphite will update a single comment on GitHub with the status of your PR's merge.

<Frame>
  <img src="https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png?fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=e257530741e7bbfc9249512a339c2275" data-og-width="1864" width="1864" data-og-height="394" height="394" data-path="images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png?w=280&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=b3563d4144a7842239c8c593c880cc15 280w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png?w=560&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=98eb8a861de981805ac987d5a9930abb 560w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png?w=840&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=94a5a290d902c6bd50364eb7da1f2f5b 840w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png?w=1100&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=8dacda550fc9304b60104cf202c790d6 1100w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png?w=1650&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=2787444d65e69a63f2b414df07aaac04 1650w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/1647e499-1695087134-screenshot-2023-09-18-at-9-31-59-pm.png?w=2500&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=3ebc9e99e4d335384dfdf7368b4df7b8 2500w" />
</Frame>

### Compatibility with GitHub branch protection rules

If you have the *dismiss stale pull request approvals when new commits are pushed* branch protection rule enabled for your repository on GitHub, you will **not** be able to successfully merge a stack with the Graphite UI. [See our documentation for configuring GitHub repository settings](https://graphite.com/docs/github-configuration-guidelines#required-settings) for more information and a workaround.

<Frame>
  <img src="https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png?fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=3fcb65eccff1e3dd906653929fa73568" data-og-width="1256" width="1256" data-og-height="118" height="118" data-path="images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png?w=280&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=afaab0a8a6e90d94e697090fc3d5a667 280w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png?w=560&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=d509670719f7eccc35b89b1a5f729130 560w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png?w=840&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=75d0d20432ccef1eba479a1e8302822e 840w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png?w=1100&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=7de864881e79bc284b38634698235382 1100w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png?w=1650&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=52c568970cbc5eadf20ea421745a8cf0 1650w, https://mintcdn.com/graphite-58cc94ce/vY1t0Vsr-LRJgMIn/images/28097070-1697120500-screenshot-2023-10-12-at-10-20-44-am.png?w=2500&fit=max&auto=format&n=vY1t0Vsr-LRJgMIn&q=85&s=978f7f93c779183a1f4c11fe077732e5 2500w" />
</Frame>

## Resolve merge conflicts

If `Merge (N)` fails due to a rebase conflict, go to your terminal and run `gt sync` && `gt restack` && `gt submit --stack` (resolving any conflicts along the way and running `gt continue`). Once you've done this, go back to the affected PR in Graphite (or to the same place in the stack where you initially kicked off the `Merge (N)` job), and click `Merge (N)` one more time to re-queue the PR for merging.

### Types of merge conflicts stack merge can resolve

When PRs are merged on GitHub using a squash and merge or a rebase and merge, GitHub [creates a commit/set of commits](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squashing-and-merging-a-long-running-branch) for those merged changes.

This means that if you have a stack with `PR A` at the base, followed by `PR B` and `PR C`, when `PR A` is merged into trunk:

* GitHub creates a commit or set of commits on trunk for the changes in `PR A`.

* Critically, because this is a new commit, the common ancestor of `PR B` and trunk does not change.

* As a result, GitHub thinks `PR B` now includes the commits of both `PR B` and the already-merged commits of `PR A`.

This behavior becomes problematic when you have a `PR A` and `PR B` that modify the same lines and you merge both PRs using one of the aforementioned merge strategies. For any `PR C` that is stacked atop `PR A` and `B`, the following transpires:

* The latest version of the change lines on trunk are those in `PR B`.

* GitHub believes that `PR C` contains the commits in `PR A` and `PR B`.

* When GitHub tests mergeability of `PR C`, it first tries to apply `PR A`—and now gets a merge conflict—even though in reality you're simply replaying history and there's no new change.

If you use the Graphite CLI, you'll notice that the CLI handles this scenario for you intelligently. When GitHub reports these sorts of merge conflicts, a `gt sync` will pull down the latest changes and rebase PR C for you, cutting out the problematic commits—and a subsequent re-submit will then eliminate the detected merge conflict for PR C.

`Merge (N)` is designed to similarly automatically resolve this type of merge conflict without the need for manual intervention or monitoring. When a merge conflict is found, the merge cron performs a shallow clone of the repository, containing just the stack commits and the trunk commit and utilizes Graphite's knowledge of the stack to perform the same set of operations.

<Warning>
  Graphite can't resolve any legitimate merge conflicts as a result of racing PRs on trunk that require human intervention. If a Graphite rebase fails, Graphite will cancel the merge job. You must restart the job by fixing the issue locally, re-submitting the PR, and enqueueing a new merge job.
</Warning>

## How a stack merge works

Each time the cron job processes a merge job it runs through the following decision tree:

* If the base PR in the stack has pending GitHub checks, do nothing.

* If the base PR in the stack is passing all GitHub checks and can be merged, merge. The next PR in the stack is now the new base PR.

* If the base PR in the stack has merge conflicts, rebase the PR and re-submit it (re-entering the waiting-for-CI phase).

During the merge process, Graphite prioritizes:

1. Speed of overall stack merge.

2. Minimizing the number of total CI runs.

To achieve these principles, it's important to note that:

* Graphite merges rather than rebasing each individual PR before merging.

* Graphite only rebases PRs lazily. When Graphite detects a merge conflict on a PR, Graphite only rebases that PR, and not the additional PRs further up the stack. This means that if a stack has `m` merge conflicts, there will only be `m` total rebases (and additional CI runs) kicked off by the merge process.

### Merge job duration

Graphite's cron job to process outstanding merge jobs runs at a cadence of once per minute.

As a result, the length of a merge job depends on how many PRs need to be rebased. If there are no merge conflicts, `Merge (N)` will take `n` minutes, but if there are merge conflicts, job time is a byproduct of the time it takes to run GitHub checks on a PR and how many PRs encounter merge conflicts.

## Compatibility with third-party merge queues

Today, merge stack supports label-based merge queues, with future plans to support GitHub's merge queue (currently not compatible).

## Automatic rebasing

<Tip>
  Graphite will automatically rebase your stacked PRs after you begin merging them — so you don’t have to. This results in temporary `graphite-base/*` branches that you can ignore
</Tip>

### Requirements

Graphite will automatically rebase your partially-merged stacks so long as you click `merge` from the Graphite app. **This feature does not work when merging from GitHub.**

### How it works

When you partially merge a stack of pull requests, Graphite runs a job that automatically rebases the remote branches corresponding to the PRs “upstack” of the one(s) you merged. This means there is never a moment where the new base of the stack points to a branch or pull request that no longer exists, so there’s no possibility of seeing an incorrect code diff.

This operation results in temporary `graphite-base/*` branches that lets Graphite retarget the rebased branches atomically -- ensuring your CODEOWNERS rules and GitHub Actions workflows don't misfire.

### Ignoring Graphite's temporary branches in your CI

You should configure your CI to ignore branches named `graphite-base/*` . Not doing so can result in unnecessary builds for these temporary branches and cancelled jobs when Graphite deletes these branches.

Here's how to disable running CI for these branches in GitHub Actions:

```yaml  theme={null}
on:
  pull_request:
    types: [opened, reopened, synchronize]
    branches-ignore:
      - "**/graphite-base/**"
```

### Troubleshooting

If your CI hasn't been configured to ignore Graphite's temporary branches yet, your CI job may fail due to an error looking like:

```bash
Fetching base branch: refs/heads/graphite-base/*
fatal: couldn't find remote ref refs/heads/graphite-base/*
```

The workaround is to trigger a fresh CI run on the PR. You can do this by:

* Running `gt sync && gt submit` (this will only work if `gt sync` fetches new commits from trunk and restacks the PR -- otherwise `gt submit` will be a no-op since there were no changes)
* Submitting a dummy change to the PR

The long-term fix to prevent this issue from appearing is [ignoring Graphite's temporary branches in your CI](https://graphite.com/docs/merge-pull-requests#ignoring-graphite%E2%80%99s-temporary-branches-in-your-ci).