clone
git splice clone [--merge] <url> [<path>]
git splice clone --from-submodule <path>
Splices an existing repository into a new folder, as one commit, or turns a submodule into a splice.
In the sandbox, pkg-b.git isn't spliced in yet:
$ git splice clone https://git.example.com/pkg-b.git vendor/pkg-b
=== vendor/pkg-b: fetching https://git.example.com/pkg-b.git
ok vendor/pkg-b: cloned 9b3cb02 from main
The commit adds the upstream's files and
.splice, which records the
upstream and the commit the folder now matches, U(H):
$ git show --stat --format=%s
splice: clone vendor/pkg-b from main at 9b3cb02
vendor/pkg-b/.splice | 5 +++++
vendor/pkg-b/file.txt | 1 +
2 files changed, 6 insertions(+)
$ git config --file vendor/pkg-b/.splice --list
splice.id=6c92e1a0e36b0b6d
splice.commit=9b3cb02af44029fd61f1a57699c3dbf033958071
upstream.origin.url=https://git.example.com/pkg-b.git
From a submodule
Here vendor/pkg-b/ is a submodule of the same repository instead, and
its checkout is at the upstream's main:
$ cat .gitmodules
[submodule "vendor/pkg-b"]
path = vendor/pkg-b
url = https://git.example.com/pkg-b.git
--from-submodule keeps its URL and the commit it points to:
$ git splice clone --from-submodule vendor/pkg-b
=== vendor/pkg-b: fetching https://git.example.com/pkg-b.git
ok vendor/pkg-b: cloned 9b3cb02 from the submodule
=== vendor/pkg-b: the submodule's repository stays in $WALKTHROUGH/monorepo/.git/modules/vendor/pkg-b -- remove it once you don't need it
One commit replaces the submodule with its files and a .splice, and
removes it from .gitmodules, here the whole file:
$ git show --stat --format=%s
splice: clone vendor/pkg-b from submodule at 9b3cb02
.gitmodules | 3 ---
vendor/pkg-b | 1 -
vendor/pkg-b/.splice | 5 +++++
vendor/pkg-b/file.txt | 1 +
4 files changed, 6 insertions(+), 4 deletions(-)
The commit has to be on a branch upstream, so it's there for everyone
after the switch. A checkout of the submodule must be at it, without
changes, or clone refuses. It finds those changes with git status,
which doesn't see the ones hidden by git update-index --assume-unchanged
or --skip-worktree: an edited file keeps its edit, but a deleted one
comes back. Clear these flags before converting. Settings in .gitmodules other than path
and url have no equivalent and are dropped, with a warning: a splice
syncs with the upstream branch named like the monorepo's current branch,
not with submodule.<name>.branch. Other branches still have the
submodule; merging the converted main branch into them converts it there
too.
Every checkout that has the submodule's files, a colleague's clone or a
linked worktree, can't pull or merge the conversion: Git sees the files
as untracked ones in the way. git submodule deinit -f vendor/pkg-b
removes them first; it discards changes in the submodule's checkout, so
push them before.
Linked worktrees: the conversion removes the submodule's settings,
submodule.<name>.*, from.git/config, which all worktrees of the monorepo share. In another worktree that still has the submodule, it then counts as uninitialized (submodule-in-linked-worktree). Git itself advises against several worktrees of a monorepo with submodules: their support "is incomplete" (git worktree, BUGS).
More
- If the folder already exists and differs,
clonerefuses. With--merge, every file that differs becomes a conflict to resolve, and nothing is lost (clone-differing-content). If the folder already has exactly the upstream's files,cloneonly adds.splice(clone-copied-content). - On a branch the upstream doesn't have,
clonetakes the upstream's default branch. The first push creates the branch upstream, if the splice changed by then (clone-on-feature-branch). - A clone is a commit on top of
HEAD, so a monorepo without commits needs a first one (clone-without-commits). - An upstream with a submodule is refused, by
cloneand later bymergeandpull: its.gitmoduleswould sit in the folder, where Git doesn't read it, so nobody could check the submodule out. Turn it into a splice in the upstream first. clone --from-submodule --recursiveconverts a submodule's own submodules too, one commit each. Its upstream still has them, so the next push of the folder sends that commit: it turns them into splices upstream too. Until then,pullbrings in the upstream's other changes, but refuses one that moves such a submodule to another commit. If that upstream's owners keep their submodules, convert it in a fork of yours instead (#153).- To publish a folder of the monorepo to a new, empty repository, use
init.