docs(pull-request-workflow): merging divergent upstream history in forks#97
Conversation
Catching a fork up with an upstream reads as a merge-strategy question but is mostly a scope question. Adds a section covering four traps, all hit in one session on an archived-upstream fork: - '"merge" is a constraint, not an import instruction'. A maintainer rejecting a rebase because it breaks releases is constraining SHA rewriting; cherry-pick satisfies that too. Measure the net delta before picking the mechanism. Real case: a full-history merge produced 548 conflicts and 11 DCO-breaking commits to deliver a two-line typo fix -- and the delta had been measured beforehand. - Resolve allowed merge methods BEFORE authoring a merge commit. A rebase-only repo cannot land one: --rebase flattens the merge and rewrites exactly the SHAs it existed to preserve. Today allow_merge_commit only appears at the merge step, which is too late to reshape the work. - Conflicts are not the whole merge. git merge only conflicts on paths both sides touched; files the other side ADDED that you never had merge silently. A fork that had unvendored resolved 545 vendor conflicts -- and 252 more files merged cleanly as additions, which would have re-vendored the project with a green merge. - DCO and third-party history are structurally incompatible: sign-off is an authorship declaration, so no fork can sign off upstream's commits. Notes that the DCO bot's own suggested 'rebase --signoff' is actively wrong here (it flattens the merge and forges sign-offs), and gives the port-and-re-author path instead. Cross-links the existing 'Signing and DCO Failures' section, whose steps do not apply when the unsigned commits belong to someone else. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
There was a problem hiding this comment.
Code Review
This pull request adds a comprehensive guide on 'Merging Divergent Upstream History (Forks)' to the git workflow documentation, detailing strategies for handling history constraints, allowed merge methods, silent additions under deleted paths, and DCO compatibility with third-party history. The review feedback suggests using git cherry instead of git log to identify unique commits more accurately, renaming the $UP variable to $UPSTREAM for clarity, and applying optional chaining and default values in jq commands to prevent fatal errors when parsing GitHub API responses.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
- Define UPSTREAM/FORK. The snippet used an undefined $UP. - Prefer 'git cherry' over 'git log' for 'what we add': it compares by patch-id, so a change upstream already carries under a different SHA is reported as already-there rather than counted as ours. Verified on the originating fork: git log reported 27 commits, git cherry 26 -- the difference being the fork's re-authored port of an upstream fix, which git cherry matched to the upstream original despite a different SHA, author and commit message. Since the whole point of the section is measuring the delta before choosing a mechanism, an overstated delta is the wrong input. Declined the accompanying jq optional-chaining suggestion: jq field access on null returns null and exits 0 (verified), so '.a.b' on a null '.a' is not the fatal error the review described. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
|



Catching a fork up with its upstream reads as a merge-strategy question. It's mostly a scope question — and four traps sit between the two. All four were hit in a single session on an archived-upstream fork (netresearch/terraform-provider-ad#14, closed in favour of #16).
What's added
1. "Merge" is a constraint on history rewriting — not an instruction to import everything
When a maintainer rejects a rebase because "rebasing would break our releases" and says "we need to merge", the load-bearing part is don't rewrite our release SHAs. Cherry-pick satisfies that too.
The fork was 22 ahead / 11 behind. The merge produced 548 conflicts and 11 DCO-breaking commits — and the entire net gain was a two-line typo fix. The other 10 upstream commits were vendor churn, upstream's own release CI, and dependency bumps the fork had already surpassed. The delta had been measured before the merge; the merge ran anyway. The maintainer's correction — "if the typo is the only change, pull in the typo, nothing more" — was the whole job.
Adds the delta-measurement commands to run before choosing the mechanism.
2. Resolve allowed merge methods before authoring a merge commit
A rebase-only repo cannot land a merge commit:
--rebaseflattens it and rewrites exactly the SHAs the merge existed to preserve. Todayallow_merge_commitappears only in the merge step of the lifecycle checklist — too late to reshape the work.3. Conflicts are not the whole merge — check clean ADDs under a deleted path
git mergeonly conflicts on paths both sides touched. Files the other side added that you never had merge silently.The fork had run
chore: unvendor; upstream still vendors. 545 paths conflictedDU(deleted by us / modified by them) — and 252 more merged cleanly as additions, because upstream's vendor upgrade had added files the fork never carried. Resolving only the conflicts would have re-vendored the project and reverted the unvendoring, with a green merge and no warning.Includes the
git rm -rfqdetail — plaingit rmrefuses when the index has staged changes.4. DCO and third-party history are structurally incompatible
Sign-off is an authorship declaration, so no fork can sign off upstream's commits. Any fork merging any third-party history fails DCO by construction — it's a property of the operation, not a mistake.
Flags that the DCO bot's own advice is wrong here: it suggests
git rebase HEAD~N --signoff, which flattens the merge and forges sign-offs on other people's commits. Gives the port-and-re-author path instead (cherry-pick -xkeeps the original author and still fails DCO;--amend --reset-author --signoffmakes it honestly yours).Placement
New section after the merge-strategy comparison in
pull-request-workflow.md, plus a cross-link fromSigning and DCO Failures— whose steps don't apply when the unsigned commits are someone else's.Verification
markdownlint-cli2: 0 errors. Anchor target confirmed to resolve. Docs-only, no version bump — matching05d53d1and the surroundingdocs(<reference>):history. Every command shown was run in the originating session.