git-machete
git machete is a logic- and feature-heavy CLI for managing chains of branches, but it keeps almost no extra state of its own: the only user-visible file it owns is .git/machete (the "branch layout" - a tree of branches with parent/child relationships, fork points and PR/MR annotations). It also maintains a transparent merge-base cache for performance, which the user never needs to touch. Everything else - rebases, merges, pushes, status rendering, PR/MR creation - is driven straight off git and the hosting API.
If the repo has no .git/machete file yet (check with git machete file && test -s "$(git machete file)"), the layout has not been initialized: run git machete discover -y (or ask the user) before anything else.
Do not run git machete discover against an already-initialized layout unless the user explicitly asks for it. discover re-derives the entire layout from heuristics (recent commit dates, branch reachability) and silently overwrites any hand-curated ordering, parenting, or annotations the user has built up. Use the targeted commands (add, slide-out, hand-edit) for incremental changes.
Hard rules - read first
Prefer dedicated subcommands over hand-editing .git/machete when one fits the task. You can edit the layout file directly, but parse errors are quiet, so reach for a subcommand whenever there is one that fits:
git machete add [-y] [<branch>] [--as-root|--onto <parent>] - add a branch
git machete slide-out [<branch>...] - remove a branch and re-parent its children (non-interactive by default; see rule 4 for --delete)
git machete anno [<text>] - set/clear annotation on the current branch
git machete rename <new-name> - rename a local branch and its layout entry (use this instead of git branch -m)
The layout file grammar is small: one branch per line, each child indented one level deeper than its parent, with an optional annotation after whitespace on the same line. Any consistent indent unit works (a tab or N spaces), but the same unit must be used throughout the file.
For operations with no dedicated command (e.g. reparenting an existing branch, splitting one branch into two, ad-hoc reordering of siblings), hand-edit .git/machete directly. The file is small and brittle: edit it in place with the agent's structured editing tool (StrReplace / equivalent string-replacement primitive), not by piping it through sed/awk or rewriting it from a shell heredoc - one stray space changes the parent/child relationship silently. Recommended sequence:
MACHETE="$(git machete file)" - resolve the actual path (worktree/submodule-aware).
cp -a "$MACHETE" "$MACHETE~" - back up; the file is NOT tracked by git, so this is your only undo.
- Read the file, perform a structured in-place edit (preserve the existing indent unit), write it back.
git machete status - verify the parse. If it errors, restore with cp -a "$MACHETE~" "$MACHETE".
When indenting, match the unit already used in the file (could be a tab or any number of spaces, but it must stay consistent throughout). For a brand-new layout, use two spaces.
In the common case the layout file lives at .git/machete and hard-coding that is fine. The two exceptions are submodules (.git/modules/<path>/machete) and linked worktrees with git config machete.worktree.useTopLevelMacheteFile false (.git/worktrees/<wt-name>/machete); when in doubt, git machete file always resolves correctly.
Register every new branch in the layout. Whenever you create a branch as part of the user's actual work (git checkout -b ..., git switch -c ..., git branch ...), follow it with git machete add -y [--onto <parent>] so the new branch joins .git/machete.
In a git-machete-managed repo, the layout is the index of "branches I care about": users typically keep every branch they actively touch under git-machete, and the only branches deliberately left out are unrelated ones (someone else's WIP, throwaway branches checked out for a quick look).
Defer to the user if they ask you to leave a branch unmanaged - but don't silently skip the add step; ask if you're unsure.
Never invoke a command that reads stdin without -y/--yes. Commands with a -y/--yes flag: add, advance, clean, delete-unmanaged, discover, traverse, github create-pr, gitlab create-mr. Always pass -y from a non-interactive context (CI, agent, script).
Some commands prompt and have no -y to suppress it - avoid or work around them:
git machete update - prompts only if the current branch is missing from the layout. Workaround: git machete add -y first, then git machete update.
git machete status - prompts to slide out stale branches when stdout is a tty. Workaround: pipe through | cat or redirect, or use git machete status --color=never > /tmp/status.txt.
git machete slide-out --delete ... - prompts once per branch and the prompt can't be silenced. Workaround: run plain git machete slide-out <branch>... first, then git branch -D <branch>... yourself (or skip the --delete entirely). Plain slide-out (and slide-out --removed-from-remote) is non-interactive.
git machete go without a direction - opens an interactive single-keystroke picker. Never invoke this form from an agent. Use git machete go <direction> (up/down/prev/next/root/first/last) instead, which is non-interactive (but may still prompt if down is ambiguous - prefer git machete show down | head -1 for scripted child discovery).
git machete edit - opens $EDITOR. Never invoke this form from an agent. Use the dedicated subcommands from rule 1, or hand-edit .git/machete for the cases that have no subcommand.
Plumbing commands have stable output across minor versions and are safe for scripting. Use these for any "I need to read state from git-machete" task:
git machete file - absolute path of .git/machete
git machete fork-point [--inferred] [<branch>] - prints fork-point SHA on stdout (and only that)
git machete is-managed [<branch>] - exit code 0 if managed, non-zero otherwise; no stdout
git machete list <category> [<branch>] - newline-separated branch names; categories: managed, addable, childless, slidable, slidable-after <branch>, unmanaged, with-overridden-fork-point
git machete show <direction> [<branch>] - newline-separated branch names for the given direction
git machete version - prints git-machete version X.Y.Z
All other commands' stdout/stderr formatting may change between minor versions, including status.
To open a PR/MR, use git machete github create-pr -y (or gitlab create-mr -y), not raw gh pr create / glab mr create.
The machete subcommand does three things the hosting CLI doesn't:
- sets the PR/MR base to the branch's parent in the layout, not the repo default branch (correct for stacked PRs);
- writes the new PR/MR number back onto the branch in
.git/machete so subsequent status / traverse / retarget-{pr,mr} see it;
- uses
.git/info/description for the default PR title.
The host's own CLI is only the right tool for things git-machete doesn't cover (read-only listing/commenting, deleting a PR, fetching CI status, etc.). See the Create / restack / retarget PRs recipe.
Resolve yellow edges before running update/traverse. A yellow edge means a child branch is a descendant of its parent but git-machete's inferred fork point lies somewhere earlier than the parent tip - usually because the branch was rebased over commits from another branch, or its real parent is a different managed branch. In ASCII-only output the edge marker is ?- (e.g. ?-feature-x); with colour it's yellow. Do not run git machete update / git machete traverse blindly in this state - a rebase from the inferred fork point will pull extra commits onto the branch.
Instead, run git machete status --list-commits --color=never | cat (which prints the relevant suggestion under the tree) and present the options to the user. The three resolutions, in roughly the order to consider them, are:
git machete fork-point <branch> --override-to-parent - accept the parent branch tip as the fork point (use when the branch was rebased and the inferred fork point is stale).
git machete update (rebase) - only after confirming the inferred fork point really is correct and the extra commits should be re-applied.
- Reattach the branch under a different parent (e.g. hand-edit
.git/machete as in rule 1) - use when the layout is wrong and the branch's real parent is a different managed branch.
Pick based on what the user wants; don't auto-choose.
Command catalog with side effects
The table lists every non-deprecated top-level command and github/gitlab subcommand. The brace notation {github,gitlab} verb-{pr,mr} is shorthand for the pair github verb-pr and gitlab verb-mr.
Commands absent from every row (completion, diff, help, log, plus the plumbing commands listed above, plus {github,gitlab} update-{pr,mr}-descriptions which only talks to the hosting API) do not satisfy any of these properties.
| Side effect |
Commands |
| reads stdin[1] |
add, advance, clean, delete-unmanaged, discover, {github,gitlab} create-{pr,mr}, go[2], slide-out[3], status[4], traverse, update |
displays status (runs machete-status-branch hook) |
discover, {github,gitlab} create-{pr,mr}, {github,gitlab} restack-{pr,mr}, go[2], status, traverse |
writes .git/machete (branch layout) |
add, advance, anno, clean, discover, edit[5], {github,gitlab} anno-{pr,mr}s, {github,gitlab} checkout-{pr,mr}s, {github,gitlab} create-{pr,mr}, {github,gitlab} restack-{pr,mr}, {github,gitlab} retarget-{pr,mr}, rename, slide-out, traverse |
| mutates the git repository (refs / index / worktree / config)[6] |
add, advance, clean, delete-unmanaged, fork-point[7], {github,gitlab} checkout-{pr,mr}s, {github,gitlab} create-{pr,mr}, {github,gitlab} restack-{pr,mr}, go, reapply, rename, slide-out, squash, traverse, update |
checks out a branch (git checkout, switching which branch HEAD points to)[11] |
add[12], {github,gitlab} checkout-{pr,mr}s, go, slide-out, traverse |
runs git merge |
advance[8], slide-out, traverse, update |
runs git rebase (runs machete-pre-rebase hook) |
reapply[9], slide-out, traverse, update |
slides out a branch (runs machete-post-slide-out hook) |
advance, slide-out[10], traverse |
| requires no ongoing rebase / merge / cherry-pick / revert / am / bisect |
advance, go, reapply, slide-out, squash, traverse, update |
Footnotes
[1]: Commands with a -y/--yes flag (add, advance, clean, delete-unmanaged, discover, traverse, {github,gitlab} create-{pr,mr}) are safe to run from an agent as long as -y is passed. Without -y they read stdin to confirm decisions. The rest (see [2]-[4]) cannot be silenced and need a workaround.
[2]: go without a direction is fully interactive (single-keystroke picker reading stdin). Never run this form from an agent. go <direction> (up/down/prev/next/root/first/last) is non-interactive, but down may prompt if there are multiple children; prefer git machete show down to enumerate them and then check out manually with git checkout.
[3]: slide-out only reads stdin under --delete (one yes/no per branch). slide-out and slide-out --removed-from-remote without --delete are non-interactive.
[4]: status reads stdin only when stdout is a tty and the layout references branches that no longer exist in the repo. Redirected/non-tty runs (| cat, > file) skip the prompt entirely. CI runs are safe.
[5]: edit doesn't itself write the layout file; it just opens $GIT_MACHETE_EDITOR/$GIT_EDITOR on it and any change is done by the editor. Never run this form from an agent.
[6]: Pure hosting-API operations don't count here - that's why {github,gitlab} retarget-{pr,mr} and {github,gitlab} update-{pr,mr}-descriptions are absent.
[7]: fork-point mutates .git/config only under its override flags (--override-to=..., --override-to-inferred, --override-to-parent, --unset-override). The default mode and --inferred/--explain are read-only.
[8]: advance can only run fast-forward merge (git merge --ff-only).
[9]: reapply can run rebase but can't run merge (merging a branch with its own fork point is a no-op).
[10]: slide-out --removed-from-remote removes branches from the layout but does NOT run the machete-post-slide-out hook. The regular slide-out and the slide-out triggered by advance/traverse do.
[11]: This is the operation that fails with fatal: '<branch>' is already used by worktree at <path> when the target branch is already checked out in another linked worktree - the class of bug that has to be guarded against (and was fixed for traverse and slide-out; each command in this row needs auditing for it, ideally refusing before any layout/refs mutation rather than midway through). Commands that only fast-forward or rewrite the current branch in place are deliberately NOT in this row, because they never switch to a different branch and so can't hit that conflict: advance (git merge --ff-only advances the current branch), squash (rewrites the current branch tip), and update/reapply (rebase the current branch). Note that git rebase <branch> does implicitly check <branch> out, but the rebase-running commands either rebase the already-current branch (update, reapply) or check the branch out explicitly just beforehand (slide-out, traverse, already counted here via that explicit checkout).
[12]: add checks out a branch only when it has to create or fetch a new local branch (e.g. git machete add <new-branch>, or adding a branch that exists only on the remote) - the CLI path opts into switching HEAD onto the freshly created branch. Adding a branch that already exists locally (including the common git machete add on the current branch) doesn't move HEAD.
Recipes
Initialize the branch layout for a fresh repo
git machete discover -y
Only run this when the layout doesn't exist yet (or the user explicitly asks to re-derive). On an existing layout, discover silently replaces any user-curated parenting/ordering.
Add the current branch under its parent
git checkout -b feature/new-thing
git machete add -y
Add a branch under an explicit parent
git machete add -y --onto develop feature/new-thing
Rename a branch (keeping the layout consistent)
git machete rename feature/new-name
Do not use git branch -m; it leaves the layout out of sync.
Get current branch state
git machete status -l # human-friendly, with commits
git machete status -l --color=never | cat # safe for agents (never prompts)
Sync the current branch with its parent
git machete update --no-interactive-rebase # rebase-based (default)
If update complains the current branch isn't in the layout, run git machete add -y (or git machete discover -y) first.
Walk the whole chain and bring everything up to date
git machete traverse -y --no-push # rebase only, don't push
git machete traverse -y # rebase + push (default)
GIT_MACHETE_PUSH_OPTS="--push-option=ci.skip" git machete traverse -y # rebase + push, forwarding a push option to every push
GIT_MACHETE_PUSH_OPTS is split on whitespace and passed straight through to every git push git-machete runs (traverse, advance, github/gitlab create-{pr,mr}/restack-{pr,mr}) - same mechanism as GIT_MACHETE_REBASE_OPTS for git rebase. It's how a bulk restack avoids firing one CI pipeline per branch (ci.skip is GitLab's spelling). Set it for a single invocation rather than exporting it, so it doesn't leak into unrelated commands.
Do not pass -M/--merge (to update, traverse, or slide-out). For stacked branches, merge-based sync entangles history quickly and recovery is non-trivial (see the README FAQ for rationale). Rebase is the only mode an agent should use. If the user explicitly asks for merge mode, repeat the warning and ask them to confirm.
Drop a branch from the layout (after merge)
git machete slide-out <branch> # branch still exists locally; non-interactive
git machete slide-out --removed-from-remote # clean up branches whose remote is gone (non-interactive, no hook)
To also delete the branch from git, run git branch -D <branch> yourself after slide-out - the built-in --delete flag prompts per branch and can't be silenced.
Inspect / set / clear fork-point overrides
git machete fork-point # prints SHA
git machete fork-point --inferred # what git-machete would infer
git machete fork-point --explain # human-readable rationale (uses stderr)
git machete fork-point --override-to-parent # pin fork point to the parent branch tip
git machete fork-point --unset-override
Create / restack / retarget PRs (GitHub)
git machete github create-pr -y # safe: -y skips push/sync prompts
git machete github restack-pr # non-interactive
git machete github retarget-pr # non-interactive, hosting-API only
git machete github checkout-prs --mine # non-interactive (forces non-interactive `add`)
GitLab equivalents: gitlab create-mr -y, restack-mr, retarget-mr, checkout-mrs --mine.
Discover children/parent for scripting (instead of go)
git machete show up # parent
git machete show down # all children, one per line
git machete show prev # previous in DFS order
git machete show next # next in DFS order
git machete show root # root of the current chain
git machete list managed # everything in the layout
git machete list slidable # branches that can be slid out
Hooks
git machete invokes three optional hooks if executable scripts of the matching names exist in .git/hooks/:
machete-pre-rebase <onto> <fork-point> <branch> - run before each git rebase initiated by git-machete (i.e. from reapply, slide-out, traverse, update). Non-zero exit aborts the rebase.
machete-post-slide-out <new-upstream> <slid-out-branch> [<new-downstream>...] - run after a successful slide-out triggered by advance, slide-out (without --removed-from-remote), or traverse.
machete-status-branch <branch> - run once per branch during status display; its stdout is appended to the branch's line in status output.
Files this tool reads/writes
| Path |
Purpose |
.git/machete |
branch layout (parent/child tree, annotations, qualifiers). The literal path varies by context (worktree, submodule); always resolve via git machete file. Not git-tracked, so back up to .git/machete~ before manual edits. |
.git/machete-merge-base-cache |
transparent merge-base cache. |
.git/config (machete.* keys) |
fork-point overrides set via fork-point --override-to=...; also feature toggles like machete.worktree.useTopLevelMacheteFile, machete.traverse.push, machete.squashMergeDetection. |
.git/info/description |
used as PR/MR title default when creating with github create-pr / gitlab create-mr. |
~/.github-token |
GitHub API token (alternative: GITHUB_TOKEN env var). |
~/.gitlab-token |
GitLab API token (alternative: GITLAB_TOKEN env var). |
Further reading
For per-command detail (full flag list, exit codes, examples), run git machete help <command> (e.g. git machete help traverse). It prints the same content as the readthedocs page for that subcommand, but in a single plain-text response that's cheap to ingest.
1---2name: git-machete3description: Use whenever invoking the `git machete` CLI to organize branch chains, compute fork points, run stacked rebases/merges, or manage GitHub/GitLab PR/MR chains - especially in a repo that already has a `.git/machete` file. Lists which subcommands modify `.git/machete`, run rebase/merge, run hooks, or read stdin, so the agent can pick the right one and pass the right flags. Crucially, names the commands that MUST be invoked with `-y/--yes` (and the few that have no `-y` and therefore must NOT be invoked at all without a tty) so the agent never hangs on an interactive prompt. Also warns against hand-editing the `.git/machete` layout file.4---56# git-machete78`git machete` is a logic- and feature-heavy CLI for managing chains of branches, but it keeps almost no extra state of its own: the only user-visible file it owns is `.git/machete` (the "branch layout" - a tree of branches with parent/child relationships, fork points and PR/MR annotations). It also maintains a transparent merge-base cache for performance, which the user never needs to touch. Everything else - rebases, merges, pushes, status rendering, PR/MR creation - is driven straight off git and the hosting API.910If the repo has no `.git/machete` file yet (check with `git machete file && test -s "$(git machete file)"`), the layout has not been initialized: run `git machete discover -y` (or ask the user) before anything else.1112**Do not run `git machete discover` against an already-initialized layout** unless the user explicitly asks for it. `discover` re-derives the entire layout from heuristics (recent commit dates, branch reachability) and silently overwrites any hand-curated ordering, parenting, or annotations the user has built up. Use the targeted commands (`add`, `slide-out`, hand-edit) for incremental changes.1314## Hard rules - read first15161. **Prefer dedicated subcommands over hand-editing `.git/machete`** when one fits the task. You *can* edit the layout file directly, but parse errors are quiet, so reach for a subcommand whenever there is one that fits:17 - `git machete add [-y] [<branch>] [--as-root|--onto <parent>]` - add a branch18 - `git machete slide-out [<branch>...]` - remove a branch and re-parent its children (non-interactive by default; see rule 4 for `--delete`)19 - `git machete anno [<text>]` - set/clear annotation on the current branch20 - `git machete rename <new-name>` - rename a local branch *and* its layout entry (use this instead of `git branch -m`)2122 The layout file grammar is small: one branch per line, each child indented one level deeper than its parent, with an optional annotation after whitespace on the same line. Any consistent indent unit works (a tab or N spaces), but the same unit must be used throughout the file.2324 For operations with no dedicated command (e.g. reparenting an existing branch, splitting one branch into two, ad-hoc reordering of siblings), hand-edit `.git/machete` directly. The file is small and brittle: edit it in place with the agent's structured editing tool (`StrReplace` / equivalent string-replacement primitive), not by piping it through `sed`/`awk` or rewriting it from a shell heredoc - one stray space changes the parent/child relationship silently. Recommended sequence:2526 1. `MACHETE="$(git machete file)"` - resolve the actual path (worktree/submodule-aware).27 2. `cp -a "$MACHETE" "$MACHETE~"` - back up; the file is NOT tracked by git, so this is your only undo.28 3. Read the file, perform a structured in-place edit (preserve the existing indent unit), write it back.29 4. `git machete status` - verify the parse. If it errors, restore with `cp -a "$MACHETE~" "$MACHETE"`.3031 When indenting, match the unit already used in the file (could be a tab or any number of spaces, but it must stay consistent throughout). For a brand-new layout, use two spaces.3233 In the common case the layout file lives at `.git/machete` and hard-coding that is fine. The two exceptions are submodules (`.git/modules/<path>/machete`) and linked worktrees with `git config machete.worktree.useTopLevelMacheteFile false` (`.git/worktrees/<wt-name>/machete`); when in doubt, `git machete file` always resolves correctly.34352. **Register every new branch in the layout.** Whenever you create a branch as part of the user's actual work (`git checkout -b ...`, `git switch -c ...`, `git branch ...`), follow it with `git machete add -y [--onto <parent>]` so the new branch joins `.git/machete`.36 In a git-machete-managed repo, the layout is the index of "branches I care about": users typically keep every branch they actively touch under git-machete, and the only branches deliberately left out are unrelated ones (someone else's WIP, throwaway branches checked out for a quick look).37 Defer to the user if they ask you to leave a branch unmanaged - but don't *silently* skip the `add` step; ask if you're unsure.38393. **Never invoke a command that reads stdin without `-y/--yes`.** Commands with a `-y/--yes` flag: `add`, `advance`, `clean`, `delete-unmanaged`, `discover`, `traverse`, `github create-pr`, `gitlab create-mr`. Always pass `-y` from a non-interactive context (CI, agent, script).40414. **Some commands prompt and have no `-y` to suppress it - avoid or work around them**:42 - `git machete update` - prompts only if the current branch is missing from the layout. **Workaround**: `git machete add -y` first, then `git machete update`.43 - `git machete status` - prompts to slide out stale branches when stdout is a tty. **Workaround**: pipe through `| cat` or redirect, or use `git machete status --color=never > /tmp/status.txt`.44 - `git machete slide-out --delete ...` - prompts once per branch and the prompt can't be silenced. **Workaround**: run plain `git machete slide-out <branch>...` first, then `git branch -D <branch>...` yourself (or skip the `--delete` entirely). Plain `slide-out` (and `slide-out --removed-from-remote`) is non-interactive.45 - `git machete go` *without* a direction - opens an interactive single-keystroke picker. **Never invoke this form from an agent.** Use `git machete go <direction>` (`up`/`down`/`prev`/`next`/`root`/`first`/`last`) instead, which is non-interactive (but may still prompt if `down` is ambiguous - prefer `git machete show down | head -1` for scripted child discovery).46 - `git machete edit` - opens `$EDITOR`. **Never invoke this form from an agent.** Use the dedicated subcommands from rule 1, or hand-edit `.git/machete` for the cases that have no subcommand.47485. **Plumbing commands have stable output across minor versions** and are safe for scripting. Use these for any "I need to read state from git-machete" task:49 - `git machete file` - absolute path of `.git/machete`50 - `git machete fork-point [--inferred] [<branch>]` - prints fork-point SHA on stdout (and only that)51 - `git machete is-managed [<branch>]` - exit code 0 if managed, non-zero otherwise; **no stdout**52 - `git machete list <category> [<branch>]` - newline-separated branch names; categories: `managed`, `addable`, `childless`, `slidable`, `slidable-after <branch>`, `unmanaged`, `with-overridden-fork-point`53 - `git machete show <direction> [<branch>]` - newline-separated branch names for the given direction54 - `git machete version` - prints `git-machete version X.Y.Z`5556 All other commands' stdout/stderr formatting may change between minor versions, including `status`.57586. **To open a PR/MR, use `git machete github create-pr -y` (or `gitlab create-mr -y`), not raw `gh pr create` / `glab mr create`.**59 The machete subcommand does three things the hosting CLI doesn't:60 - sets the PR/MR base to the branch's *parent in the layout*, not the repo default branch (correct for stacked PRs);61 - writes the new PR/MR number back onto the branch in `.git/machete` so subsequent `status` / `traverse` / `retarget-{pr,mr}` see it;62 - uses `.git/info/description` for the default PR title.6364 The host's own CLI is only the right tool for things git-machete doesn't cover (read-only listing/commenting, deleting a PR, fetching CI status, etc.). See the [Create / restack / retarget PRs](#create--restack--retarget-prs-github) recipe.65667. **Resolve yellow edges before running `update`/`traverse`.** A yellow edge means a child branch is a descendant of its parent *but* git-machete's inferred fork point lies somewhere earlier than the parent tip - usually because the branch was rebased over commits from another branch, or its real parent is a different managed branch. In ASCII-only output the edge marker is `?-` (e.g. `?-feature-x`); with colour it's yellow. **Do not run `git machete update` / `git machete traverse` blindly in this state** - a rebase from the inferred fork point will pull extra commits onto the branch.6768 Instead, run `git machete status --list-commits --color=never | cat` (which prints the relevant suggestion under the tree) and present the options to the user. The three resolutions, in roughly the order to consider them, are:69 - `git machete fork-point <branch> --override-to-parent` - accept the parent branch tip as the fork point (use when the branch was rebased and the inferred fork point is stale).70 - `git machete update` (rebase) - only after confirming the inferred fork point really is correct and the extra commits should be re-applied.71 - Reattach the branch under a different parent (e.g. hand-edit `.git/machete` as in rule 1) - use when the layout is wrong and the branch's real parent is a different managed branch.7273 Pick based on what the user wants; don't auto-choose.7475## Command catalog with side effects7677The table lists every non-deprecated top-level command and `github`/`gitlab` subcommand. The brace notation `{github,gitlab} verb-{pr,mr}` is shorthand for the pair `github verb-pr` and `gitlab verb-mr`.7879Commands absent from every row (`completion`, `diff`, `help`, `log`, plus the plumbing commands listed above, plus `{github,gitlab} update-{pr,mr}-descriptions` which only talks to the hosting API) do not satisfy any of these properties.8081| Side effect | Commands |82|----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|83| reads stdin<sup>[1]</sup> | `add`, `advance`, `clean`, `delete-unmanaged`, `discover`, `{github,gitlab} create-{pr,mr}`, `go`<sup>[2]</sup>, `slide-out`<sup>[3]</sup>, `status`<sup>[4]</sup>, `traverse`, `update` |84| displays status (runs `machete-status-branch` hook) | `discover`, `{github,gitlab} create-{pr,mr}`, `{github,gitlab} restack-{pr,mr}`, `go`<sup>[2]</sup>, `status`, `traverse` |85| writes `.git/machete` (branch layout) | `add`, `advance`, `anno`, `clean`, `discover`, `edit`<sup>[5]</sup>, `{github,gitlab} anno-{pr,mr}s`, `{github,gitlab} checkout-{pr,mr}s`, `{github,gitlab} create-{pr,mr}`, `{github,gitlab} restack-{pr,mr}`, `{github,gitlab} retarget-{pr,mr}`, `rename`, `slide-out`, `traverse` |86| mutates the git repository (refs / index / worktree / config)<sup>[6]</sup> | `add`, `advance`, `clean`, `delete-unmanaged`, `fork-point`<sup>[7]</sup>, `{github,gitlab} checkout-{pr,mr}s`, `{github,gitlab} create-{pr,mr}`, `{github,gitlab} restack-{pr,mr}`, `go`, `reapply`, `rename`, `slide-out`, `squash`, `traverse`, `update` |87| checks out a branch (`git checkout`, switching which branch HEAD points to)<sup>[11]</sup> | `add`<sup>[12]</sup>, `{github,gitlab} checkout-{pr,mr}s`, `go`, `slide-out`, `traverse` |88| runs `git merge` | `advance`<sup>[8]</sup>, `slide-out`, `traverse`, `update` |89| runs `git rebase` (runs `machete-pre-rebase` hook) | `reapply`<sup>[9]</sup>, `slide-out`, `traverse`, `update` |90| slides out a branch (runs `machete-post-slide-out` hook) | `advance`, `slide-out`<sup>[10]</sup>, `traverse` |91| requires no ongoing rebase / merge / cherry-pick / revert / am / bisect | `advance`, `go`, `reapply`, `slide-out`, `squash`, `traverse`, `update` |9293### Footnotes9495[1]: Commands with a `-y/--yes` flag (`add`, `advance`, `clean`, `delete-unmanaged`, `discover`, `traverse`, `{github,gitlab} create-{pr,mr}`) are safe to run from an agent **as long as `-y` is passed**. Without `-y` they read stdin to confirm decisions. The rest (see [2]-[4]) cannot be silenced and need a workaround.9697[2]: `go` without a direction is fully interactive (single-keystroke picker reading stdin). Never run this form from an agent. `go <direction>` (`up`/`down`/`prev`/`next`/`root`/`first`/`last`) is non-interactive, but `down` may prompt if there are multiple children; prefer `git machete show down` to enumerate them and then check out manually with `git checkout`.9899[3]: `slide-out` only reads stdin under `--delete` (one yes/no per branch). `slide-out` and `slide-out --removed-from-remote` without `--delete` are non-interactive.100101[4]: `status` reads stdin only when stdout is a tty and the layout references branches that no longer exist in the repo. Redirected/non-tty runs (`| cat`, `> file`) skip the prompt entirely. CI runs are safe.102103[5]: `edit` doesn't itself write the layout file; it just opens `$GIT_MACHETE_EDITOR`/`$GIT_EDITOR` on it and any change is done by the editor. Never run this form from an agent.104105[6]: Pure hosting-API operations don't count here - that's why `{github,gitlab} retarget-{pr,mr}` and `{github,gitlab} update-{pr,mr}-descriptions` are absent.106107[7]: `fork-point` mutates `.git/config` only under its override flags (`--override-to=...`, `--override-to-inferred`, `--override-to-parent`, `--unset-override`). The default mode and `--inferred`/`--explain` are read-only.108109[8]: `advance` can only run fast-forward merge (`git merge --ff-only`).110111[9]: `reapply` can run rebase but can't run merge (merging a branch with its own fork point is a no-op).112113[10]: `slide-out --removed-from-remote` removes branches from the layout but does NOT run the `machete-post-slide-out` hook. The regular `slide-out` and the slide-out triggered by `advance`/`traverse` do.114115[11]: This is the operation that fails with `fatal: '<branch>' is already used by worktree at <path>` when the target branch is already checked out in another linked worktree - the class of bug that has to be guarded against (and was fixed for `traverse` and `slide-out`; each command in this row needs auditing for it, ideally refusing *before* any layout/refs mutation rather than midway through). Commands that only fast-forward or rewrite the *current* branch in place are deliberately NOT in this row, because they never switch to a different branch and so can't hit that conflict: `advance` (`git merge --ff-only` advances the current branch), `squash` (rewrites the current branch tip), and `update`/`reapply` (rebase the *current* branch). Note that `git rebase <branch>` *does* implicitly check `<branch>` out, but the rebase-running commands either rebase the already-current branch (`update`, `reapply`) or check the branch out explicitly just beforehand (`slide-out`, `traverse`, already counted here via that explicit checkout).116117[12]: `add` checks out a branch only when it has to create or fetch a *new* local branch (e.g. `git machete add <new-branch>`, or adding a branch that exists only on the remote) - the CLI path opts into switching HEAD onto the freshly created branch. Adding a branch that already exists locally (including the common `git machete add` on the current branch) doesn't move HEAD.118119## Recipes120121### Initialize the branch layout for a fresh repo122```bash123git machete discover -y124```125Only run this when the layout doesn't exist yet (or the user explicitly asks to re-derive). On an existing layout, `discover` silently replaces any user-curated parenting/ordering.126127### Add the current branch under its parent128```bash129git checkout -b feature/new-thing130git machete add -y131```132133### Add a branch under an explicit parent134```bash135git machete add -y --onto develop feature/new-thing136```137138### Rename a branch (keeping the layout consistent)139```bash140git machete rename feature/new-name141```142**Do not** use `git branch -m`; it leaves the layout out of sync.143144### Get current branch state145```bash146git machete status -l # human-friendly, with commits147git machete status -l --color=never | cat # safe for agents (never prompts)148```149150### Sync the current branch with its parent151```bash152git machete update --no-interactive-rebase # rebase-based (default)153```154If `update` complains the current branch isn't in the layout, run `git machete add -y` (or `git machete discover -y`) first.155156### Walk the whole chain and bring everything up to date157```bash158git machete traverse -y --no-push # rebase only, don't push159git machete traverse -y # rebase + push (default)160GIT_MACHETE_PUSH_OPTS="--push-option=ci.skip" git machete traverse -y # rebase + push, forwarding a push option to every push161```162163`GIT_MACHETE_PUSH_OPTS` is split on whitespace and passed straight through to every `git push` git-machete runs (`traverse`, `advance`, `github`/`gitlab` `create-{pr,mr}`/`restack-{pr,mr}`) - same mechanism as `GIT_MACHETE_REBASE_OPTS` for `git rebase`. It's how a bulk restack avoids firing one CI pipeline per branch (`ci.skip` is GitLab's spelling). Set it for a single invocation rather than exporting it, so it doesn't leak into unrelated commands.164165**Do not** pass `-M`/`--merge` (to `update`, `traverse`, or `slide-out`). For stacked branches, merge-based sync entangles history quickly and recovery is non-trivial (see the [README FAQ](https://github.com/VirtusLab/git-machete#can-i-use-git-merge-for-syncing-stacked-branches) for rationale). Rebase is the only mode an agent should use. If the user explicitly asks for merge mode, repeat the warning and ask them to confirm.166167### Drop a branch from the layout (after merge)168```bash169git machete slide-out <branch> # branch still exists locally; non-interactive170git machete slide-out --removed-from-remote # clean up branches whose remote is gone (non-interactive, no hook)171```172To also delete the branch from git, run `git branch -D <branch>` yourself after `slide-out` - the built-in `--delete` flag prompts per branch and can't be silenced.173174### Inspect / set / clear fork-point overrides175```bash176git machete fork-point # prints SHA177git machete fork-point --inferred # what git-machete would infer178git machete fork-point --explain # human-readable rationale (uses stderr)179git machete fork-point --override-to-parent # pin fork point to the parent branch tip180git machete fork-point --unset-override181```182183### Create / restack / retarget PRs (GitHub)184```bash185git machete github create-pr -y # safe: -y skips push/sync prompts186git machete github restack-pr # non-interactive187git machete github retarget-pr # non-interactive, hosting-API only188git machete github checkout-prs --mine # non-interactive (forces non-interactive `add`)189```190GitLab equivalents: `gitlab create-mr -y`, `restack-mr`, `retarget-mr`, `checkout-mrs --mine`.191192### Discover children/parent for scripting (instead of `go`)193```bash194git machete show up # parent195git machete show down # all children, one per line196git machete show prev # previous in DFS order197git machete show next # next in DFS order198git machete show root # root of the current chain199git machete list managed # everything in the layout200git machete list slidable # branches that can be slid out201```202203## Hooks204205`git machete` invokes three optional hooks if executable scripts of the matching names exist in `.git/hooks/`:206207- `machete-pre-rebase <onto> <fork-point> <branch>` - run before each `git rebase` initiated by git-machete (i.e. from `reapply`, `slide-out`, `traverse`, `update`). Non-zero exit aborts the rebase.208- `machete-post-slide-out <new-upstream> <slid-out-branch> [<new-downstream>...]` - run after a successful slide-out triggered by `advance`, `slide-out` (without `--removed-from-remote`), or `traverse`.209- `machete-status-branch <branch>` - run once per branch during status display; its stdout is appended to the branch's line in `status` output.210211## Files this tool reads/writes212213| Path | Purpose |214|-------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|215| `.git/machete` | branch layout (parent/child tree, annotations, qualifiers). The literal path varies by context (worktree, submodule); always resolve via `git machete file`. Not git-tracked, so back up to `.git/machete~` before manual edits. |216| `.git/machete-merge-base-cache` | transparent merge-base cache. |217| `.git/config` (`machete.*` keys) | fork-point overrides set via `fork-point --override-to=...`; also feature toggles like `machete.worktree.useTopLevelMacheteFile`, `machete.traverse.push`, `machete.squashMergeDetection`. |218| `.git/info/description` | used as PR/MR title default when creating with `github create-pr` / `gitlab create-mr`. |219| `~/.github-token` | GitHub API token (alternative: `GITHUB_TOKEN` env var). |220| `~/.gitlab-token` | GitLab API token (alternative: `GITLAB_TOKEN` env var). |221222## Further reading223224For per-command detail (full flag list, exit codes, examples), run `git machete help <command>` (e.g. `git machete help traverse`). It prints the same content as the readthedocs page for that subcommand, but in a single plain-text response that's cheap to ingest.