Importing a change
The other direction: commits made directly in a subrepo’s own history -
typically because someone fetched from its real, public remote - don’t show
up under repo/<name>/ in central on their own. Bringing them in is:
central import <name>
-m "<message>" is optional here - it defaults to "Import changes from <name>". Unlike export, repo/<name>/ in central isn’t public history, so
there’s rarely anything worth saying beyond that.
Unlike export, central may itself have moved on with changes of its own in
the meantime, so import has to pick between two ways of bringing the
subrepo’s commits in:
- If central hasn’t touched
repo/<name>/at all since the last sync, the subrepo’s changes are applied straight onto the current commit, as a single new commit - no merge, because there is nothing underrepo/<name>/for it to possibly conflict with. This is the default, and keeps history linear in the common case. - Otherwise - central does have changes of its own under
repo/<name>/-importfalls back to an ordinary two-parentgit merge: it builds a new commit carrying the subrepo’s changes, then merges it into whatever branch you have checked out (normallymain).
The default: applying directly
Say new commits landed on widget’s own subrepo branch (from fetching its
real remote), while central moved on with an unrelated change of its own -
elsewhere, outside repo/widget/. central todo already knows there’s
something to bring in:
$ central todo
┌──────────┬───────────┬──────┐
│ Repo │ Next step │ Diff │
├──────────┼───────────┼──────┤
│ central │ push │ 2 │
│ widget │ import │ │
└──────────┴───────────┴──────┘
Following it here means importing. Since central never touched
repo/widget/, the change lands directly, with no merge commit:
$ central import widget -m "Bring in upstream usage example"
[ OK ] Imported into [main] directly (no merge needed).
A single, linear commit - no second parent to merge:
* Bring in upstream usage example
* Unrelated central change
* Add fake subrepo sprocket
* Add fake subrepo gadget
* Add fake subrepo widget
* Initial commit
repo/widget/README.md now carries the upstream change:
# widget
This is a fake [widget] repo, generated by [Central_test_helpers] for tests.
Upstream added a usage example.
And central todo shows both central and widget with the same,
ordinary next step - push, covered next:
$ central todo
┌──────────┬───────────┬──────┐
│ Repo │ Next step │ Diff │
├──────────┼───────────┼──────┤
│ central │ push │ 8 │
│ widget │ push │ │
└──────────┴───────────┴──────┘
Falling back to a merge
If central has touched repo/widget/ since the last sync - even in a file
the upstream change never went near - import can no longer assume
repo/widget/ is untouched, so it falls back to building a separate import
commit and merging it in, an ordinary two-parent git merge:
$ central import widget -m "Bring in upstream usage example"
[ 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
|\
| * Bring in upstream usage example
* | Add internal note
* | Add fake subrepo sprocket
* | Add fake subrepo gadget
|/
* Add fake subrepo widget
* Initial commit
When it doesn’t merge cleanly
Falling back to a merge means it can behave like an ordinary git merge in
every other way too: if your own central changes happen to touch the exact
same lines the upstream commits did, import leaves you in the middle of a
real conflict, markers included:
$ 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]
Resolve it exactly like you would any git merge conflict - edit the
file, then git add and git commit. .gitrepo is already updated at
this point, so there’s nothing else to do for the subrepo side of it:
<<<<<<< HEAD
# widget, edited by central
=======
# widget, retitled upstream
>>>>>>> 1185512b92d612b25613f2e5b473e5231185512b
With the merge committed, export is available again right away - it
carries your resolution out to widget, since that’s what its 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
central todo shows the same pattern as after any export: widget’s
own main is left one advance-main behind its subrepo branch -
nothing to do with the conflict just resolved:
$ central todo
┌──────────┬──────────────┬──────┐
│ Repo │ Next step │ Diff │
├──────────┼──────────────┼──────┤
│ central │ push │ 8 │
│ widget │ advance-main │ │
└──────────┴──────────────┴──────┘
Either way, once a change has landed in a subrepo’s own history, the last step is pushing it out for real.