Import
central import <repo> brings commits from the tip of the subrepo’s
subrepo branch - normally landed there by fetching from the subrepo’s real
remote - into repo/REPO. -m MSG is optional and defaults to "Import changes from REPO".
Unlike export, this has to account for central having moved on since the
last sync - so it picks between two ways of bringing the change in,
depending on whether central has any local changes of its own under
repo/REPO:
- If central hasn’t touched
repo/REPOat all since the last sync,repo/REPOat central’s current HEAD is - by construction - exactly what it was at the last sync point, so the subrepo’s diff is guaranteed to apply there too. There is nothing to merge, soimportdoesn’t build one: it applies the diff directly as a single new commit on top of HEAD. This is the default, and it keeps history linear in the common case where central had no reason to conflict with what the subrepo brings in. - Otherwise - central does have local changes of its own under
repo/REPO-importfalls back to an ordinary two-parentgit merge: it builds a new commit as a direct child of the central revision recorded inrepo/REPO/.gitrepo- not of the current HEAD - and applies the subrepo’s diff there, where it is guaranteed to apply cleanly regardless of what else happened on central’s actual HEAD since. That commit (the “import commit”) also updates.gitrepoto record the new sync point. Merging it into the active branch is then an ordinarygit merge: if there is a real conflict, git surfaces it exactly as it always does, for a human to resolve.
Applying directly
A fake central and a fake widget, as usual - someone pushes directly to
widget’s subrepo branch (standing in for something fetched from its
real remote), while central hasn’t touched repo/widget/ since the last
sync. So import applies the upstream change straight onto HEAD, no merge
needed:
$ central import widget
[ OK ] Imported into [main] directly (no merge needed).
A single, linear commit lands directly on top of HEAD - no second
parent, no merge commit. -m was left out here, so the message falls
back to "Import changes from widget":
Import changes from widget
Add fake subrepo widget
Initial commit
# widget
This is a fake [widget] repo, generated by [Central_test_helpers] for tests.
Edited directly upstream.
Guardrails
Running import again right away, with nothing new upstream, is a clean
error rather than an empty commit - symmetric to export’s own guard:
$ central import widget
Error: Nothing to import: the [subrepo] branch of [widget] has not moved
since the last sync.
[123]
And just like export, import first checks that central’s own working
tree is clean - an unstaged edit is rejected outright:
$ central import widget
Error: Repo "$CENTRAL_ROOT" has uncommitted changes.
M README.md
Hint: Commit or stash them first.
[123]
Falling back to a merge
This time, central does touch something under repo/widget/ since the
last sync - a new file of its own, NOTES.md, unrelated to the file
upstream changed. import can no longer assume repo/widget/ is
untouched, so it falls back to building an import commit as a child of the
last sync point and merging it in. Since the two sides touch different
files, the merge still completes cleanly on its own:
$ central import widget
[ OK ] Built the import commit.
Merge made by the 'ort' strategy.
repo/widget/.gitrepo | 4 ++--
repo/widget/README.md | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
[ OK ] Imported into [main].
Unlike the direct case above, the import commit sits as a child of the old sync point, not of central’s HEAD at the time - a separate line of history, joined by the merge:
Merge widget import
Add local notes under widget
Add fake subrepo widget
Initial commit
A real conflict
Same fallback, but this time central and the subrepo both edit the very
same line under repo/widget/ since the last sync:
$ central import widget -m "Bring in upstream retitle"
[ OK ] Built the import commit.
Auto-merging repo/widget/README.md
CONFLICT (content): Merge conflict in repo/widget/README.md
Automatic merge failed; fix conflicts and then commit the result.
Error: Merge conflict while importing - resolve the conflicts above in
[main], then [git add] the resolved files and [git commit] to finish the
merge.
Hint: .gitrepo has already been updated as part of the import commit being
merged - no further action needed there once the merge is complete.
[123]
Central is left in the middle of the merge, exactly as an ordinary
git merge would - conflict markers included, with the trailing
revision on >>>>>>> naming the import commit, the side being merged
in. That revision is a deterministic mock rather than the real sha -
see Deterministic Revisions for why:
<<<<<<< HEAD
# widget, edited by central
=======
# widget, retitled upstream
>>>>>>> 1185512b92d612b25613f2e5b473e5231185512b
Resolving it is the same as for any git merge conflict - pick a
resolution, git add, git commit:
Resolve README retitle conflict
Central retitles the README
Add fake subrepo widget
Initial commit
.gitrepo was already updated as part of the import commit, so
export is available again right away - it carries the resolution
itself out to widget, since that’s what central’s own history now
disagrees with:
$ central export widget -m "Resolve conflicting retitle"
==================== widget ====================
[ OK ] Applied patch in the subrepo.
[ OK ] Exported to [widget].
Resolve conflicting retitle
Upstream retitles the README
Initial commit