Bumping the sync point
A push never writes to the monorepo,
so after one, .splice still names the upstream commit from before it.
git splice pull --bump records the upstream branch anyway, in a
commit that only changes .splice, like a submodule bump. Later rebuilds then start at the pushed commit, instead
of rebuilding every commit pushed since the last pull.
Don't bump too often. A bump only saves work: without it, a push still
sends only what isn't upstream yet. But each bump is one more commit
that changes .splice, and two branches that record different commits
there conflict when they're merged, even where the files would merge
cleanly.
Bump on main. If the library squash-merges its pull requests, a bump
on a feature branch makes .splice conflict when the branch is merged
after the library's. Merged before, it leaves main's .splice naming
the pull request's commit, which the library may delete. This workflow
shows a bump on main, both cases on a feature branch, and how to get
out of the conflict.
On main, after a push
Bring pkg-a up to date, as in the main walkthrough,
then change it and push:
$ git splice pull vendor/pkg-a >/dev/null
$ echo "a faster parser" >>vendor/pkg-a/file.txt && git commit -qam "pkg-a: a faster parser"
$ git splice push vendor/pkg-a
ok vendor/pkg-a: pushed 9816d9f to main
A pull right after the push has nothing to bring in, and leaves .splice
as it was:
$ git splice pull vendor/pkg-a
ok vendor/pkg-a fetched
ok vendor/pkg-a: nothing to pull
$ git log -1 --format=%s "$(git config --file vendor/pkg-a/.splice splice.commit)"
pkg-a: a second commit, after the clone
With --bump, it records the pushed commit:
$ git splice pull --bump vendor/pkg-a
ok vendor/pkg-a fetched
ok vendor/pkg-a: bumped the synced commit to 9816d9f
$ git log -1 --format=%s "$(git config --file vendor/pkg-a/.splice splice.commit)"
pkg-a: a faster parser
$ git log -1 --format=%s
splice: bump vendor/pkg-a from main at 9816d9f
bump-after-push shows what that changes for the rebuild.
On a feature branch: a conflict
A feature that changes the library and the monorepo's code that uses it:
$ git switch -q -c feature
$ echo "an option" >>vendor/pkg-a/file.txt && mkdir -p app && echo "uses the option" >app/main.txt && git add app && git commit -qam "pkg-a: an option, and the app uses it"
The push creates pkg-a's feature branch, the library's pull request.
A bump then records it on the monorepo's feature:
$ git splice push vendor/pkg-a
?? vendor/pkg-a: upstream has no 'feature' branch yet -- this push creates it
ok vendor/pkg-a: pushed 556e8b7 to feature
$ git splice pull --bump vendor/pkg-a
ok vendor/pkg-a fetched
ok vendor/pkg-a: bumped the synced commit to 556e8b7
The library squash-merges the pull request: its main gets the same
change as a new commit. Here in a clone of pkg-a, as its maintainer
would:
$ git clone -q "$WALKTHROUGH/upstream/pkg-a.git" "$WALKTHROUGH/pkg-a" && cd "$WALKTHROUGH/pkg-a" && git config user.name "Maintainer" && git config user.email "maintainer@example.com"
$ git merge -q --squash origin/feature && git commit -q -m "an option (#1)" && git push -q origin main
Squash commit -- not updating HEAD
Back in the monorepo, main pulls it:
$ cd "$WALKTHROUGH/monorepo" && git switch -q main
$ git splice pull vendor/pkg-a
ok vendor/pkg-a fetched (main moved 9816d9f..0d27eb0)
ok vendor/pkg-a: pulled 0d27eb0
main has the library's change now, but not the app's. So the monorepo's
feature still needs merging, and that conflicts: main changed
.splice to the squashed commit, and the bump on feature changed the
same line to the pull request's commit. A squash merge computes its
files like any merge, so it conflicts too:
$ git merge --squash feature
Auto-merging vendor/pkg-a/.splice
CONFLICT (content): Merge conflict in vendor/pkg-a/.splice
Squash commit -- not updating HEAD
Automatic merge failed; fix conflicts and then commit the result.
[1]
$ git reset -q --hard
Without the bump, feature wouldn't have changed .splice, and the merge
would take main's.
The way out: rebase the library's branch
Rebase the library's feature onto its main. The squashed commit
already has the change, so the rebase drops it, and feature becomes the
library's main:
$ cd "$WALKTHROUGH/pkg-a" && git switch -q feature && git -c advice.skippedCherryPicks=false rebase -q main && git push -q -f origin feature
$ git log -1 --format=%s feature
an option (#1)
The monorepo's feature pulls it. The folder already has its files, so
pull records it, without the need for --bump:
$ cd "$WALKTHROUGH/monorepo" && git switch -q feature
$ git splice pull vendor/pkg-a
ok vendor/pkg-a fetched (feature moved 556e8b7..0d27eb0)
ok vendor/pkg-a: recorded 0d27eb0 as the synced commit -- the folder already has its files
Now both branches name the same commit in .splice, and the merge only
brings in the app:
$ git switch -q main && git merge --squash feature
Automatic merge went well; stopped before committing as requested
Squash commit -- not updating HEAD
$ git status --short
A app/main.txt
$ git commit -q -m "app: use pkg-a's option" && git splice status
On branch main
up to date vendor/pkg-a
If the library deleted its feature branch after the merge, there's
nothing to pull. Merge main into the monorepo's feature instead, and
resolve .splice to main's version.
Merged first: a commit that disappears
Another feature, with a bump on its branch. This time, main merges it
before the library merges its pull request:
$ git switch -q -c feature-2 && echo "a second option" >>vendor/pkg-a/file.txt && git commit -qam "pkg-a: a second option"
$ git splice push vendor/pkg-a >/dev/null && git splice pull --bump vendor/pkg-a
ok vendor/pkg-a fetched
ok vendor/pkg-a: bumped the synced commit to f7e1048
$ git switch -q main && git merge -q --no-ff -m "Merge branch 'feature-2'" feature-2
main's .splice now names a commit of the library's feature-2:
$ git log -1 --format=%s "$(git config --file vendor/pkg-a/.splice splice.commit)"
pkg-a: a second option
The library squash-merges the pull request and deletes its branch, as many hosts do:
$ cd "$WALKTHROUGH/pkg-a" && git fetch -q && git switch -q main && git merge -q --squash origin/feature-2 && git commit -q -m "a second option (#2)" && git push -q origin main :feature-2
Squash commit -- not updating HEAD
Then it goes on with a change of its own:
$ echo "a third option" >>file.txt && git commit -qam "a third option" && git push -q origin main
Nothing refers to the pull request's commit any more, and the library's
gc removes it:
$ git -C "$WALKTHROUGH/upstream/pkg-a.git" gc -q --prune=now && git -C "$WALKTHROUGH/upstream/pkg-a.git" cat-file -t "$(git -C "$WALKTHROUGH/monorepo" config --file vendor/pkg-a/.splice splice.commit)"
fatal: git cat-file: could not get object info
[128]
The monorepo that bumped still has the commit, but a fresh clone of it can't fetch it:
$ cd "$WALKTHROUGH" && git clone -q --config "url.$WALKTHROUGH/upstream/.insteadOf=https://git.example.com/" "file://$WALKTHROUGH/monorepo" colleague && cd colleague
$ git splice fetch vendor/pkg-a
ok vendor/pkg-a fetched
$ git splice status vendor/pkg-a
On branch main
!! unrelated history vendor/pkg-a see 'git splice merge vendor/pkg-a' for options
Without the bump, main's .splice would name a commit on the
library's main, which it keeps, and a pull would bring in
a third option.
A company fork
The rebase needs a library branch you can force-push. For a library you
don't maintain, that's a branch in your company's fork of it: push the
feature there, open the pull request from the fork, and rebase the fork's
branch once the original squash-merged it. A splice that follows both the
fork and the original needs several upstreams in one .splice
(#108).