fix(git): correct three command claims the plugin got wrong, and give rebase an owner

Three statements were false against the git in use (2.39.5), each verified by
running it.

`git rebase --autosquash HEAD~N` without `-i` is a silent no-op: git prints
"Successfully rebased", the `fixup!` commit survives with the same SHA, and
rewrite-history.md presented that as the preferred flow with `-i` as an optional
review step. The agent reports the squash as done and the `fixup!` subject then
trips this repo's own commit-msg gate. `-i` is now the command, not the alternative.

"Fetch never modifies a local branch, so it is always safe to run" — new text on
this branch — is false: `git fetch origin main:probe` fast-forwarded the local
branch, and a `+` prefix force-updates it, losing commits. The claim is scoped to
the no-refspec form.

`git worktree add --orphan` does not exist before Git 2.42; on 2.39.5 it is
`error: unknown option 'orphan'`, exit 129. The same file gives a version floor for
`--recurse-submodules` three sections earlier. Floor added, with a fallback that
was tested before being documented.

git-workflow claimed "every request resolves to exactly one of these six" while
rebase, reset and stash were owned by no skill — `git reset` appeared nowhere in
the plugin, old tree or new — so "undo my last commit" routed nowhere. The claim is
gone, the router gains rows for all three, and the procedures now exist: plain
rebase with `--onto` and conflict handling, a reset mode table gated on `--hard`,
and stash save/pop/list/drop. `--hard` gets an always-loaded Gotcha, matching the
register the force-push refusal already sets.

Cherry-pick had three claimants pointing at git-history while git-commits owned the
flow, and the two copies were not equivalent — git-history's lacked the destination
check, the rtk prefix and `--abort`. Resolved to git-commits per #112; the weaker
duplicate is replaced by a hand-off.

git-commits' metadata.version was deleted rather than bumped in 14af50b, leaving two
house-contract documents citing a worked v0.1.2 to v0.1.3 transition against a file
declaring no version. Restored to 0.1.3.

Also: the divergent-pull explanation stated a `--ff-only` default that does not
exist (it is a hard error); `--remote` "requires" a configured branch where it uses
one; `git push origin --delete` moved to git-remotes, which owns the remote-side
gates; seven retired `git:<name>` source slugs; git-orchestrate quoted a
git-workflow sentence that no longer exists; git-submodules regains the indirect
trigger that made "add a dependency repo" routable; and commit atomicity is a common
gate rather than reachable only from the create flow.

Refs: #112, #113
This commit is contained in:
2026-09-01 12:38:38 +00:00
parent fc305ba7d9
commit 20e5627fd7
32 changed files with 246 additions and 70 deletions

View File

@@ -21,7 +21,9 @@ Prefer this whenever a commit is written to be folded, because git does the mark
1. `rtk git commit --fixup=<commit>` keeps the target's message; `rtk git commit --squash=<commit>` lets you edit the combined message later. Both prefix the message with `fixup!`/`squash!` and name the target commit.
2. Get explicit approval — the rebase still rewrites history.
3. Run `rtk git rebase --autosquash HEAD~N`, or `-i --autosquash` to review the plan first. Git reorders the tagged commits against their targets automatically.
3. Run `rtk git rebase -i --autosquash HEAD~N`. Git pre-fills the todo list with the tagged commits already reordered against their targets; save it unchanged to apply.
**`-i` is not optional here.** On Git 2.39.5, `rtk git rebase --autosquash HEAD~N` without `-i` prints `Successfully rebased and updated refs/heads/<branch>.` and exits 0 while leaving the `fixup!` commit in place at its original SHA — `--autosquash` is honoured only by the interactive machinery, and the false success is the trap: the fold is reported as done, and the surviving `fixup!` subject then fails the Conventional Commits `commit-msg` hook. Later Git versions taught the non-interactive rebase to honour the flag, but `-i --autosquash` is correct on every version, so always write that.
## Squash by hand (interactive rebase)
@@ -35,3 +37,40 @@ Use this when the commits were not tagged at commit time. **Interactive rebase h
## When a rebase halts on a conflict
Offer conflict resolution or `rtk git rebase --abort`. Do not resolve conflicts automatically without confirmation.
## Rebase the branch onto a new base
Replays this branch's commits on top of another branch's tip — bringing a feature branch up to
date without a merge commit.
1. Confirm nothing being replayed has been pushed anywhere someone else has based work on. A rebase
gives every replayed commit a new SHA, which breaks any clone that already has the old ones.
2. Get explicit approval — this rewrites history like every other flow on this page.
3. `rtk git fetch origin` first, so `<newbase>` is the real tip rather than a stale local copy.
4. `rtk git rebase <newbase>` — for example `rtk git rebase main`. Use
`rtk git rebase --onto <newbase> <upstream> <branch>` to replay only the commits after
`<upstream>`, which is how a branch started from the wrong base gets moved.
5. The branch has now diverged from its remote. It needs
`--force-with-lease --force-if-includes` to push, never a bare `--force`, and never on
`main`/`master` — refuse that and explain.
## Move the branch pointer back (`git reset`)
`reset` moves the current branch to another commit. The mode decides what survives:
| Mode | Branch pointer | Index | Working tree |
|---|---|---|---|
| `--soft` | moves | untouched — the changes stay staged | untouched |
| `--mixed` (default) | moves | reset — the changes become unstaged | untouched |
| `--hard` | moves | reset | **overwritten; uncommitted work is destroyed** |
- "Undo my last commit but keep the changes" is `rtk git reset --soft HEAD~1`. That is the default
answer to the request; reach for anything else only when the caller asked for it.
- `rtk git reset --mixed HEAD~1` when the staging should be redone from scratch too.
- `rtk git reset --hard <ref>` is gated like a force-push: state exactly which uncommitted changes
will be discarded, get approval for that specific reset, and offer `rtk git stash push -u` first.
The commits it drops stay reachable through `git reflog`; the uncommitted edits never entered git
at all and nothing recovers them.
Reset does not rewrite the commits it leaves behind, so no force-push is needed unless the branch
was already pushed at the newer commit.