git-branchless
Contract
| Field | Bound contract |
|---|---|
| Trigger | Multi-commit work, stack edits, rebases, fixups, stacked-PR publishing, or mention of branchless, smartlog, git move, or git undo. |
| Authority | Human-only. Preview the target and consequence before publishing, remote bulk mutation, or any irreversible history change. Never rebase -i, reset --hard, or force flags. |
| Side effect | Local git-branchless commits, moves, and restacks; publish paths submit or push remote stack state. Silently inert when branchless is absent. |
| Done | Branchless idioms applied per the decision rubric with a publish gate, or an explicit not-initialized inert line. |
Not for
- Plain-git workflows in repos without branchless; the skill stays inert and yields to plain git.
- Interactive rebase (
rebase -i),reset --hard, or force flags; never use these. - Suggesting
git branchless initunless the user explicitly asks how to enable.
Inputs
- A git repository (required).
- branchless initialization state (detected by the pre-flight gate, not supplied).
- The target commits or stack tip (required for edits and restacks).
- The publish target (required only for publish; main versus feature is decided by the publish gate).
Procedure
-
Run the pre-flight gate to confirm branchless is initialized for the current repository, resolving the git-common-dir so linked worktrees are handled:
test -d "$(git rev-parse --git-common-dir)/branchless" && git config --get branchless.core.mainBranch- Both checks succeed: skill is active. Acknowledge with one line:
git-branchless active: main=<value>. - Either check fails: skill is silently inert. Emit one line:
git-branchless not initialized; skill inactive. Yield to plain git. Do not suggestgit branchless initunless the user explicitly asks how to enable. Stop.
Done when: branchless initialization is confirmed or the inert line is emitted.
- Both checks succeed: skill is active. Acknowledge with one line:
-
Classify the requested work into one operation class and apply its Always rule. Plain-git commands are fine when they fall outside the class.
| Class | Always | Never | |---|---|---| | Stack edits (reorder, fixup, squash, split) |
git move,git move -F,git reword,git split. |git rebase -ito drive stack edits. | | Base updates (rebase a stack onto fresh main) |git sync --pull(orgit move -b 'stack()' -d origin/main). Read the skip summary. |git pull --rebaseagainst a stack. | | Undoing committed history |git undo -i. |git reset --hard <SHA>against any commit already made. | | Discarding local work in progress |git hide -r <tip>(recoverable). |git branch -Dorgit reset --hardpurely to wipe. | | Branch creation for ephemeral work | Detached HEAD until publish; commit immediately, branch later. |git checkout -b feature/Xbefore the first commit exists. | | Publishing (feature stacks) | Name the tip, thengit submit -c @(first publish) orgit submit @(update). Stockgit push -u origin <feature>only if submit is denied. |git submittargetingmain/master/release/*. Writing--force/--force-with-leasein recipes. | | Publishing (gated main) | Only when the user requested main or HEAD is already on localmain/master:git sync --pull, prove@descends fromorigin/main, then stockgit push -u origin main. Detached: FF-only attach to local main first. |git submitfor main. Blindgit switch -C main/git branch -f main. Any force flag. |Legitimate plain-git edge cases that are not blocked:
git reset --soft HEAD~against staging when nothing is committed yet;git rebase --ontofor a one-off non-interactive upstream sync in a repo where branchless is not initialized (the skill is inert there anyway);git checkout -bwhen the work is genuinely about to be pushed.Done when: the work is classified into one operation class and the Always rule is applied.
-
Use the decision rubric to pick the concrete command sequence for the goal:
| Goal | Command sequence | |---|---| | Insert a fixup mid-stack |
git commit --fixup <target>thengit move -s HEAD -d <target> --fixup| | Reorder commits |git move -s <src> -d <dest>| | Squash two commits |git move -s <child> -d <parent> --fixup| | Split a commit |git split <commit>| | Rebase stack onto main |git sync --pull| | Find first failing commit |git test run --search binary --exec '<cmd>' 'stack()'| | Recover lost work |git undo -i| | Discard a local experiment |git hide -r <tip>| | Publish feature stack |git branch <name> @thengit submit -c @(update:git submit @) | | Land on main (gated) |git sync --pull+ ancestor oforigin/main+ stockgit push -u origin main| | Post-merge hygiene |git sync --pullthengit hide -r <merged-tips>; optionalgit gc|Done when: the concrete command sequence is selected and executed.
-
Before any publish, run the publish gate:
- Path M (main): only when the user requested main or HEAD is already on local
main/master. Rungit sync --pull, prove@descends fromorigin/main, then stockgit push -u origin main. Nevergit submitfor main. Never any force flag. If detached, FF-only attach to local main first. - Path F (feature):
git branch <name> @thengit submit -c @(first publish) orgit submit @(update). Fall back to stockgit push -u origin <feature>only if submit is denied. Never targetmain/master/release/*. Never write--force/--force-with-lease. Done when: the publish gate is run and the correct path is taken.
- Path M (main): only when the user requested main or HEAD is already on local
-
After
git amend,git reword,git move, orgit split, descendants are auto-restacked in-memory. Rungit restackmanually only when the smartlog warns about abandoned subtrees (✕ancestors). Done when: restack is handled and no abandoned subtrees remain. -
After a land/merge, run
git sync --pullthengit hide -r <merged-tips>; optionallygit gc. Done when: post-merge hygiene is complete. -
Read the skip summary line after every
git syncandgit move. Speculative-merge skips are silent unless the line is read. Done when: the skip summary is read after every sync and move.
Failure and recovery
- Not initialized: emit the inert line, make no mutation, yield to plain git. Do not suggest
git branchless initunless asked. - Version-gated flag rejected: fall back to the closest documented alternative and tell the user which feature was unavailable. Do not invent an unverified flag.
git submit --forge githubunsuitable for general use (upstream arxanas/git-branchless#1184): stack reordering can lose PR ancestry. Prefer the default forgebranchwithgit submit -c @/git submit @for feature stacks; never submit main. Stockgit push -uis the gated-main path and the submit-denied fallback.- Event log is per-repository and per-clone:
git undocannot reach state from a different clone or machine. State this when recovery is requested across clones. - Speculative-merge skips during and :c
andgit move`**: silent unless the summary line is read. If a skip is missed, re-run and read the summary before assuming success. - Never swallow an error or pretend the done predicate holds. If a command fails, report the exact failure and stop rather than widening scope.
Output
Applied branchless command sequence and resulting smartlog state; or a publish result (feature stack submitted, or main pushed after the ancestry check); or the explicit inert line git-branchless not initialized; skill inactive.