Finding 13: five blocks of near-identical wording were repeated across skills within a plugin — the gitea "resolve owner and repo" step (5 skills), the 404-masks-403 note (6 files), the manual pagination explanation (8 files), the git plugin's main/master force-push refusal (7 files, some with multiple internal restatements), and the bin skills' domain-glossary/ADR paragraph (5 skills). Tightened each instance in place — same meaning, fewer words — rather than extracting to a shared file, which ADR-0014's one-file-per-skill install constraint rules out. Left the three git skills' structured-result JSON shapes alone (coupled to the separate, out-of-scope git-orchestrate merge candidate, finding 19). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
76 lines
4.8 KiB
Markdown
76 lines
4.8 KiB
Markdown
---
|
|
source_keys:
|
|
- org-commit-conventions
|
|
- context7-git-htmldocs
|
|
---
|
|
|
|
# Rewriting existing commits
|
|
|
|
Every flow here rewrites history. None runs without explicit approval, and none ends in a force-push to `main`/`master` — refuse that and explain why.
|
|
|
|
## Amend the last commit
|
|
|
|
1. Stage the new changes, or the changes that undo something.
|
|
2. Run `rtk git commit --amend`, adding `--no-edit` when the message stays as it is.
|
|
3. If the message should change, show the current one and prompt for the replacement.
|
|
4. The branch has diverged from its remote. Amending is safe only where nobody else has based work on it; on `main`/`master`, refuse the force-push and explain rather than warn and proceed.
|
|
|
|
## Fold a commit into an earlier one (autosquash — preferred)
|
|
|
|
Prefer this whenever a commit is written to be folded, because git does the marking:
|
|
|
|
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 `git rebase -i --autosquash HEAD~N` — bare, not `rtk`: `-i` opens an interactive sequence editor. 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, `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)
|
|
|
|
Use this when the commits were not tagged at commit time. **Interactive rebase has no undo once `rebase -i` starts — `git reflog` is the recovery path.**
|
|
|
|
1. Identify the commits to squash — typically the last N on the current branch.
|
|
2. Get explicit approval.
|
|
3. Run `git rebase -i HEAD~N` — bare, not `rtk`, for the same interactive-editor reason — marking the older commits `squash` to keep their messages for editing, or `fixup` to discard them.
|
|
4. Compose the combined message when the rebase stops to ask. For a non-trivial combined message, follow the structure in `references/commit-template.md`.
|
|
|
|
## 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 diverged from its remote. Push needs `--force-with-lease --force-if-includes`,
|
|
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.
|