Skip to content

Hard-reset integration branch after merge to prevent SHA divergence#158

Merged
sebastientaggart merged 2 commits into
devfrom
feature/156-merge-reset-hard
Jun 3, 2026
Merged

Hard-reset integration branch after merge to prevent SHA divergence#158
sebastientaggart merged 2 commits into
devfrom
feature/156-merge-reset-hard

Conversation

@sebastientaggart

Copy link
Copy Markdown
Member

Replaces git pull on the integration/production branches with git fetch + git reset --hard origin/<branch> so the local branch becomes a perfect mirror of the remote after every CodeCannon-driven merge.

The previous git pull after gh pr merge --merge was creating a second, parallel merge commit locally for the same logical PR — once any divergence existed, every iteration compounded it (the symptom in the linked issue: 466 vs 465 different commits, near-empty content diff). Hard reset is safe because the workflow forbids direct commits to the integration/production branches, so there is no local work to lose (and git reflog keeps a 90-day safety net regardless).

Changes:

  • Makefile.agents.mk merge: target — git pullgit fetch + git reset --hard origin/$(INTEGRATION_BRANCH).
  • skills/start.md Step 4 (Case A and Case B, both BRANCH_DEV and BRANCH_PROD variants) — same pattern.
  • skills/deploy.md Step 1 sync — bare git pullgit fetch && git reset --hard @{u} (uses upstream so it works for whichever branch the project's deploy mode requires).
  • Rendered skill outputs synced.

Closes #156

@sebastientaggart

Copy link
Copy Markdown
Member Author

Review Summary

Verdict: APPROVE

The change faithfully implements the fix described in #156: replaces git pull with git fetch + git reset --hard origin/<branch> in the four sites that sync the integration/production branches (Makefile.agents.mk merge: target, skills/start.md Case A and Case B Step 4, skills/deploy.md Step 1). All four rendered adapter outputs (.claude/, .cursor/, .agents/, .gemini/) match the templates and updated content hashes. The acceptance criteria from #156 are satisfied by the diff.

Findings

  • [NOTE] skills/deploy.md uses git reset --hard @{u} while skills/start.md and Makefile.agents.mk name the branch explicitly as origin/<branch>. Both forms are correct given the preceding git checkout / required-branch guard, but using @{u} introduces a small inconsistency and depends on the local branch having an upstream configured pointing at origin/<deploy-branch>. Naming the branch explicitly (matching the other two sites) would be marginally more defensive and stylistically consistent.

  • [NOTE] git reset --hard silently discards any uncommitted working-tree changes on the integration/production branch, whereas the previous git pull would have aborted loudly on a dirty tree. This is safe under the documented CodeCannon workflow (integration/prod branches are never edited locally — all changes flow through feature branches + PRs) and Local integration branch (dev) accumulates SHA-divergent history vs origin/dev over time — make merge uses git pull where it needs git reset --hard #156 already calls this out, with git reflog providing 90-day recovery. Worth being aware of as a behavior change for any user who had been hand-editing those branches against convention.

@sebastientaggart

Copy link
Copy Markdown
Member Author

Review Summary (re-review after 34c1f16)

Verdict: APPROVE

The new commit cleanly addresses both prior NOTEs and adds the local-only-commits warning specified in #156's recovery rationale.

Verified against the diff:

  • Dirty-tree guard (git diff --quiet && git diff --cached --quiet || abort) is present at every git reset --hard site: Makefile.agents.mk merge:, skills/start.md Step 4 Case A and Case B (both BRANCH_DEV and BRANCH_PROD variants), and skills/deploy.md Step 1 (all three conditional blocks).
  • Local-only-commits warning in Makefile.agents.mk counts git rev-list --count origin/$(INTEGRATION_BRANCH)..HEAD after git fetch and prints git log --oneline origin/$(INTEGRATION_BRANCH)..HEAD before the reset. Non-aborting, as intended for the Local integration branch (dev) accumulates SHA-divergent history vs origin/dev over time — make merge uses git pull where it needs git reset --hard #156 recovery path. Output reaches the user's terminal via the make recipe.
  • skills/deploy.md three-mode conditional now covers all three branching modes: {{#if BRANCH_TEST}} → reset to origin/{{BRANCH_TEST}}, {{#if !BRANCH_TEST}}{{#if BRANCH_DEV}} → reset to origin/{{BRANCH_DEV}}, {{#if !BRANCH_TEST}}{{#if !BRANCH_DEV}} → reset to origin/{{BRANCH_PROD}}. Matches the trunk/two-branch/three-branch documentation block at the top of Step 1.
  • The earlier @{u} form is gone — every site now names the branch explicitly as origin/<branch>, resolving the stylistic NOTE from the prior review.

Findings

  • [NOTE] The dirty-tree guard git diff --quiet && git diff --cached --quiet deliberately ignores untracked files. This is the right call — git reset --hard does not touch untracked files, so guarding against them would produce false aborts (e.g. editor swap files, build artifacts, .DS_Store) without protecting any user work.

  • [NOTE] The guard can produce a benign false abort if the working tree has uncommitted submodule pointer changes, file-mode flips (e.g. on filesystems where core.fileMode differs), or CRLF/autocrlf renormalization noise that leaves git diff non-empty without user-visible edits. The failure mode is loud (clear error message asking the user to resolve) rather than silent data loss, so this is the correct trade-off; flagging only for awareness.

  • [NOTE] The local-only-commits warning in Makefile.agents.mk is informational rather than interactive — by the time the user reads "discarding N commit(s)", the reset has already executed (chained with &&). Recovery via git reflog within 90 days remains available, matching the recovery story documented in Local integration branch (dev) accumulates SHA-divergent history vs origin/dev over time — make merge uses git pull where it needs git reset --hard #156. Acceptable, and prompting for confirmation inside a make recipe would be awkward, but worth noting that the message is post-hoc.

@sebastientaggart
sebastientaggart merged commit 893979f into dev Jun 3, 2026
6 checks passed
@sebastientaggart
sebastientaggart deleted the feature/156-merge-reset-hard branch June 3, 2026 22:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant