Scenario: a recursive pull, step by step
One git splice pull --recursive does a lot between its start and its
end: it fetches every upstream, merges one splice after another, top-down,
and makes one commit of it all. This page runs it once, records each ref
it moves, then winds the monorepo back and replays the record, one step
at a time, with the tree after each.
No merge conflicts here: the monorepo has no commits of its own, and each upstream changed only its own files.
Output
setup.bash builds this state, and has the helpers
that record, rewind and replay:
$ build_scenario scenario_recursive_pull
Each upstream moves on, and a's splices e in:
$ for x in b c d; do
> git clone -q "https://git.example.com/$x.git" "../$x-work" &&
> echo "$x upstream" >>"../$x-work/file.txt" &&
> git -C "../$x-work" commit -q -am "${x}2: $x upstream" &&
> git -C "../$x-work" push -q origin main
> done
$ git clone -q https://git.example.com/a.git ../a-work &&
> cd ../a-work &&
> git splice clone https://git.example.com/e.git e >/dev/null &&
> echo "a upstream" >>file.txt &&
> git commit -q --amend -am "a2: a upstream, and e spliced in" &&
> git push -q origin main &&
> cd ../monorepo
The whole pull
$ record_refs ../refs.log git splice pull --recursive vendor/a
ok vendor/a fetched (main moved 764d9c4..6d12ed8)
ok vendor/a/b fetched (main moved f815a3c..59ed2fb)
ok vendor/a/b/c fetched (main moved 8c169b6..94cad5e)
ok vendor/a/d fetched (main moved 2c64d15..36c850e)
ok vendor/a: pulled 6d12ed8
ok vendor/a/e fetched
ok vendor/a/e: nothing to pull
ok vendor/a/b: pulled 59ed2fb
ok vendor/a/b/c: pulled 94cad5e
ok vendor/a/d: pulled 36c850e
ok vendor/a: 4 pulls made one commit, 9b51e79
Step by step
Wound back to before the pull, the tree is as it was:
$ rewind_refs ../refs.log
1. Discover
The fetches move the refs of the upstreams, and nothing else. The tree records what the monorepo has, so it doesn't change yet:
$ replay_refs ../refs.log refs/splices/
refs/splices/a/heads/main
refs/splices/b/heads/main
refs/splices/c/heads/main
refs/splices/d/heads/main
2. Merge vendor/a/
The pull starts, and merges a's upstream first. Its a2 brings e/
in, a splice now:
$ replay_refs ../refs.log refs/heads/main
SPLICE_PULL_START
refs/heads/main
3. Merge b/
e/ is fetched, now that it's known, and has nothing to merge. b's
upstream merges into vendor/a/'s folder, which gets a commit of its
own, pb':
$ replay_refs ../refs.log refs/heads/main
refs/heads/main
refs/splices/e/heads/main
4. Merge c/
c/ is inside b/, inside vendor/a/: both get the copy pc'.
$ replay_refs ../refs.log refs/heads/main
refs/heads/main
5. Merge d/
$ replay_refs ../refs.log refs/heads/main
refs/heads/main
6. One commit
The four pulls become one commit, p, and the pull is done: the mark where it started is gone. Each splice's history has the copy p' where it had pb', pc' or pd':
$ replay_refs ../refs.log SPLICE_PULL_START
SPLICE_PULL_START
refs/heads/main
That's the tree the whole pull ended with, above: