diff options
| -rw-r--r-- | claude-rules/commits.md | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/claude-rules/commits.md b/claude-rules/commits.md index 84f408b..754c53f 100644 --- a/claude-rules/commits.md +++ b/claude-rules/commits.md @@ -218,9 +218,52 @@ problem belong out. Same conciseness pressure as commit-message bodies. Commits and PRs are team-visible, permanent, and hard to amend once shared (especially after push or after a reviewer has replied). Before executing `git commit` or `gh pr create`, the change must pass a local code review -*and* the message must be reviewed by the user. The flow has two steps, in +*and* the message must be reviewed by the user. The flow has three steps, in order. +### Step 0: pre-flight reconcile (mandatory) + +Before reviewing the diff, fetch from the remote and reconcile against the +upstream of the current branch. Reconciliation can change the working state +when a rebase brings in upstream commits that touch staged files, and that +would invalidate Step 1's review. Handling drift first means the review and +the commit message describe the post-reconcile state. + +1. Fetch all remotes: + + git fetch --all --prune + +2. If the current branch has no upstream (new branch, never pushed), skip + to Step 1 — there's nothing to reconcile against, and the first push + sets the upstream. + +3. Otherwise, check divergence against `@{u}`: + + git rev-list --left-right --count @{u}...HEAD + + Output is `<behind>\t<ahead>`. Decide based on the pair: + + - **0 behind, anything ahead** — no-op. Continue to Step 1. + - **Behind only, clean tree** — fast-forward: `git merge --ff-only @{u}`. + - **Behind only, dirty tree** — surface to the user. Don't auto-stash or + auto-merge. Offer to commit or stash first, or skip the reconcile and + proceed knowing the push may need attention later. + - **Diverged (behind AND ahead)** — surface to the user. Ask whether to + rebase the local commits onto upstream (default for feature branches), + merge the upstream branch in (rare; preserves both lines), or skip and + proceed with the divergence. Don't auto-rebase. + +4. **PR flow only.** Also fetch the base branch (usually `main`) and check + whether the feature branch's base is behind. Surface this informationally; + don't auto-rebase the feature branch without asking. The "X commits + behind base" badge on the PR is a follow-up decision, not a reason to + block publish. + +The startup workflow's `git fetch --all --prune` doesn't substitute for +Step 0. Upstream can advance during a long session, especially across +machines or with teammates pushing in parallel. Run Step 0 every time the +publish flow starts. + ### Step 1: local code review (mandatory) Run the `review-code` skill against the change: @@ -406,6 +449,13 @@ independent gate. confirmation before `git push`, `gh pr merge`, or any equivalent. The Review and Publish flow above approves the *content*; merge strategy is a separate decision that needs its own confirmation. +- *Pre-push reconcile.* Right before `git push`, do one more + `git fetch <remote> <branch>` and verify the local branch is still + ahead-only against its upstream. If something landed between Step 0 and + push (review and draft together can take several minutes, and another + machine or teammate may push in that window), surface and resolve before + the push command runs. Catching drift here is cheaper than recovering + from a failed non-fast-forward push under publish-step pressure. - Override the squash default only when there's a concrete reason: a clean per-commit review history the user has explicitly asked for, a multi-commit semantic narrative the team values, etc. Squash is the |
