Scenario: up-to-date, worked on in a worktree of the rebuild
git splice rebuild vendor/a prints the splice's history as its upstream
would have it: a commit of the upstream's repository, with the folder's
files at its root. Checked out in a worktree of the monorepo, it's that
repository, to work in as if it were a clone: build it on its own, or run
git-splice there for a splice inside it.
git splice merge --rebuilt-commit brings what was committed there back
into vendor/a/. It's a three-way merge from where the commit left the
rebuild, so the monorepo's own changes since then stay. The synced commit
doesn't move: the commit is local work, and the next push sends it.
It brings back the worktree's file changes, and nothing else:
- Its history stays behind, as with
git merge --squash: a branch that goes on is rebased onto the new rebuild first. - A commit without file changes, e.g. one reworded, has nothing to bring back.
- Commits of the splice's upstream, e.g. from a pull in the worktree, aren't the monorepo's own changes: the merge refuses them (the upstream pulled in a worktree).
Output
setup.bash builds this state:
$ build_scenario scenario_up_to_date
The rebuild, checked out on a branch of its own:
$ git worktree add -q -b work-on-a ../a-work "$(git splice rebuild vendor/a)"
$ ls ../a-work
file.txt
A commit there:
$ echo "from the worktree" >../a-work/other.txt &&
> git -C ../a-work add other.txt &&
> git -C ../a-work commit -q -m "add other.txt"
Meanwhile, the monorepo changes vendor/a/ too:
$ echo "monorepo change" >>vendor/a/file.txt &&
> git commit -q -am "monorepo change"
Two lines of work start at the rebuild, k: the monorepo's change c,
which the rebuild copies to c', and o, the worktree's commit, on a
branch of the monorepo no upstream has, work-on-a:
Back into the monorepo
$ git splice merge --rebuilt-commit work-on-a vendor/a
ok vendor/a: merged d55cb3f
One commit, with the worktree commit's message, and both changes:
$ git log --format=%s -3
add other.txt
monorepo change
add vendor/a
$ cat vendor/a/other.txt vendor/a/file.txt
from the worktree
seed
monorepo change
The merge's commit, m, has o's changes, not o: the rebuild has m' on top of c', and o stays on its branch:
.splice still names seed, so both changes are ahead, and the push
sends them:
$ git log -1 --format=%s "$(git config --file vendor/a/.splice splice.commit)"
seed
$ git splice status
On branch main
ahead 2 vendor/a
$ git splice push vendor/a
ok vendor/a: pushed 895449a to main
$ git -C "$UPSTREAM" log --format=%s main
add other.txt
monorepo change
seed
Continued, and merged again
The rebuild doesn't have o, only m', so the worktree's branch is rebased onto it before it goes on, as a branch after a squash merge is. The rebase leaves o out, since m' has its changes:
$ git -C ../a-work rebase -q "$(git splice rebuild vendor/a)" &&
> git -C ../a-work log --format=%s
hint: use --reapply-cherry-picks to include skipped commits
hint: Disable this message with "git config set advice.skippedCherryPicks false"
add other.txt
monorepo change
seed
The push sent c' and m' upstream, and the worktree's branch is the rebuild now:
It goes on, and removes the file again, in d:
$ git -C ../a-work rm -q other.txt &&
> git -C ../a-work commit -q -m "remove other.txt"
The branch starts at m' now, so the merge starts there too. The only
change since is d, which removes other.txt, and so does the merge:
$ git splice merge --rebuilt-commit work-on-a vendor/a
ok vendor/a: merged 179d029
$ git log --format=%s -1
remove other.txt
$ ls vendor/a
file.txt
Without the rebase, the branch would still start at k, and so would
the merge. other.txt didn't exist there, so it would look like the
monorepo's own addition, and stay.
Nothing to merge
merge --rebuilt-commit brings back files, not messages. A commit in the
worktree that changes no files has nothing to bring back, like e, d
reworded:
$ git -C ../a-work commit -q --amend -m "remove other.txt, reworded"
e has the files of d, which the monorepo merged as r. The rebuild's copy of r, r', is d itself here: the same files, parent, message and date make the same commit.
So the merge leaves the monorepo as it is, r and its message too, and no cherry-pick in progress:
$ git splice merge --rebuilt-commit work-on-a vendor/a
ok vendor/a: dbb456a's changes are in the folder already -- nothing to merge
$ git log --format=%s -1
remove other.txt
$ git status --short
A reworded message goes upstream with git splice push --rebuilt-commit instead (edited before
push).