@withgraphite/graphite-cli 1.6.5 → 1.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.CHANGELOG.md +13 -0
- package/build/asset-manifest.json +9 -9
- package/build/index.html +1 -1
- package/build/static/css/{274.74a3708d.chunk.css → 603.b5b455ea.chunk.css} +1 -1
- package/build/static/css/main.18f97c48.css +2 -0
- package/build/static/js/447.f60d5f2f.chunk.js +2 -0
- package/build/static/js/603.0c99f909.chunk.js +1 -0
- package/build/static/js/main.js +1 -1
- package/data/description.md +322 -0
- package/graphite.js +1 -1
- package/graphite.js.LICENSE.txt +2 -546
- package/package.json +2 -1
- package/build/static/css/main.6c222a98.css +0 -2
- package/build/static/js/274.dce911b9.chunk.js +0 -1
- package/build/static/js/697.e9243bfd.chunk.js +0 -2
- /package/build/static/js/{697.e9243bfd.chunk.js.LICENSE.txt → 447.f60d5f2f.chunk.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# Stacking with Graphite CLI: A Solo Developer’s Guide
|
|
2
|
+
|
|
3
|
+
## What is **Stacking** and Why Use It?
|
|
4
|
+
|
|
5
|
+
**Stacking** (or stacked pull requests) is a development workflow where new feature branches are created **on top of existing feature branches**, rather than directly off the main trunk. In practice, this means breaking a large feature or change into a **sequence of smaller, dependent PRs**. Each PR (or “diff”) builds on the previous one, forming a stack. For example, instead of one huge PR with all your changes, you might have PR1 (base changes), PR2 (built on PR1), PR3 (built on PR2), and so on. Each can be reviewed and merged independently in order.
|
|
6
|
+
|
|
7
|
+
**Benefits for development and code review:** Stacking offers several advantages for a solo developer (and teams alike):
|
|
8
|
+
|
|
9
|
+
* **Parallel Development:** You don’t have to stop and wait for one PR to be merged before starting the next. Stacking **parallelizes development and code review**, so you can continue building on your last PR while it’s under review. This keeps you unblocked and speeds up your workflow.
|
|
10
|
+
* **Smaller, Focused PRs:** By design, stacking forces you to break up a big change into **smaller, more manageable changesets**. Each PR in the stack addresses a distinct part of the feature, typically on the order of tens or hundreds of lines rather than thousands. Smaller PRs are **easier to understand and review** for both you and your reviewers.
|
|
11
|
+
* **Faster, Incremental Reviews:** Reviewers can give feedback one piece at a time. Code review is faster and less overwhelming when focusing on a small diff. Issues can be caught and fixed in the relevant PR without holding up the entire feature. Meanwhile, you (as the author) can respond to feedback on an earlier PR while continuing work on later PRs.
|
|
12
|
+
* **Clear History & Separation of Concerns:** Each PR in a stack has a clear purpose. This structure makes the code history cleaner – if a bug arises or a revert is needed, you can target the specific PR that introduced it, rather than untangling a monolithic change. Overall, stacking **makes changes easier to understand** and maintain down the line.
|
|
13
|
+
* **No Long-Lived Massive Branches:** Instead of one long-lived feature branch with many commits, stacked branches regularly merge into main. This minimizes the pain of massive, out-of-date branches and reduces merge conflicts, since changes integrate to main in smaller chunks.
|
|
14
|
+
|
|
15
|
+
In short, stacked PRs help solo developers **ship code faster and with more confidence**. You can develop features in logical slices, get incremental feedback, and avoid the “mega-PR” anti-pattern that slows everyone down. However, manually managing stacked branches (constant rebasing, updating PR bases, etc.) can be tedious. **Graphite CLI (`gt`)** is a tool built to streamline this workflow by automating branch stacking operations.
|
|
16
|
+
|
|
17
|
+
## Getting Started with Graphite CLI
|
|
18
|
+
|
|
19
|
+
*Assumptions:* You have the Graphite CLI installed, have run `gt auth` to authenticate with GitHub, and initialized it in your repository (i.e., configured your trunk branch with `gt init`). This guide focuses on using Graphite’s CLI commands for a solo developer workflow. Graphite commands are invoked with the `gt` prefix. You can always run `gt --help` or consult the CLI’s help for details on flags.
|
|
20
|
+
|
|
21
|
+
Graphite CLI serves two key purposes: **simplifying Git commands** (especially tricky tasks like rebasing) and **enabling PR stacking** as a first-class concept. In the following sections, we’ll walk through a typical solo development cycle using stacked PRs with Graphite CLI – from the first branch, through stacking more PRs, updating them, and finally merging and cleaning up.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Step 1: Creating the First Stacked Branch (Initial PR)
|
|
26
|
+
|
|
27
|
+
Let’s start by creating our first pull request using Graphite CLI. This will set the foundation (the bottom of the stack) for subsequent PRs.
|
|
28
|
+
|
|
29
|
+
1. **Check out the trunk branch** (usually `main`):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
gt checkout main
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This ensures you’re up-to-date on the base branch before starting new work. (Graphite’s `gt checkout` is similar to `git checkout`, and with no argument it even presents an interactive branch picker, which is useful as your stack grows.)
|
|
36
|
+
|
|
37
|
+
2. **Make your code changes** on `main` (using your editor or any method). For example, if you’re adding a new API method, you’d edit or create the necessary files in your project. (In this guide, we’ll use simple shell commands to simulate changes.)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# For example, simulate code changes:
|
|
41
|
+
echo "new code changes" >> file.js
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. **Create a new branch with a commit for your first PR:** Use `gt create` to create a branch stacked on the current branch (main) and commit your changes in one go. For convenience, add flags to stage all changes and set a commit message:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
gt create --all \
|
|
48
|
+
--message "feat(api): Add new API method for fetching users"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This single command does the following: stages all your modified files (`--all`), creates a new branch off `main` (automatically naming it based on your commit message), and creates a commit with the given message. It also checks out the new branch for you, so you’re now on your feature branch. At this point, you have a local commit on a new branch (say the branch is named something like `username/feat-api-add-new-api-method-for-fetching-users`).
|
|
52
|
+
|
|
53
|
+
4. **Push the branch and create a pull request:** Use `gt submit` to push your new branch to the remote and open a PR on GitHub:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
gt submit
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
By default, `gt submit` will push the current branch to GitHub and open a pull request for it (Graphite CLI syncs with GitHub). You’ll likely be prompted (either in the CLI or on the web) to add a PR title/description if not provided. After this, your first PR is live on GitHub (or on Graphite’s web UI) for review.
|
|
60
|
+
|
|
61
|
+
5. **(Optional) Iterating on the PR:** If you realize you need to make further changes on this PR (before or after review), Graphite provides an easy way to update the commit. Simply make the needed code changes on this branch, then run:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
gt modify --all
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This stages all changes and **amends the last commit** of the current branch (by default). Essentially, `gt modify` lets you “modify” the tip of your branch; it will also automatically restack any descendant branches (we have none yet) to include this amended commit. After modifying, run `gt submit` again to update the PR on GitHub with your changes (Graphite will force-push the amended commit).
|
|
68
|
+
|
|
69
|
+
* *Alternative:* If you prefer not to amend but to add a new commit for the update, you can do `gt modify --commit --all -m "fix: adjust API response format"` to create a new commit on this branch. This is useful to preserve separate commits for feedback changes. Graphite will still restack any upstack branches to include this new commit.
|
|
70
|
+
|
|
71
|
+
At this stage, you have one open PR (let’s call it **PR1**) based on `main`. Now imagine you’ve submitted PR1 for review. Instead of waiting idle for PR1 to be reviewed and merged, you can immediately start on the next part of your project by stacking another PR on top of it.
|
|
72
|
+
|
|
73
|
+
## Step 2: Stacking an Additional Pull Request (Next PR in the Stack)
|
|
74
|
+
|
|
75
|
+
While PR1 is in review, Graphite enables you to create **another branch on top of PR1** for the next set of changes. This second branch will form **PR2**, and will be “stacked” on PR1 (meaning PR2’s base is PR1’s branch, not main).
|
|
76
|
+
|
|
77
|
+
1. **Check out the first PR’s branch:** Before creating the next PR, make sure you are on the branch that you want to build upon. You can use the interactive selector `gt checkout` (with no arguments) to choose the PR branch you just created:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
gt checkout
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Running `gt checkout` with no branch opens a list of branches – select your PR1 branch and press Enter. (Alternatively, you could run `gt checkout <branch_name>` directly.)
|
|
84
|
+
|
|
85
|
+
2. **Make the next set of changes** on this branch. These changes should logically build on what you did in PR1. For example, if PR1 added a new API, PR2 could add front-end code that uses that API:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Simulate some changes on top of PR1's changes:
|
|
89
|
+
echo "update frontend to use the new API" > frontend/UsersPage.tsx
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
3. **Create the second branch for PR2:** Now use `gt create` again to create a new branch for PR2. This will base the new branch on the current branch (which is PR1’s branch):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
gt create --all \
|
|
96
|
+
--message "feat(frontend): Load and display user list"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Graphite creates a new branch stacked on PR1’s branch and commits the changes with the provided message. Now you have a second branch (child of the first) locally.
|
|
100
|
+
|
|
101
|
+
4. **Submit the stacked PRs:** Push the new branch (and update PRs) with `gt submit --stack`:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
gt submit --stack
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The `--stack` flag tells Graphite to **submit the entire stack** of changes, not just the current branch. In this case, PR1 was already submitted, so Graphite will push PR2 and ensure it’s correctly marked as dependent on PR1. After this, you should have **two PRs open**: PR1 (the base of the stack) and PR2 (stacked on PR1). PR2’s base branch will be PR1’s branch on GitHub, indicating the dependency.
|
|
108
|
+
|
|
109
|
+
*Tip:* You can also assign reviewers at submit time. For example, `gt submit --stack --reviewers alice` would mark **@alice** as the reviewer on each PR in the stack. Otherwise, you can open the PRs in the browser and assign reviewers manually.
|
|
110
|
+
|
|
111
|
+
5. **Visualize the stack:** Locally, use `gt log` or the shorthand `gt ls` to see your stack of branches in a tree view:
|
|
112
|
+
|
|
113
|
+
 *Graphite CLI output of `gt log`, showing a stack of branches (each bullet is a branch, with indentation indicating the stack hierarchy). In this example, `main` is at the bottom, and several feature branches are stacked above it.*
|
|
114
|
+
|
|
115
|
+
The `gt log` command displays your trunk and all stacked branches as a DAG (directed acyclic graph). You should see that your second branch is shown as a child of the first branch, confirming the stack structure. (Under the hood, Graphite is managing metadata so it knows branch A is the parent of branch B, etc.)
|
|
116
|
+
|
|
117
|
+
6. **Open PRs in the browser (optional):** Run `gt pr` at any time to open the current branch’s PR page in your web browser. This is useful to double-check how the PR looks on GitHub/Graphite, assign reviewers, etc. If you run `gt pr` from the top of your stack, you’ll see PR2; from the bottom, you’ll see PR1. You can also use `gt pr --stack` to open Graphite’s stack view in the browser (if using Graphite’s web UI).
|
|
118
|
+
|
|
119
|
+
You have now created a **stack of two PRs**. PR2 is built on PR1. You can continue this process to create larger stacks (3, 4, 5, ... PRs) by always checking out the tip of the stack and then using `gt create` for the next branch. Graphite will handle tracking their relationships. Each PR can be reviewed independently, but you don’t have to stop coding while waiting for reviews.
|
|
120
|
+
|
|
121
|
+
## Step 3: Managing the Stack – Submitting and Updating PRs
|
|
122
|
+
|
|
123
|
+
At this point, you might be iterating on your stack: some PRs might get reviewed and need changes, or new commits on `main` might conflict with your open PRs. Graphite CLI provides commands to **modify, restack, and reorder** your stack easily. Let’s cover common scenarios:
|
|
124
|
+
|
|
125
|
+
### Addressing Code Review Feedback (Mid-Stack Changes)
|
|
126
|
+
|
|
127
|
+
It’s common to get feedback on the *bottom* PR while you’re still working on higher PRs. With a normal Git workflow, changing an earlier commit would require manually rebasing the later commits. Graphite automates this via `gt modify` and `gt restack`.
|
|
128
|
+
|
|
129
|
+
**Scenario:** Your reviewer asks for changes in PR1 (the bottom of your stack), which means PR2 (and any above) will need to incorporate those changes.
|
|
130
|
+
|
|
131
|
+
1. **Check out the PR that needs changes:** Use `gt checkout <branch_name>` for the PR that requires edits (e.g., PR1’s branch). For example:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
gt checkout feat/api-add-new-api-method-for-fetching-users
|
|
135
|
+
# Now on PR1's branch
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
2. **Make the required code changes** in that branch (e.g., adjust some API logic in `file.js` as per review comments).
|
|
139
|
+
|
|
140
|
+
3. **Amend or commit the changes:** Run `gt modify` to update this branch’s commit(s). By default, `gt modify -a` (with `--all`) will amend the latest commit with your staged changes and **automatically rebase (“restack”) all child branches on top of it**. For example:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
gt modify --all
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This stages all changes and amends the current commit in PR1, then Graphite **rebases PR2 on top of the updated PR1** for you. After this, PR1 now includes the review fixes, and PR2’s branch tip is moved to incorporate PR1’s new commit (so PR2 is up-to-date). Graphite essentially performs the equivalent of a `git commit --amend` on PR1 and a `git rebase` of PR2, all in one step.
|
|
147
|
+
|
|
148
|
+
* If you prefer to add a new commit on PR1 for the fixes (instead of amending), you can run:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
gt modify --commit --all --message "chore: address review feedback"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
This creates a new commit on PR1 (with your message) and restacks the branches above it as well. The choice between amending or adding a commit is up to your team’s conventions; either way, Graphite will ensure the stack remains consistent.
|
|
155
|
+
|
|
156
|
+
4. **Push the updated stack:** After modifying, push the changes with `gt submit` (or `gt submit --stack`). Graphite will update the open PRs on GitHub. PR1 will show the new changes (either as an amended single commit or an extra commit), and PR2 will now automatically include those changes in its diff (since its base changed). This makes it seamless for the reviewer – they’ll see PR1’s update, and PR2’s diff may shrink or adjust accordingly.
|
|
157
|
+
|
|
158
|
+
Graphite’s handling of mid-stack updates means you can fix something in an earlier PR **without having to manually rebase all subsequent PRs** – the CLI’s core commands do that heavy lifting. The `gt modify` command “will let you edit any branch in a stack, and automatically restack all the branches above it”.
|
|
159
|
+
|
|
160
|
+
### Keeping Your Stack Up-to-Date with `main`
|
|
161
|
+
|
|
162
|
+
As you work on your feature branches, the main branch (trunk) might advance (for instance, if you or others merged other changes into `main`). It’s important to keep your open PRs in sync with the latest `main` to catch any conflicts early and ensure a smooth merge later.
|
|
163
|
+
|
|
164
|
+
**Sync with trunk:** The command **`gt sync`** is your friend here. Running `gt sync` will:
|
|
165
|
+
|
|
166
|
+
* Fetch and fast-forward your local `main` to the latest remote `main`.
|
|
167
|
+
* **Rebase (restack) all your open PR branches on top of the new `main`** (for all stacks in the repo, or just the current stack).
|
|
168
|
+
* Identify any merged or closed PR branches and offer to delete them locally (cleanup).
|
|
169
|
+
|
|
170
|
+
In practice, just do:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
gt sync
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Graphite will pull the latest `main` and then rebase your stack’s branches one by one onto `main`. If everything applies cleanly, you’re done – all your branches now sit on the newest main, and their PRs are updated accordingly (Graphite updates the base commit in GitHub’s view).
|
|
177
|
+
|
|
178
|
+
If a conflict is encountered during this automatic restack, `gt sync` will pause and tell you which branch has conflicts. You can then checkout that branch (Graphite will usually prompt or can do it for you) and run `gt restack` to manually resolve conflicts:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Graphite tells you branch "feat/frontend-user-list" has conflicts
|
|
182
|
+
gt checkout feat/frontend-user-list
|
|
183
|
+
gt restack
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The `gt restack` command will initiate an interactive rebase for that branch onto its updated parent. You would then resolve merge conflicts in the files (if any) using your editor, `git add` the resolutions, and continue the rebase with `gt continue`. (You can also do `git rebase --continue`, but `gt continue` is a convenient alias that resumes a Graphite-stopped rebase operation.)
|
|
187
|
+
|
|
188
|
+
Once conflicts are resolved and `gt restack` finishes, run `gt submit` to push the now-conflict-free branch updates. Your PR stack is now rebased onto latest main.
|
|
189
|
+
|
|
190
|
+
**When to use `gt restack` vs `gt sync`:**
|
|
191
|
+
|
|
192
|
+
* Use `gt sync` regularly to incorporate upstream changes from trunk into all your stacks at once. It’s a broad operation (default affects all tracked branches) and is the easiest way to stay current.
|
|
193
|
+
* Use `gt restack` for more targeted rebasing. For instance, if you only want to rebase a specific branch or subset of the stack (perhaps after manually editing commits), you can use `gt restack` with options. By default, running it on a branch ensures that branch’s parent is in its history (rebasing if not). You can scope it with flags like `--upstack` or `--downstack` to restack only certain portions of the stack. In most cases, you won’t need to call `gt restack` manually unless fixing conflicts or performing an advanced operation – Graphite’s other commands (modify, sync, submit, etc.) call it under the hood as needed.
|
|
194
|
+
|
|
195
|
+
### Reordering PRs in a Stack (When and How)
|
|
196
|
+
|
|
197
|
+
Sometimes you may decide to **change the order of PRs** in your stack. Perhaps you realized PR2’s changes are actually independent and could go before PR1, or you want to split a PR into two and insert one in the middle of the stack. Graphite CLI supports reordering without manually juggling branches.
|
|
198
|
+
|
|
199
|
+
* **When to reorder:** Reordering is useful if the logical sequence of changes changes. For example, if PR2 no longer depends on PR1, you might want to swap them so PR2 can merge first. Or if you’ve created PR1 and PR2, but now want to insert a new PR between them (effectively reordering the sequence).
|
|
200
|
+
|
|
201
|
+
* **How to reorder:** Use the `gt reorder` command. First, checkout the branch that will be the new “bottom” of the section you want to reorder (or ensure you’re on one of the branches in the stack). Then run:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
gt reorder
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
This opens an editor (likely your default text editor) listing all branches from trunk (main) up to the current branch. You can then **move lines around** to specify a new order of those branches. Save and close the editor, and Graphite will automatically restack the branches in the order you specified. Essentially, it’s doing a series of rebases to shuffle the order.
|
|
208
|
+
|
|
209
|
+
For example, if your editor shows:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
main
|
|
213
|
+
feat/api-new-endpoint
|
|
214
|
+
feat/frontend-user-list
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
And you swap the two feature branches:
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
main
|
|
221
|
+
feat/frontend-user-list
|
|
222
|
+
feat/api-new-endpoint
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
After saving, the branch that was second is now based on `main`, and the one that was first is now stacked on it. Their PR dependencies will update accordingly (Graphite updates the parent/child relationships).
|
|
226
|
+
|
|
227
|
+
* **Inserting a new PR mid-stack:** A common pattern is realizing you need another PR in the middle of a stack. You can accomplish this by checking out the branch **below** where the new one should go and running `gt create -i`. The `--insert` (`-i`) flag on `gt create` will create a new branch above the current one and below its former child. Graphite will prompt if there are multiple children to choose which chain to insert into. This effectively is a shortcut for “create and then reorder into the middle,” which Graphite handles seamlessly.
|
|
228
|
+
|
|
229
|
+
* **Moving a branch to a different parent:** If you want to change a branch’s base to a completely different branch (not just reorder within the same trunk), you can use `gt move`. For instance, `gt move --onto other_branch` will rebase the current branch onto `other_branch` and restack its descendants accordingly. This is more advanced, but it’s good to know it exists if you ever need to re-parent a branch to a different part of the stack or a different base.
|
|
230
|
+
|
|
231
|
+
**Note:** Reordering can be complex if the changes truly depended on each other. Always consider if reordering makes sense logically (tests should pass in the new order). Graphite will handle the Git mechanics, but it can’t magically make dependent code independent. Use this feature when the dependency is flexible or mis-specified.
|
|
232
|
+
|
|
233
|
+
## Step 4: Merging the Stack of PRs
|
|
234
|
+
|
|
235
|
+
After your PRs have been reviewed and approved, the final goal is to merge them into the trunk (e.g., `main`). With a stacked PR workflow, you have a couple of options for merging:
|
|
236
|
+
|
|
237
|
+
* **Merge all PRs in the stack sequentially:** The straightforward approach is to merge from the bottom of the stack upwards. Since PR2 is based on PR1, PR1 must be merged (or at least merged into trunk) before PR2 can land on trunk. Graphite’s web UI has a “Merge Stack” button which can merge the entire stack in one go. If you’re using GitHub’s UI, you would merge PR1 (the base PR) first – once PR1 is merged into `main`, PR2’s base will automatically change to `main` (Graphite or GitHub will handle this if the branches are properly linked). Then you can merge PR2. In practice it’s often easiest to use Graphite’s **“Merge when ready”** feature: if you mark each PR as “merge when ready” (Graphite CLI has a flag `-m`/`--merge-when-ready` on `gt submit` to do this), they will auto-merge as soon as all requirements (approvals, CI checks) are met, in the correct order.
|
|
238
|
+
|
|
239
|
+
* **Partial merges:** Sometimes you might only want to merge part of the stack and leave the rest for later (e.g., PR1 is approved and independent, but PR2 is still under review). This is fine – you can merge PR1 by itself. After merging PR1, you’ll need to update PR2: you can either rebase PR2 onto `main` (Graphite should do this via `gt sync`) or GitHub might auto-update the base if it detects the base branch was merged. In Graphite’s UI, you could select PR1 as the last to merge, leaving PR2 open. Essentially, merging the bottom PR will turn the next PR into a normal PR against `main` (since its parent is merged).
|
|
240
|
+
|
|
241
|
+
* **Merge queue:** If you have Graphite’s merge queue or any automation, that can also handle stacks, but as a solo developer you might simply merge manually.
|
|
242
|
+
|
|
243
|
+
After merging, all the commits from PR1 and PR2 are now in `main`. Graphite (and GitHub) will mark those PRs as merged/closed.
|
|
244
|
+
|
|
245
|
+
## Step 5: Post-Merge Cleanup and Workflow Tips
|
|
246
|
+
|
|
247
|
+
Once your stacked PRs are merged, you should clean up local branches and make sure everything is synced. We already introduced `gt sync` for keeping up to date; it’s also the go-to for cleanup after merges.
|
|
248
|
+
|
|
249
|
+
* **Run `gt sync` after merging**: This will fetch the latest `main` (now containing your merged changes) and prompt you to delete the local branches that have been merged. Graphite knows which branches correspond to closed/merged PRs and will offer to remove them from your machine (they remain in GitHub history if needed, but you don’t need the local branches anymore). This keeps your environment clean.
|
|
250
|
+
|
|
251
|
+
* **Confirm branch deletion:** If you accept the prompt, Graphite will delete those branches locally. If you said “No” or used `--force`, you can always manually delete merged branches later with `gt delete <branch>` – Graphite’s delete will also handle any internal metadata and restack children appropriately.
|
|
252
|
+
|
|
253
|
+
* **Staying up-to-date:** As a solo dev, you might not have frequent incoming changes on `main` from others, but it’s still good practice to run `gt sync` periodically. It ensures your local trunk is current and that your next stack starts from the latest code.
|
|
254
|
+
|
|
255
|
+
* **Start the next task:** After merging and syncing, you’re ready to start a new stack for your next feature! Typically you’d `gt checkout main` (now updated) and repeat the process by creating a new branch with `gt create`. Graphite encourages a continuous flow: develop -> submit PRs -> merge -> sync -> repeat, always working in stacked, reviewable increments.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Troubleshooting & Common Patterns
|
|
260
|
+
|
|
261
|
+
Even with Graphite’s automation, you might encounter situations that need special handling. Here are some common scenarios and how to address them:
|
|
262
|
+
|
|
263
|
+
* **“Your branch and 'origin/main' have diverged” (Diverged Branch):** This Git message means your local branch history and the remote `main` have different commits (e.g., you made local commits while `main` moved on with other commits). In a stacking workflow, you typically avoid merging `main` into feature branches; instead you rebase feature branches onto `main`. The easiest fix is to run `gt sync` – Graphite will fetch the latest `main` and rebase your branch (or stack) onto it, effectively reconciling the divergence by making your commits sit on top of the new `main`. If `gt sync` warns that it can’t fast-forward `main` (because you have local commits on `main` that aren’t on origin), it will **force-reset your `main` to match origin** by default (Graphite assumes trunk should mirror the remote). After syncing, the divergence should be resolved. In general, if you stick to using `gt` commands for creating and updating branches, you’ll rarely see this error.
|
|
264
|
+
|
|
265
|
+
* **Merge Conflicts During Restack:** If a `gt sync` or `gt restack` stops due to conflicts, Graphite will pause the operation and let you resolve them. The CLI might output something like “Conflict in file X. Please resolve and run `gt continue`.” To handle this:
|
|
266
|
+
|
|
267
|
+
1. Open the conflicting file(s), and fix the merge markers (choose the correct code from HEAD vs incoming changes).
|
|
268
|
+
2. Stage the fixes with `git add <file>`.
|
|
269
|
+
3. Run `gt continue` to resume the restack/rebase. This is analogous to `git rebase --continue`, but use `gt continue` to keep Graphite aware of the operation.
|
|
270
|
+
4. If you decide to abort the rebase instead, you can use `gt abort` to cancel the operation (this will abort the Git rebase and reset to the pre-restack state). Then you might address the issue differently or try again.
|
|
271
|
+
|
|
272
|
+
* **Accidentally editing the wrong branch:** If you realize you committed changes on the wrong branch in your stack (e.g., you meant to be on a new branch but were still on PR1’s branch), Graphite can help adjust. You could use `gt split` to split out commits, or simpler, if the changes should really be a new PR on top, use `gt branch` (or `gt move`) to move that commit to a new branch. For example, checkout PR1, use `git reset HEAD~1` to undo the commit but keep changes staged, then `gt create` a new branch for those changes. Graphite’s `gt split` command can also take a multi-commit branch and break it into multiple single-commit branches automatically (advanced usage for after-the-fact stacking).
|
|
273
|
+
|
|
274
|
+
* **Rebasing a single branch or sub-stack:** If you want to rebase just part of a stack (say you have a long stack but only need to adjust the bottom few), you can use `gt restack --downstack` (to restack the branch and all its ancestors only) or `gt restack --upstack` (the branch and its descendants). For example, `gt restack --downstack` on a mid-stack branch will rebase that branch onto its correct parent (likely a new base if you changed something) and then stop, without touching branches above. This is rarely needed, but gives fine control.
|
|
275
|
+
|
|
276
|
+
* **Graphite metadata issues:** On rare occasions (say you performed some Git actions outside `gt` that confused it), Graphite might lose track of the parent/child relationship of branches. If you see strange behavior in `gt log` or Graphite’s stack view, the command `gt track` can be used to manually tell Graphite the parent of a branch. Running `gt track <branch>` lets you pick a parent branch for it (useful if you created a branch outside Graphite and want to include it in a stack). Similarly, `gt untrack` will remove a branch from Graphite’s tracking (if you no longer want it treated as part of a stack).
|
|
277
|
+
|
|
278
|
+
* **Undoing mistakes:** If you ever invoke a Graphite command and realize it did something you didn’t intend (like created or reordered incorrectly), you can often undo it. Git is underlying, so classic undo tactics apply. Graphite provides `gt undo`, which will attempt to reverse the last Graphite operation (for example, if you accidentally ran `gt create` and want to undo that branch creation). It’s essentially a safer wrapper around Git’s reflog/restore capabilities.
|
|
279
|
+
|
|
280
|
+
**Common Patterns Summary:** Keep these patterns in mind: use `gt modify` for updating commits, `gt sync` to stay current with trunk, `gt restack` (or automatic restacking) to handle any rebase needs, `gt reorder` or `gt move` for changing stack structure, and `gt continue/gt abort` when dealing with conflict resolutions. By using these tools, even tricky situations (rebasing a complex stack, resolving conflicts, altering stack order) become more manageable.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Appendix: Common Graphite CLI Commands for Stacking
|
|
285
|
+
|
|
286
|
+
Below is a quick-reference for the Graphite CLI commands used in stacked development. These are the most relevant commands for creating and managing stacks:
|
|
287
|
+
|
|
288
|
+
* **`gt checkout [branch]`:** Checks out the given branch. If no branch is specified, it opens an **interactive branch picker** for you to select a branch to switch to. (Use this to quickly switch between PR branches or to trunk.)
|
|
289
|
+
|
|
290
|
+
* **`gt create [name]`:** Creates a **new branch stacked on the current branch** and commits any staged changes to it. If you don’t provide a name, Graphite will auto-generate one from the commit message. Useful flags: `-a/--all` to stage all changes (including untracked files) before commit, `-m/--message "msg"` to set the commit message. This command is the standard way to start a new PR (stacked on whatever branch you’re currently on).
|
|
291
|
+
|
|
292
|
+
* **`gt submit`:** Pushes your local branches to GitHub and opens/updates PRs for them. By default it will submit only the current branch (and its ancestors, if they don’t have PRs yet). Use `gt submit --stack` to ensure it submits **all branches from the current branch’s ancestors down to itself** (i.e., the whole stack). Graphite will validate that branches are properly stacked (rebased) before pushing. It’s safe to run multiple times; it will create new PRs for new branches or update existing PRs if commits have changed. Common flags: `-d/--draft` to mark new PRs as draft, `-r/--reviewers user1,user2` to assign reviewers, `-m/--merge-when-ready` to mark PRs to auto-merge when requirements are met.
|
|
293
|
+
|
|
294
|
+
* **`gt modify`:** Modifies the current branch’s latest commit *or* creates a new commit on it, and **auto-restacks descendant branches**. This is a convenient alternative to `git commit --amend` or making new commits manually, as it will handle the rebase of children. Without flags, `gt modify` will prompt how to handle changes. With `--all`, it stages everything. Use `-c/--commit` to create a new commit instead of amending. Use `-m "message"` to provide a commit message (for new commit) or to update the amended commit message. Typically, `gt modify -a` (amend) or `gt modify -c -a -m "msg"` are used to apply feedback to a PR.
|
|
295
|
+
|
|
296
|
+
* **`gt restack`:** Restack the current branch (and by default, all its descendants) onto its proper base, ensuring each branch in the stack has its parent’s latest commits. In effect, it rebases the stack. In Graphite’s normal workflow, you don’t often run this manually unless dealing with conflicts or special cases, because `gt modify`, `gt submit`, etc., automatically keep things restacked. Flags: `--upstack`, `--downstack`, `--only` to limit which parts of the stack to restack. If conflicts occur, it will stop and prompt you to resolve them (via `gt continue`).
|
|
297
|
+
|
|
298
|
+
* **`gt sync`:** Syncs your local repository with the remote. This performs multiple actions: updates the trunk branch from remote, restacks all open branches on the new trunk (where possible), and offers to delete merged or closed branches. It’s essentially your “keep everything up-to-date” command. Use it frequently to avoid drift. You can add `--all` to sync across all trunk configurations if you have multiple trunk branches. If any branch can’t be automatically rebased (conflict), you’ll be told which one to manually `gt restack`.
|
|
299
|
+
|
|
300
|
+
* **`gt reorder`:** Opens an editor for you to reorder the branches between the current branch and the trunk, then restacks them in the new order. Use this when you want to rearrange the sequence of stacked PRs.
|
|
301
|
+
|
|
302
|
+
* **`gt move [--onto target]`:** Rebase the current branch onto a new target branch (changing its parent). This effectively moves a sub-stack to a different place. If no `--onto` is provided, it will interactively prompt for a target branch. After moving, it will restack the current branch’s children on the new base as well.
|
|
303
|
+
|
|
304
|
+
* **`gt continue`:** If a Graphite operation (like restack or sync) is paused due to conflicts, fix the conflicts then run `gt continue` to resume the operation. It continues the last operation that was interrupted by a rebase conflict. (Analogy: `git rebase --continue` in Graphite flavor.)
|
|
305
|
+
|
|
306
|
+
* **`gt abort`:** Abort a currently paused Graphite rebase/operation. This will stop the rebase and return your branches to the state before the operation (like `git rebase --abort`).
|
|
307
|
+
|
|
308
|
+
* **`gt top` / `gt bottom`:** Quickly navigate to the top of the current stack or the bottom (closest to trunk) of the current stack, respectively. For example, `gt top` checks out the tip-most branch in the stack you’re on, and `gt bottom` goes to the base branch of the stack (often trunk or the first feature branch).
|
|
309
|
+
|
|
310
|
+
* **`gt up` / `gt down`:** Move one level upstack or downstack in the branch hierarchy. `gt up` is like “go to my child branch” (if it exists), and `gt down` goes to the parent branch. These are handy for navigating a stack without specifying branch names.
|
|
311
|
+
|
|
312
|
+
* **`gt pr [branch]`:** Open the pull request page in your browser for the specified branch (or the current branch if none given). Use this to quickly jump to the GitHub/Graphite PR view.
|
|
313
|
+
|
|
314
|
+
* **`gt ls` / `gt log`:** Show the structure of your stacks. `gt log` by default shows a **graph of branches** (DAG) in your repo, which is great for visualizing stacks. `gt log short` or `gt ls` gives a concise list view of branches in the current stack. This helps confirm the order and parent-child relations.
|
|
315
|
+
|
|
316
|
+
* **`gt delete [branch]`:** Delete a branch locally and remove it from Graphite tracking. If that branch had children, Graphite will prompt or handle moving those children onto the deleted branch’s parent (essentially “folding” the stack). Use this to clean up feature branches that you perhaps decided to discard or after a merge (though `gt sync` automates merged branch deletion as noted).
|
|
317
|
+
|
|
318
|
+
* **`gt undo`:** Undo the most recent Graphite mutation command. For example, if you ran a rebase or create that you want to revert, `gt undo` tries to roll it back.
|
|
319
|
+
|
|
320
|
+
* **`gt help` or `gt <command> --help`:** Graphite provides detailed help for each command. Use this to discover more flags or subcommands as you become more advanced in stacking.
|
|
321
|
+
|
|
322
|
+
This appendix covered the key commands you’ll use day-to-day. Graphite CLI has many more capabilities (integration with AI for descriptions, splitting commits, etc.), but those above are the core for working with **stacked PRs** as a solo developer. By mastering these, you’ll be able to efficiently create, manage, and land stacked pull requests, making your development workflow more productive and your code reviews smoother.
|