Skip to content

feat: amend staged changes into an older commit (DAN-92) - #154

Merged
danielss-dev merged 2 commits into
mainfrom
developements/amend-into-commit-a04a
Oct 19, 2026
Merged

danielss-dev merged 2 commits into
mainfrom
developements/amend-into-commit-a04a

Conversation

@danielss-dev

@danielss-dev danielss-dev commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Summary

First slice of DAN-92: Amend staged changes into this commit on a graph commit, as one operation.

  • Creates a fixup! commit, then replays an explicit oid plan (pick each commit in the range, fixup the new oid immediately after the target). Does not use --autosquash, so two commits that share a subject stay distinct.
  • Autostashes unstaged work for this path only.
  • Confirmation lists every commit the rewrite will replay, marks the target, refuses when the range contains a merge commit, and warns when the target is already on @{upstream} (a force push will be needed).
  • Abort of a conflicted rewrite soft-resets back to the pre-fixup tip (.git/strand-amend-into). Continue uses the existing sequencer.
  • Entry points: graph context menu, commit-detail more menu, command palette (amend-into). Hunk and line moves are out of this slice and were not filed.

Proof

cargo test -p strand-core --lib history::tests::amend_into -- --nocapture — 7 passed, 0 failed.

  • Fold C1..C3. Staged edit to a.txt (touched in C1) plus an unstaged edit to c.txt. After the action, subjects stay c1, c2, c3; C1's blob is a\nplus; C2/C3 blobs are unchanged; the worktree still has c\nlocal; the index for c.txt is still c; no fixup! remains. Rewritten oids: 414d34e9…, b88d1ad5…, 901dd48d….
  • Oid plan, duplicate subjects. Two commits both subject same. The chosen oid's diff contains +plus; the later same-subject commit's diff for that file is empty.
  • Root target. --root rebase; file becomes a\nplus; subjects stay root, c2.
  • Conflict → Abort. Rebase pauses with the marker present. Abort restores the original tip (fee6453d…), puts staged back in the index, keeps unstaged g\nlocal, and leaves no fixup! commit.
  • Conflict → Continue. Resolving the pauses finishes the rewrite. C1's blob is staged; subjects stay c1, c2, c3; unstaged g.txt is preserved; the marker is gone.
  • Merge in range. Plan lists feature, main, Merge branch 'feature', after and sets has_merge. The operation errors with this range contains a merge commit — Strand won't rewrite it. HEAD and the staged diff are unchanged.
  • Already on upstream. C1 reachable from @{upstream} → pushed=true. A newer local-only commit → pushed=false. HEAD and origin/main stay put.

Local gates before push: cargo test for the CI packages, cargo clippy -p strand-core -p strand-tauri -p strand-ops -p strand-headless -p strand-azdo-protocol -p strand-azdo -- -D warnings, pnpm --filter ./ui test (105 files, 626 tests), and pnpm --filter ./ui exec tsc --noEmit all exited 0.

CI

Native agent review (Windows) failed twice in pull_requests::pages::tests::cancellation_terminates_an_active_read before the WebView2 step: PowerShell did not create the ready file within 10s (child did not reach its cancellation checkpoint). That startup budget is now 30s. The cancel-latency check is still under 5s.

Test plan

  • CI, including Native agent review (Windows)
  • Graph commit with staged changes → confirm dialog lists the rewrite range → history folds the change into that commit
  • Unstaged edits survive; abort of a conflict restores the original tip
  • Merge in the range is refused; a pushed target shows the force-push warning

Review fixes

  • Abort only undoes amend-into when the abort was the amend's own rebase and HEAD is still the fixup commit. The marker now records the original and fixup IDs. A stale marker is dropped on any other abort.
  • Continue checks for an autostash that failed to re-apply (git ls-files --unmerged), names the stash, and returns an error instead of a silent success. The direct path does the same.
  • New tests:
    • a merge commit as the target is refused without rewriting;
    • a stale marker doesn't reset an unrelated abort;
    • Continue surfaces a conflicting autostash.
  • Reverted ee9e881, the 30s Windows startup wait (febb96b). The empty ci: commits stay, because removing them would need a force push.

Merge order 157 → 153 → 155 → 154 → 156 → 158: this PR must adapt to #155 (new rebase / interactive_rebase signatures, and passing update_refs). #156 must wrap amend_into in its journal.

Open in Web Open in Cursor 

cursoragent and others added 2 commits October 19, 2026 16:58
Fold staged changes into a chosen graph commit as one operation:
create a fixup, then replay an oid-built rebase plan with autostash.
Refuse ranges that contain a merge, warn when the target is already
on upstream, and restore the pre-fixup tip if the rewrite is aborted.

Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
- The amend marker now records the pre-amend tip and the fixup commit.
  Abort restores the original only for a rebase abort that lands exactly
  on that fixup; any other abort just drops the marker.
- A finished amend-into rewrite (direct or via Continue) whose autostash
  re-apply conflicted now returns an error naming the stash instead of
  reporting success. git exits 0 in that case.
- Tests: merge commit as the target is refused, a stale marker is ignored
  by an unrelated cherry-pick abort, a conflicting autostash after
  Continue is surfaced.

Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
@danielss-dev
danielss-dev marked this pull request as ready for review October 19, 2026 14:58
@danielss-dev
danielss-dev force-pushed the developements/amend-into-commit-a04a branch from 3e8f9d7 to 4294df2 Compare October 19, 2026 14:58
@danielss-dev
danielss-dev merged commit 9358527 into main Oct 19, 2026
6 checks passed
danielss-dev pushed a commit that referenced this pull request Oct 19, 2026
Squashed for the rebase onto #155 and #154: journal, worktree and pushed-commit
guards, stale-entry removal, staged-path stdin, overlap guards.
danielss-dev added a commit that referenced this pull request Oct 19, 2026
Squashed for the rebase onto #155 and #154: journal, worktree and pushed-commit
guards, stale-entry removal, staged-path stdin, overlap guards.

Co-authored-by: Grok Bot <grokbot@users.noreply.github.com>
danielss-dev pushed a commit that referenced this pull request Oct 19, 2026
Squashed for the rebase onto #155, #154 and #156. Drag-rebase now opens the
same RebaseOntoDialog as the Rebase menu (with the --update-refs choice).
danielss-dev added a commit that referenced this pull request Oct 19, 2026
…#158)

Squashed for the rebase onto #155, #154 and #156. Drag-rebase now opens the
same RebaseOntoDialog as the Rebase menu (with the --update-refs choice).

Co-authored-by: Grok Bot <grokbot@users.noreply.github.com>
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.

3 participants