feat(stack): rebase-aware compare URLs in revision history comments#1325
Conversation
Merge ProtectionsYour pull request matches the following merge protections and will not be merged until they are valid. 🟢 🤖 Continuous IntegrationWonderful, this rule succeeded.
🟢 👀 Review RequirementsWonderful, this rule succeeded.
🟢 Enforce conventional commitWonderful, this rule succeeded.Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
🟢 🔎 ReviewsWonderful, this rule succeeded.
🟢 📕 PR descriptionWonderful, this rule succeeded.
|
There was a problem hiding this comment.
Pull request overview
Adds a rebase-aware diff anchor for revision-history compare links by synthesizing and uploading a “replay” commit (so content-change pushes show only the user’s changes, not upstream rebase noise), and updates revision-history rendering/data to carry this anchor across pushes.
Changes:
- Introduce
mergify_cli/stack/replay.pyto compute a merged tree viagit merge-tree, derive a Git Data API tree delta, and upload an unreferenced replay commit. - Wire replay generation into
stack_pushand propagate a newreplay_shafield through revision-history comment JSON markers and rendering (including a “rebase only” badge and optional raw fallback link). - Add/extend tests covering replay orchestration and revision-history round-trip/rendering behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
mergify_cli/stack/replay.py |
New module that computes and uploads a synthetic “replay” commit for clean compare URLs. |
mergify_cli/stack/push.py |
Integrates replay computation into stack_push; extends revision-history entry model + rendering/marker persistence. |
mergify_cli/tests/stack/test_replay.py |
New unit tests for merge-tree, diff-tree parsing, API upload, and orchestration fallbacks. |
mergify_cli/tests/stack/test_push.py |
Updates existing tests and adds coverage for replay_sha propagation and rebase-only rendering. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dfca0a7 to
55e9b3a
Compare
Revision history
|
After a stack push that includes both a rebase onto a moved trunk and content edits, the standard `compare/old_sha...new_sha` URL anchored at `merge-base(old, new)` shows the user's actual changes mixed with every upstream commit pulled in by the rebase. Reviewers see noise instead of intent. This change synthesises a "replay" commit per content-change push: cherry-pick the previous PR head onto the new PR head's parent (via `git merge-tree --write-tree` — no working-tree side effects), upload it as an unreferenced commit through the GitHub Git Data API, and use its SHA as the URL anchor for a clean rebase-aware diff. The visible SHA-shorthand label still shows the actual old/new SHAs so users see what they expect, and a small `(raw)` fallback link points at the original three-dot URL — useful when GitHub eventually GCs the unreferenced replay commit. Pure-rebase pushes (patch-IDs match) skip the synthesis entirely and render a `_(rebase only)_` badge with no link, since the meaningful diff is empty. Failure modes (cherry-pick conflict, missing parents, GitHub API errors, git < 2.38) all return None silently and the renderer falls back to the existing three-dot URL — no behaviour regression. New module `mergify_cli/stack/replay.py`: - compute_merged_tree → runs `git merge-tree --write-tree` with parallel parent rev-parses, returns merged tree SHA + parent_new SHA - compute_tree_delta → parses `git diff-tree -r --raw --no-renames` into Git Data API tree entries, with mode/type preservation for executables, symlinks, and submodules - upload_replay_commit → POSTs the tree delta with `base_tree` then a parentless-of-new commit; returns the new commit SHA or None on any HTTP error - replay_for_revision → top-level orchestration with all-failure-mode fallback to None Wired into `stack_push`: `replay_for_revision` runs concurrently per "content"-classified PR (bounded by the existing MAX_CONCURRENT_API_CALLS semaphore) before the force-push to GitHub. The resulting replay SHA flows through the revision-history comment data path as a new `_RevisionEntry.replay_sha` field, persisted in the JSON marker for round-trip and re-render across subsequent pushes. Tests: 12 new in `test_replay.py` (covering merge-tree clean/conflict, tree-delta parsing for M/A/D/T statuses including submodule mode preservation, two-stage API upload happy and partial-failure paths, end-to-end orchestration including conflict / no-diff / rev-parse-tree short-circuits) plus 5 new in `test_push.py` covering the data-model round-trip, the rebase-only badge, the dual-link rendering with and without replay_sha, and end-to-end propagation through `stack_push`. Change-Id: I4b16130414084031dc79dc3de22fc1ae32334409
55e9b3a to
3ce743d
Compare
Merge Queue Status
This pull request spent 12 minutes 19 seconds in the queue, including 11 minutes 46 seconds running CI. Required conditions to merge
|
After a stack push that includes both a rebase onto a moved trunk and
content edits, the standard
compare/old_sha...new_shaURL anchored atmerge-base(old, new)shows the user's actual changes mixed with everyupstream commit pulled in by the rebase. Reviewers see noise instead of
intent.
This change synthesises a "replay" commit per content-change push:
cherry-pick the previous PR head onto the new PR head's parent (via
git merge-tree --write-tree— no working-tree side effects), uploadit as an unreferenced commit through the GitHub Git Data API, and use
its SHA as the URL anchor for a clean rebase-aware diff. The visible
SHA-shorthand label still shows the actual old/new SHAs so users see
what they expect, and a small
(raw)fallback link points at theoriginal three-dot URL — useful when GitHub eventually GCs the
unreferenced replay commit. Pure-rebase pushes (patch-IDs match) skip
the synthesis entirely and render a
_(rebase only)_badge with nolink, since the meaningful diff is empty.
Failure modes (cherry-pick conflict, missing parents, GitHub API
errors, git < 2.38) all return None silently and the renderer falls
back to the existing three-dot URL — no behaviour regression.
New module
mergify_cli/stack/replay.py:git merge-tree --write-treewithparallel parent rev-parses, returns merged tree SHA + parent_new SHA
git diff-tree -r --raw --no-renamesinto Git Data API tree entries, with mode/type preservation for
executables, symlinks, and submodules
base_treethen aparentless-of-new commit; returns the new commit SHA or None on
any HTTP error
fallback to None
Wired into
stack_push:replay_for_revisionruns concurrently per"content"-classified PR (bounded by the existing
MAX_CONCURRENT_API_CALLS semaphore) before the force-push to GitHub.
The resulting replay SHA flows through the revision-history comment
data path as a new
_RevisionEntry.replay_shafield, persisted in theJSON marker for round-trip and re-render across subsequent pushes.
Tests: 12 new in
test_replay.py(covering merge-tree clean/conflict,tree-delta parsing for M/A/D/T statuses including submodule mode
preservation, two-stage API upload happy and partial-failure paths,
end-to-end orchestration including conflict / no-diff / rev-parse-tree
short-circuits) plus 5 new in
test_push.pycovering the data-modelround-trip, the rebase-only badge, the dual-link rendering with and
without replay_sha, and end-to-end propagation through
stack_push.