Skip to content

feat(stack): port replay git helpers (merge-tree + diff-tree) to Rust#1534

Closed
jd wants to merge 1 commit into
devs/jd/feat/rust-stack-detect-change-type/port-stackcomment-renderer-rust--8665e116from
devs/jd/feat/rust-stack-detect-change-type/port-replay-git-helpers-merge-tree-diff-tree-rust--a95ecd67
Closed

feat(stack): port replay git helpers (merge-tree + diff-tree) to Rust#1534
jd wants to merge 1 commit into
devs/jd/feat/rust-stack-detect-change-type/port-stackcomment-renderer-rust--8665e116from
devs/jd/feat/rust-stack-detect-change-type/port-replay-git-helpers-merge-tree-diff-tree-rust--a95ecd67

Conversation

@jd

@jd jd commented Jun 4, 2026

Copy link
Copy Markdown
Member

When stack push force-pushes an amended PR head, the revision-
history compare URL …/compare/<old>...<new> is useless when the
rebase moved the base — reviewers see the whole PR diff instead
of just the edit. Python fixes this by replaying the user's
amendment onto parent(old_sha) and uploading a synthetic
commit, so compare anchors on old_sha and renders only the
edit.

Port the git-only half of mergify_cli/stack/replay.py to
mergify-stack::replay:

  • compute_merged_treegit merge-tree --write-tree --merge-base=parent(new_sha) parent(old_sha) new_sha to
    produce the merged tree SHA. Same coerce-on-error → None
    semantics as Python (conflict, missing parents, old git
    without --write-tree all map to None so the caller falls back
    to the plain three-dot URL).
  • compute_tree_delta — parses git diff-tree -r --raw --no-renames into TreeEntrys shaped for GitHub's
    POST /repos/.../git/trees. D status emits sha: None
    → JSON null to instruct GitHub to delete the path; other
    statuses we don't recognise are dropped on the floor (Python
    matches).
  • mode_to_type160000commit, 040000tree,
    everything else→blob. Public so the eventual orchestrator
    can reuse it without a re-import.

Coverage: a real-repo orientation test that mirrors the bug
this whole module exists to fix (PR amended on a stable base —
the diff against parent_old^{tree} must contain ONLY the
amendment), plus conflict + missing-parent fallbacks and a
diff-tree parse over modified/added/deleted/type-changed
entries. Wire shape was cross-checked against the Python
implementation byte-for-byte.

The HTTP upload step (upload_replay_commit +
replay_for_revision) lands separately — it needs
mergify-core's HTTP client wired in, and the git half is
useful on its own when the eventual native stack push
arrives.

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

Depends-On: #1533

@jd

jd commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

This pull request is part of a Mergify stack:

# Pull Request Link
1 feat(stack): port detect_change_type + patch-id helpers to Rust #1532
2 feat(stack): port StackComment renderer to Rust #1533
3 feat(stack): port replay git helpers (merge-tree + diff-tree) to Rust #1534 👈
4 feat(stack): port RevisionHistoryComment to Rust #1535
5 feat(stack): port stack push approvals decision to Rust #1536
6 feat(stack): port replay HTTP upload + orchestrator to Rust #1537
7 feat(stack): port stack push git plumbing (notes fetch + push) to Rust #1539
8 feat(stack): port stack push rebase log lines to Rust #1540
9 feat(stack): port format_pull_description + build_change_tasks to Rust #1541
10 feat(stack): port create_or_update_pr + orphan branch delete to Rust #1542
11 feat(stack): port per-PR stack + revision-history comment upserters to Rust #1543
12 feat(stack): port stack push planner (get_changes) to Rust #1544
13 feat(stack): port stack push orchestrator to Rust #1545
14 feat(rust): wire native stack push + delete Python push.py #1546
15 chore: delete Python tree + simplify wheel/CI for pure-Rust binary #1547

@mergify mergify Bot had a problem deploying to Mergify Merge Protections June 4, 2026 14:29 Failure
@jd jd temporarily deployed to func-tests-live June 4, 2026 14:29 — with GitHub Actions Inactive
@mergify

mergify Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🔴 ⛓️ Depends-On Requirements

Waiting for

This rule is failing.

Requirement based on the presence of Depends-On in the body of the pull request

🔴 👀 Review Requirements

Waiting for

  • #approved-reviews-by>=2
This rule is failing.
  • any of:
    • #approved-reviews-by>=2
    • author = dependabot[bot]
    • author = mergify-ci-bot
    • author = renovate[bot]

🔴 🔎 Reviews

Waiting for

  • #review-requested = 0
This rule is failing.
  • #review-requested = 0
  • #changes-requested-reviews-by = 0
  • #review-threads-unresolved = 0

🟢 🤖 Continuous Integration

Wonderful, this rule succeeded.
  • all of:
    • check-success=ci-gate

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?:

🟢 📕 PR description

Wonderful, this rule succeeded.
  • body ~= (?ms:.{48,})

When `stack push` force-pushes an amended PR head, the revision-
history compare URL `…/compare/<old>...<new>` is useless when the
rebase moved the base — reviewers see the whole PR diff instead
of just the edit. Python fixes this by replaying the user's
amendment onto `parent(old_sha)` and uploading a synthetic
commit, so compare anchors on `old_sha` and renders only the
edit.

Port the **git-only** half of `mergify_cli/stack/replay.py` to
`mergify-stack::replay`:

- `compute_merged_tree` — `git merge-tree --write-tree
  --merge-base=parent(new_sha) parent(old_sha) new_sha` to
  produce the merged tree SHA. Same coerce-on-error → None
  semantics as Python (conflict, missing parents, old git
  without --write-tree all map to None so the caller falls back
  to the plain three-dot URL).
- `compute_tree_delta` — parses `git diff-tree -r --raw
  --no-renames` into `TreeEntry`s shaped for GitHub's
  `POST /repos/.../git/trees`. `D` status emits `sha: None`
  → JSON `null` to instruct GitHub to delete the path; other
  statuses we don't recognise are dropped on the floor (Python
  matches).
- `mode_to_type` — `160000`→`commit`, `040000`→`tree`,
  everything else→`blob`. Public so the eventual orchestrator
  can reuse it without a re-import.

Coverage: a real-repo orientation test that mirrors the bug
this whole module exists to fix (PR amended on a stable base —
the diff against `parent_old^{tree}` must contain ONLY the
amendment), plus conflict + missing-parent fallbacks and a
diff-tree parse over modified/added/deleted/type-changed
entries. Wire shape was cross-checked against the Python
implementation byte-for-byte.

The HTTP upload step (`upload_replay_commit` +
`replay_for_revision`) lands separately — it needs
mergify-core's HTTP client wired in, and the git half is
useful on its own when the eventual native `stack push`
arrives.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Change-Id: Ia95ecd671cb3c38d8d4ff97b90a748eb7b766b1e
@jd jd force-pushed the devs/jd/feat/rust-stack-detect-change-type/port-replay-git-helpers-merge-tree-diff-tree-rust--a95ecd67 branch from 97a4c1d to b652dd4 Compare June 4, 2026 14:36
@jd

jd commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

Revision history

# Type Changes Reason Date
1 initial 97a4c1d 2026-06-04 14:36 UTC
2 content 97a4c1d → b652dd4 (raw) 2026-06-04 14:36 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant