Skip to content

Post a plain two-merge conflict resolution instead of a git-merge-onto re-parent#61

Closed
Phlogistique wants to merge 2 commits into
claude/autorestack-rebase-merge-supportfrom
claude/merge-onto-conflict-ux-ofnwra
Closed

Post a plain two-merge conflict resolution instead of a git-merge-onto re-parent#61
Phlogistique wants to merge 2 commits into
claude/autorestack-rebase-merge-supportfrom
claude/merge-onto-conflict-ux-ofnwra

Conversation

@Phlogistique

@Phlogistique Phlogistique commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #60.

The conflict comment asked the user to run a single uvx 'git-merge-onto>=0.2' --absorbed origin/<trunk> origin/<merged>. --absorbed is an obscure flag and git-merge-onto is an extra tool to reach for; the resolution is now two plain merges:

git merge origin/<merged>   # catch up to the moved base
git merge origin/<trunk>    # bring in the target

Why this works without a re-parent:

  • Mergeability / resume. The resume rides on a synchronize event, and GitHub creates no runs for a PR that conflicts with its base (the merged branch, kept until the resume retargets it). The first merge lands the merged branch's tip in the head's ancestry, so the pushed head descends from its base and the event fires. This is the role --absorbed played.
  • Clean diff. The trunk already carries the merged branch's content (the squash commit, or the rebase copies), so once the head contains the trunk the retargeted diff shows only the child's own changes. Nothing needs to explicitly drop the base.

No rebase detection comes back with it: both merges name branch tips, never SQUASH_COMMIT or its parent (the SQUASH_COMMIT~ reference that broke on rebase merges, dropped in #60), so a squash and a rebase merge resolve identically.

Tradeoff: git-merge-onto forced the merge base to the parent's tip, which kept the trunk step clean when the child had edited its parent's own lines. A plain git merge origin/<trunk> uses the true merge base, so in that case the child re-resolves the same region against the trunk. In the common case (the child's changes are elsewhere) the base merge is a no-op or a clean fast-forward and only the trunk merge conflicts.

The action's own automated re-parent still uses git-merge-onto --absorbed internally on the clean path; only the user-facing recipe changed. Since the posted command drops --absorbed, it no longer waits for git-merge-onto 0.2.0 on PyPI.

test_conflict_absorbed_resolution.sh (which replayed the incident that motivated --absorbed) becomes test_conflict_two_step_resolution.sh and asserts the same descent guarantee, now provided by the first merge. The e2e's conflict-comment assertion and resume checks follow the plain recipe.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SKuDUgzS8rSA4mvJ1r7Djd

claude added 2 commits July 5, 2026 21:14
The conflict comment asked the user to run a single
`uvx 'git-merge-onto>=0.2' --absorbed origin/<trunk> origin/<merged>`.
--absorbed is an obscure assertion flag; a plain two-step recipe reads
better.

The recipe is now `git merge origin/<merged>` (catch up to the moved base),
then `uvx git-merge-onto origin/<trunk> origin/<merged>` (re-home onto the
trunk). The first step is what --absorbed was for: it lands the merged
branch's tip in the resolved head's ancestry, and the re-home keeps it as a
parent, so the pushed head still descends from its base and GitHub fires the
resume event. Splitting also gives the user a base-vs-parent conflict and a
base-vs-trunk conflict separately instead of one merge that conflates both.

No rebase detection comes back with it: the recipe never references
SQUASH_COMMIT~ (the reference that broke on rebase merges, dropped in #60),
only branch tips, which carry the same content under squash and rebase.

The action's own clean re-parent keeps --absorbed; it is internal and
unchanged. Only the user-facing recipe drops it, so the posted command runs
on the published git-merge-onto 0.1.0 and no longer waits for 0.2.0 on PyPI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKuDUgzS8rSA4mvJ1r7Djd
The second step re-parented with `uvx git-merge-onto origin/<trunk>
origin/<merged>`. Replace it with a plain `git merge origin/<trunk>`: the
trunk already carries the merged branch's content, so once the head contains
the trunk the retargeted diff shows only the child's own changes -- dropping
the base explicitly is unnecessary. The recipe is now entirely plain git.

Still rebase-safe and still needs no rebase detection: both merges name
branch tips, never SQUASH_COMMIT or its parent.

Tradeoff: git-merge-onto forced the merge base to the parent's tip, which
kept the trunk step clean when the child had edited its parent's lines. A
plain `git merge origin/<trunk>` uses the true merge base, so in that case
the child re-resolves the same region against the trunk. The unit test now
covers this (both merges conflict on the same line).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKuDUgzS8rSA4mvJ1r7Djd
@Phlogistique Phlogistique changed the title Post a two-step conflict resolution instead of a --absorbed re-parent Post a plain two-merge conflict resolution instead of a git-merge-onto re-parent Jul 5, 2026
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.

2 participants