Check us out on Product Hunt! Use code PH15 for 15% off Graphite Team 🚀

Introduction to Graphite

Graphite is a simple code review platform designed for engineers to write and review smaller pull requests, stay unblocked, and ship faster. Graphite was inspired by code review tools like Phabricator at Facebook and Critique at Google.

The Graphite workflow follows three main principles to enhance your normal git workflow:

  1. Keep your pull requests small

  2. Sync your trunk branch with remote, and restack (rebase) your working branches frequently

  3. Use one commit per branch


Note

Ready to start building? Check out the quick start, which walks you through initializing Graphite in a GitHub repo, all the way to merging a stack in the app.


Keep PRs small

Graphite promotes a trunk-based development workflow, where developers break their changes into small PRs. In this workflow, you frequently rebase your changes onto your trunk branch (this is also known as main or the branch that has the most activity in your repository), and each of your changes is usually dependent on the last.

Let's say you're an engineer at a big tech company called Flipstagram. You’re tasked with creating Flipstagram's Stories feature, which requires API, server, and frontend changes.

Flipstagram has thousands of engineers, all working in the same codebase with updates to Flipstagram's trunk branch every few seconds.

To build Stories, you may think to create a feature branch—but these often go stale and lead to messy merge conflicts and extremely long review cycles. You typically have to send a monster PR to multiple reviewers, or ask one person without all of the necessary knowledge and context to review all your changes.

But with stacking and trunk-based development, you can send modular PRs to relevant reviewers, leading to faster review times. Graphite offers first-class support for stacking with a CLI and web app that’s fully interoperable with GitHub. In order to start stacking, you're encouraged to follow a trunk-based workflow, rather than a long-lived feature branch workflow.


Note

We explicitly designed Graphite so you can use our CLI and web app without the rest of your team having to change their tools or workflows—we'll seamlessly sync your code changes and reviews back to GitHub.


Sync with remote and restack frequently

Following a trunk-based style means you frequently rebase your changes onto your trunk branch, and each of your changes is usually dependent on the last.

In the case of Flipstagram, you would:

  • Branch off of main and create a branch with your API changes

  • Then branch off of the API changes and create your server additions

  • Create a branch based off of the server changes with all of your frontend work

This flow makes your PRs small and self-contained, producing a stack with three independent changes. By frequently rebasing onto main, you can more easily manage (and avoid) merge conflicts.

Since your changes across all three surfaces are separate PRs, you can request separate, more suitable reviewers for each. And while awaiting feedback, you can continue to stack changes and submit them for review. You're no longer blocked on merging all of your changes into main before iterating on the feature.

Use one commit per branch

The Graphite CLI use branches instead of commits to represent atomic changes in a stack. And your standard git workflow still works with Graphite. Fundamentally, each gt (Graphite’s CLI) command is executing a series of git commands under the hood. We've created a series of command combinations and flags that allow you to accomplish 3–4 git commands with just one gt command—which is why we strongly recommend that you follow this flow when creating a new branch in gt (which diverges from the GitHub mental model):

  1. Start by building your feature on an existing branch: do NOT create a new branch before working on your feature as you would in GitHub.

  2. Add your unstaged changes with gt add.

  3. Create a new branch and commit your changes simultaneously with gt branch create -m <COMMIT-MESSAGE>.

Managing a stack of changes

A stack is essentially a DAG, and you can see this by running any of the gt log commands. With Graphite, you'll frequently jump between branches in your stack as you make updates. You may also decide to do things like split your branch into multiple smaller branches, fold two or more branches into one, or shuffle the order of the branches in your stack entirely.



Let's take a look at what the Flipstagram Stories stack looks like right now:

# view your current stacks as tracked by Graphite
> gt log
# output
◉ feat-stories-frontend (current)
│ 8 seconds ago
│ 95338df - Stories - front end [3/3]
◯ feat-stories-server
│ 8 seconds ago
│ 95610c6 - Stories - server [2/3]
◯ feat-stories-api
│ 10 minutes ago
│ 48cd85e - Stories - API [1/3]
◯ main
│ 11 minutes ago

From here, you can see what your current position is in the stack (indicated by the (current) flag near the branch name, as well as the filled-in node).

Automatically rebase branches after changes

Many gt commands take the pain out of rebasing, which we refer to as restacking, since we’re “restacking” each of our branches on top of each other and resolving merge conflicts as we go.

Going back to Flipstagram, let's say a teammate pushed some new icons to main that you want access to when editing the frontend of your app:

# syncing changes from main
> gt sync
# output
🌲 Pulling main from remote...
main fast-forwarded to 818b7181eca9bb31f1578e22c5d4522ebe480c91.
# checking the state of our stack again
> gt log
◉ feat-stories-frontend (needs restack)
8 seconds ago
│ 95338df - Stories - front end [3/3]
◯ feat-stories-server (needs restack)
8 seconds ago
│ 95610c6 - Stories - server [2/3]
◯ feat-stories-api (needs restack)
10 minutes ago
│ 48cd85e - Stories - API [1/3]
◯ main
│ just now
|
│ 818b718 - adding support for new stories icons
|

Notice that each of the branches in this stack now says (needs restack), since gt has detected that the parent branch has updates that aren't yet reflected. We can fix this by doing the following:

# restacking changes on main
> gt restack
# output
Restacked feat-stories-api on main.
Restacked feat-stories-server on feat-stories-api.
Restacked feat-stories-fronted on feat-stories-server.
# checking the state of our stack one more time
> gt log
◉ feat-stories-frontend (current)
│ just now
│ 95338df - Stories - front end [3/3]
◯ feat-stories-server
│ just now
│ 95610c6 - Stories - server [2/3]
◯ feat-stories-api
│ just now
│ 48cd85e - Stories - API [1/3]
◯ main
1 minute ago
|
│ 818b718 - adding support for new stories icons
|

If needed, gt will prompt you to resolve merge conflicts with any of these branches and the new additions to main. Otherwise, the branches have successfully been restacked and you're ready to implement the new icons in your frontend.

Using gt means you can push all of these changes to GitHub at once.

You can also review and merge PRs directly from the Graphite app. Unlike GitHub, Graphite's review interface is stack-friendly, and makes reviewing and submitting stacks extremely easy. When viewing the top-most PR in a stack, you'll see a button that prompts you to Merge 3 PRs—and Graphite will take care of the rebasing portion of the merge for you.

Each PR in Graphite has an equivalent page in GitHub, so regardless of which platform your reviewers are on, they can still see all of your changes. To give GitHub reviewers more context, whenever you push a stack of PRs to GitHub, Graphite automatically adds a comment to every PR in the stack to help your reviewers navigate between them as you would in the Graphite app: