Scenario: nested-splices
One splice below another. a's upstream uses git-splice itself: it has b's
upstream spliced in at b/, with a b/.splice of its own. Cloning a's
upstream into the monorepo brings that .splice along, so vendor/a/b/
is a splice in the monorepo too.
- b's upstream (
$UPSTREAM-b.git, reached ashttps://git.example.com/b.git):b seed. - a's upstream (
$UPSTREAM):a seed, thenadd b, which spliced b's upstream in atb/. - Monorepo:
vendor/a/from a's upstream, andvendor/a/b/below it, from b's upstream, both fetched.
Each push sends its folder without its own .splice. So a's push sends
b's .splice with b's files, and in a's upstream, b/ stays a splice
that git-splice can pull and push there.
The design
explains why both repositories agree on b's state.
Output
setup.bash builds this state:
$ build_scenario scenario_nested_splices https://git.example.com/b.git
Both splices are up to date:
$ git splice status
On branch main
up to date vendor/a
up to date vendor/a/b
A change in b is a change in a too:
$ echo "b local" >>vendor/a/b/file.txt && git commit -q -a -m "b local"
$ git splice status
On branch main
ahead 1 vendor/a
ahead 1 vendor/a/b
Each push sends its own folder, bottom-up: b's upstream gets the change,
without .splice:
$ git splice push vendor/a/b vendor/a
ok vendor/a/b: pushed 701ab17 to main
ok vendor/a: pushed b42292d to main
$ git -C "$UPSTREAM-b.git" ls-tree -r --name-only main
file.txt
a's upstream gets it too, with b's .splice:
$ git -C "$UPSTREAM" ls-tree -r --name-only main
b/.splice
b/file.txt
file.txt
a's upstream pulls b
Someone working in a's upstream pulls b's new commit there, and pushes
the result. (seed_bare_repo, from
fixtures.bash, commits a line to a file
of b's upstream.)
$ seed_bare_repo "$UPSTREAM-b.git" "b upstream change" main other.txt
$ git clone -q "$UPSTREAM" ../a-work && git -C ../a-work -c user.name=Test -c user.email=test@example.com splice pull b && git -C ../a-work push -q origin main
ok b fetched
ok b: pulled 527b1a2
Meanwhile, the monorepo has a new commit in b:
$ echo "b local 2" >>vendor/a/b/file.txt && git commit -q -a -m "b local 2"
Pulling a brings in b's .splice as a's upstream has it, with a newer
synced commit. pull fetches the splices below a too, so that commit is
there:
$ git splice pull vendor/a
ok vendor/a fetched (main moved b42292d..1ca3147)
ok vendor/a/b fetched (main moved 701ab17..527b1a2)
ok vendor/a: pulled 1ca3147
The pull records b's new synced commit. b's unpushed commit is kept, and the next push joins it with the change in b's upstream:
$ git splice status
On branch main
ahead 2 vendor/a
ahead 2 vendor/a/b
$ git splice push vendor/a/b && git -C "$UPSTREAM-b.git" log --graph --format=%s main
ok vendor/a/b: pushed c5dc450 to main
* splice: pull vendor/a from main at 1ca3147
|\
| * b upstream change
* | b local 2
|/
* b local
* b seed
If the monorepo had pulled b as well, to a different commit, the pull of a would have conflicted: see Limits.
Once the monorepo has pushed a change in b, another monorepo that splices
a in rebuilds b's history up to the clone from a's upstream, so b's
first change there goes on top of the pushed one:
spliced into another monorepo. That history comes
from the splice above with the newest last pull, even two levels up
(three levels); not where a's upstream has
another splice at b/ (replaced above); and it
doesn't drop what b's upstream got from the monorepo directly
(pushed and made above).