Skip to content

fix(restack): reconcile remote-only commits before force-pushing - #272

Merged
lararosekelley merged 1 commit into
mainfrom
fix/270-reconcile-remote-only-commits
Jul 20, 2026
Merged

fix(restack): reconcile remote-only commits before force-pushing#272
lararosekelley merged 1 commit into
mainfrom
fix/270-reconcile-remote-only-commits

Conversation

@lararosekelley

@lararosekelley lararosekelley commented Jul 20, 2026

Copy link
Copy Markdown
Owner

fix(restack): reconcile remote-only commits before force-pushing

When a stack branch's remote tip has commits the local branch lacks (e.g. a commit made directly on GitHub), sync/restack now refresh the branches' tracking refs and offer to cherry-pick those commits in before force-pushing. Previously the push was rejected and git-stk looped on "the remote has moved on — run sync" with no way to reconcile.

Closes #270


Stack managed by git-stk

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

Claude finished @lararosekelley's task in 4m 47s —— View job


Code Review - Confidence: 93/100

Adds a pre-push reconciliation step to restack that detects remote-only commits (web UI edits, bot commits, committed suggestions) and offers to cherry-pick them in before force-pushing, replacing the prior --force-with-lease deadlock with an actionable prompt.

No actionable findings.

The implementation is correct end-to-end:

  • remote_only_commits correctly uses git log --cherry-pick --right-only --no-merges — the --cherry-pick flag strips patch-equivalent local counterparts, so only genuinely absent commits appear. Combined with commits.reverse() for oldest-first order, the cherry-picks apply cleanly.
  • fetch_tracking + ls-remote pre-check is the right approach: a targeted fetch of only the stack branches, guarded by an ls-remote probe to skip branches the remote has never seen, avoids both a whole-remote fetch and a hard failure on unpushed branches.
  • up_to_date interaction: after cherry-picking onto a branch (e.g. feature/a), the fork-point relative to its parent is unchanged, so up_to_date correctly returns true and the rebase skips it — the picked commits are preserved as-is. Descendants that need to rebase onto the new tip (feature/b) correctly see fork_point != parent_tip and are replayed. The comment in the code describing this invariant is accurate.
  • --force-with-lease coherence: the tracking refs are refreshed by fetch_tracking before the divergence check, so the lease used later in finish_restack is compared against a tracking ref that genuinely reflects the remote state. The lease will pass.
  • Conflict recovery: on a cherry-pick conflict the function returns the error before any branch is checkout'd back, leaving the user on the conflicted branch with an in-progress cherry-pick — exactly where they need to be to resolve it. The error message correctly says git cherry-pick --continue, not git stk continue (which would bail with "no interrupted restack found" since no rebase state file is written at this stage).
  • Non-interactive behavior: prompt::confirm (default-no) returns false on EOF, so piped/CI runs that encounter diverged remotes fail with the actionable bail message rather than auto-cherry-picking unreviewed commits. This is the correct safe default.
  • Boundary discipline: new git primitives (cherry_pick, fetch_tracking, remote_only_commits, remote_branches_present) are all in src/git.rs; the orchestration sits in src/stack/restack.rs. No boundary violations.

The three tests cover the critical branches: accepting the prompt (verifying the commit lands on feature/a, propagates to feature/b, and remote SHAs match), declining (verifying nothing is pushed and no "run sync" loop guidance appears), and dry-run (verifying fetch/write side-effects are suppressed). Coverage is complete for the feature.

@lararosekelley
lararosekelley merged commit 60ba36e into main Jul 20, 2026
14 checks passed
@lararosekelley
lararosekelley deleted the fix/270-reconcile-remote-only-commits branch July 20, 2026 19:21
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.

sync/restack loops forever when a stack branch's remote has commits the local branch lacks

1 participant