aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--claude-rules/commits.md52
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