Repository navigation
feat(fork-sync): snapshot sync, git submodules, and AI model fallback - #4424
Merged
Vladimir Morozov (vmoroz) merged 4 commits intoOct 21, 2026
Merged
Vladimir Morozov (vmoroz) merged 4 commits into
Vladimir Morozov (vmoroz) merged 4 commits into
Conversation
…I model fallback Make fork-sync able to roll huge, submodule-based upstreams such as Chromium on a regular cadence: - fetchMode "snapshot": fetch only the base and target commits (depth 1) and merge synthetic snapshots of the synced scope whose merge base is exactly the last synced commit, so release tags on different branches roll cleanly. - submodules: follow listed gitlinks at the SHAs upstream pins, with fallback URLs, grafted into the synced tree so merge/conflict/apply work unchanged. - keepLocalDeletions: pruned files stay pruned, new upstream files are added, only upstream deletions are applied; warns about .syncignore-hidden files. - File entries in sparsePaths; history-mode tag/commit fetch, capped PR-notes commit table, fetch hygiene; safer --continue checkpoints. Keep ai-merge working as AI models change: - Copilot CLI is the default provider with model "auto" (Copilot routes each request) and reasoning effort "low" where supported. - aiMerge.model accepts an ordered list; unavailable models fall back to the next entry with a warning. - Fix hunks rejected as context mismatches when the context ends with blank lines (e.g. a file's final newline). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vladimir Morozov (vmoroz)
requested review from
Jason Morse (JasonVMo),
Saad Najmi (Saadnajmi),
acoates-ms and
Tommy Nguyen (tido64)
as code owners
October 21, 2026 02:54
Merge branch names used a one-second timestamp, so two syncs of the same dependency within one second failed with "a branch named ... already exists" (seen in CI, where the e2e syncs run back to back). Append a numeric suffix when the name is taken; add a test that occupies upcoming names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
On fast CI the previous sync's branch for the current second is still checked out in the sync repo, so `git branch -f` fails. Create only the missing names; existing ones are already taken. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
git reports the repository root with symlinks, junctions and Windows 8.3 short names resolved, but the manifest and dependency paths came from the working directory as given. When the two spellings differed (e.g. a TEMP of C:\Users\RUNNER~1 on CI, a subst drive, or -C through a junction), the dependency prefix became "../../.." and every git listing failed with "is outside repository". Resolve the working directory, manifest directory and repo root with realpath first; add a test that syncs through a junction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vladimir Morozov (vmoroz)
enabled auto-merge (squash)
October 21, 2026 04:44
Anandraj (mganandraj)
approved these changes
Oct 21, 2026
Saad Najmi (Saadnajmi)
approved these changes
Oct 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Lets
fork-syncroll a large, submodule-based upstream such as Chromium on a regularcadence. Before this change, rolling a vendored Chromium subset from one release tag to the
next failed in several places: release tags are on separate branches and are not ancestors of
each other, new tags never reached the cached clone,
tree:0history fetches took close to anhour and then failed, content from git submodules was invisible, and every sync re-added files
the fork had deliberately removed. AI merge had also gone stale: the configured Claude setup no
longer worked, and a retired model ID made every hunk fail.
Snapshot sync (
fetchMode: "snapshot") — fetches only the base and target commits(
--depth=1) and merges two synthetic commits that contain just the synced scope, the targetparented on the base. The merge base is exactly the last synced commit, so release-tag rolls
work across branches (e.g.
149.0.7827.149→156.0.8078.48) without keeping an upstreamhistory cache. Tags resolve with
ls-remote, and PR notes link the upstream range instead oflisting every commit.
Git submodules (
submodules) — listed submodules are synced at the SHAs the upstreamcommit pins, at both base and target. Their files are grafted into the synced tree, so 3-way
merge, conflicts,
.syncignore, and deletions work on them unchanged, and pins can never driftfrom upstream's. Optional
fallbackUrlscover mirrors that dropped an old commit. URLs from.gitmodulesmay not use the localfiletransport. PR notes list pin moves, URL changes, andgitlinks that appeared, disappeared, or are not followed.
Pruned forks (
keepLocalDeletions) — files the fork removed stay removed, new upstreamfiles are added, and only files that upstream deleted are deleted locally, so local-only files
are never touched. A newly configured submodule or sparse path is imported in full. fork-sync
also warns about vendored files hidden by
.syncignorethat would silently stop updating.AI merge — the GitHub Copilot CLI is now the default provider, and its default model is
auto, so Copilot routes each request and no model ID goes stale.aiMerge.modelaccepts anordered list, and a model the CLI reports as unavailable falls back to the next entry with a
warning. A new
reasoningEffortsetting (defaultlow, skipped for models that reject it)keeps the two calls per hunk cheap. Also fixes hunks being rejected as context mismatches when
the conflict is followed by blank lines, e.g. near the end of a file.
Smaller fixes —
sparsePathsentries may be files (e.g.LICENSE).--tagor--committhatgit fetchdid not bring in, and caps thePR-notes commit table at 200 rows.
--continueis safer: it refuses changed options, and the checkpoint is kept until thechanges are applied.
a junction or symlink, or a
substdrive. Previously every listing failed with "isoutside repository".
CLAUDE.mdnow points to a newAGENTS.md, as at the repo root.History mode with none of the new options set behaves as before, apart from the fixes above.
Test plan
above: release branches, a whole-directory submodule served only by a fallback URL, unfollowed
and newly appearing gitlinks, prunes,
subDir, conflicts with--continueand--abort,switching modes, and config validation. Unit tests cover the new git plumbing, PR-notes
formatting, and model fallback.
yarn testpasses, and the Copilot integration tests passwith
RUN_INTEGRATION=1.true no-op; before, it re-added about 3,000 removed files. A roll from
149.0.7827.149to156.0.8078.48completed the merge with 6 expected conflicts, all in files the fork modifies."fetchMode": "snapshot"in a dependency'ssync-config.jsonandrun
fork-sync --dep <name> --tag <tag>. See the README sections "Snapshot mode", "Gitsubmodules", "Pruned forks", and "Choosing AI models".