From 97cb551c84cf01ea3500d44de184831ab49c567e Mon Sep 17 00:00:00 2001 From: Juan Pablo Vega Date: Wed, 17 Jun 2026 12:06:54 +0200 Subject: [PATCH] docs: GitButler branching/PR workflow in AGENTS.md; gitignore lane scratchpad Document the but-CLI lifecycle (status/branch/commit/absorb/push), stacked-PR flow via gh, and the hard-won gotchas (linear-history requirement, absorb over hand-amend). Ignore the local .gitbutler.lanes.md tracking file. --- .gitignore | 3 +++ AGENTS.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/.gitignore b/.gitignore index 48e7b32614..eea313fba4 100644 --- a/.gitignore +++ b/.gitignore @@ -91,3 +91,6 @@ hosting/kubernetes/**/values.*.yaml # IDE/LSP config (local tooling) pyrightconfig.json .gstack/ + +# GitButler local lane tracking (not committed) +.gitbutler.lanes.md diff --git a/AGENTS.md b/AGENTS.md index c64298c509..394d09c579 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,49 @@ bottom. - Docs writing: the Diátaxis framework digest at `agents/docs/diataxis/`, and the `write-docs` skill for Agenta style, voice, and structure. +## Branching and PRs with GitButler + +This repo may be in GitButler workspace mode (current branch `gitbutler/workspace`). +If so, use the `but` CLI instead of raw `git branch`/`git commit`: + +- `but status` shows lanes and unassigned changes; `but branch new ` creates a + parallel lane; add `--anchor ` to stack on a parent. +- `but commit -m "..."` commits the uncommitted changes to that branch. + Pre-commit hooks (ruff, prettier, gitleaks) run; if a hook reformats files the + commit aborts — just rerun it. Changes belonging to another lane's commits stay + unassigned rather than being folded in. +- `but pr new` needs interactive forge auth; use `but push ` then + `gh pr create --head --base ` instead. For stacked PRs, + set `--base` to the parent branch so each PR shows only its own diff. +- To update already-committed files, use `but absorb` — it routes uncommitted + changes back into the commits they belong to in one operation. Run + `but absorb --dry-run` first to see the plan (which change → which commit). With + no argument it absorbs ALL uncommitted changes; `but absorb ` scopes to a + stack. Do NOT hand-amend file-by-file with `but amend `: each amend + rewrites the commit and invalidates the cliIds, so the next amend fails on a stale + id. Force-push an amended branch with `but push -f`. +- To commit to a specific branch in a stack, stage the files to it first + (`but rub `), then `but commit --only`. `but commit` + alone sweeps ALL uncommitted changes into that branch. + +### Hard-won gotchas (don't relearn these) + +- **GitButler series need linear history.** A stack of branches connected by + `git merge` commits (e.g. branches synced by merging a release in) can collapse + to a single series (the tip) when unapplied/re-applied — the intermediate + branches stop being addressable and you can't `but commit` to them. Prefer + GitButler's own stacking over merging branches into each other. +- **Don't sync a behind lane with `unapply` → `git branch -f origin/` → + `apply`.** Pointing a series at a merge-based origin ref flattens the stack. + There is no clean "fast-forward this series to its own remote" in the CLI when + origin is merge-based and ahead. +- **`but pull` rebases applied branches on the TARGET (main), not on each + branch's own upstream.** It will not advance a series to `origin/`. +- **Recovery: `but oplog list` then `but oplog restore `** rewinds the whole + workspace (including uncommitted changes) to any prior snapshot — this is how + you undo a botched unapply/apply and get a collapsed stack's series back. Take + a `but oplog snapshot -m "..."` before risky operations. + ## Before committing - Frontend changes: run `pnpm lint-fix` within the `web` folder. Details: `web/AGENTS.md`.