Stitch
central stitch <repo> is for a narrower situation than import:
someone exported a change, then reworked the commit(s) that just landed in
the subrepo’s own history - splitting one commit into a nicer sequence,
squashing, reordering, rewording - without changing the tree they arrive at.
repo/<repo>/.gitrepo in central still names the pre-rewrite commit, which
no longer exists on the subrepo’s subrepo branch.
Running import at this point would either fail outright (the old commit
isn’t an ancestor of the new tip any more) or, if it somehow went through,
apply an empty patch for no reason - there is nothing to actually bring in,
since the tree hasn’t changed. stitch is the narrow fix: it just repoints
.gitrepo at the subrepo’s new tip, and commits that update with an
auto-generated message - central’s copy of a subrepo isn’t public history,
so unlike export there’s nothing worth writing by hand here.
The required pre-conditions:
- The
subrepobranch has actually moved since the last sync. - There is no real content diff between the commit recorded in
.gitrepoand the subrepo’s current tip - i.e. this really is a pure history rewrite. - Central has no local changes of its own under
repo/<repo>/since the last sync.
Rewriting history after an export
Suppose a change lands in central and gets exported as usual, as one squashed commit:
$ central export widget -m "Document feature A and B"
==================== widget ====================
[ OK ] Applied patch in the subrepo.
[ OK ] Exported to [widget].
Now, imagine that squashed commit gets reworked directly in widget’s
own history into two smaller, better organized commits - reaching the
exact same final README.md either way. .gitrepo still names the
abandoned squash commit, which no longer exists on subrepo:
import would refuse here - the commit .gitrepo names is gone, so it
can’t tell this apart from a more troubling rewrite. stitch recognizes
it for what it is and just catches .gitrepo up, committing the update
itself with an auto-generated message:
$ central stitch widget
==================== widget ====================
[ OK ] Stitched [widget].
Stitch repo widget
export widget
Document feature A and B
Add fake subrepo widget
Initial commit
Running stitch again right away is a clean error - .gitrepo is
already caught up, so there is nothing left to stitch:
$ central stitch widget
==================== widget ====================
File "$CENTRAL_ROOT/repo/widget/.gitrepo", line 1, characters 0-0:
Error: Nothing to stitch: the [subrepo] branch of [widget] is already the
commit recorded in [.gitrepo].
[123]
And central todo confirms both sides agree - widget’s own main
just needs to catch up, same as after any ordinary export:
$ central todo
┌──────────┬──────────────┬──────┐
│ Repo │ Next step │ Diff │
├──────────┼──────────────┼──────┤
│ central │ push │ 8 │
│ widget │ advance-main │ │
└──────────┴──────────────┴──────┘
Guardrails
stitch only repoints .gitrepo - it never brings in real content changes.
If the subrepo’s tip actually differs in substance from what .gitrepo
records, this isn’t a pure history rewrite any more, and stitch refuses
rather than silently pretending the trees still match:
$ central stitch widget
==================== widget ====================
File "$CENTRAL_ROOT/repo/widget/.gitrepo", line 1, characters 0-0:
Error: Nothing to stitch: the [subrepo] branch of [widget] is already the
commit recorded in [.gitrepo].
[123]
$ central stitch widget
==================== widget ====================
File "$CENTRAL_ROOT/repo/widget/.gitrepo", line 1, characters 0-0:
Error: Cannot stitch: "repo/widget" has content changes between the commit
recorded in [.gitrepo] and its current tip - this isn't a pure history
rewrite.
Hint: Use [central import] instead to bring those changes in.
[123]
And if central itself has moved on with local changes of its own under
repo/<repo>/ since the last sync - even alongside an otherwise legitimate
history rewrite upstream - stitch refuses too, since a plain re-pointing
of .gitrepo can no longer account for the full picture:
$ central export widget -m "Document feature A"
==================== widget ====================
[ OK ] Applied patch in the subrepo.
[ OK ] Exported to [widget].
$ central stitch widget
==================== widget ====================
File "$CENTRAL_ROOT/repo/widget/.gitrepo", line 1, characters 0-0:
Error: Cannot stitch: central has local changes of its own under
"repo/widget" since the last sync.
Hint: Export or import those changes first, then stitch.
[123]
And as a precondition, stitch first checks that central’s own working
tree is clean - an unstaged edit is rejected outright, before anything else
is even looked at:
$ central stitch widget
Error: Repo "$CENTRAL_ROOT" has uncommitted changes.
M README.md
Hint: Commit or stash them first.
[123]