Work with plain Git¶
LazySubmodules stores its data where Git ignores it, so collaborators and tools without it keep working.
Why plain Git keeps working¶
Namespaced keys. The tracking configuration lives in
.gitmodulesunderlsm-modeandlsm-ref. Git ignores keys it does not know, and thelsm-prefix avoids collisions with future Git keys.Ordinary gitlinks. The superproject records submodule commits exactly as plain Git does.
.lsm.lockis an extra file next to them.The native
branchkey. For branch-tracking submodules, LazySubmodules also writessubmodule.<name>.branch, whichgit submodule update --remotereads.Native keys stay.
update,ignore,shallowand the other keys that Git reads are left as they are.
LazySubmodules is not a replacement for repo, west, git subtree or
monorepo tooling. It manages ordinary submodules and nothing else.
Clone a superproject¶
A colleague without LazySubmodules clones as usual:
git clone <superproject-url>
cd <superproject>
git submodule update --init
git submodule update --init checks out the commits that the
superproject records, which are the commits LazySubmodules locked. The
exception is a submodule with update = none in .gitmodules, which Git
skips:
$ git submodule update --init
…
Skipping submodule 'libs/quirky'
With LazySubmodules, lazysubmodules fetch clones, initializes and
fetches every managed submodule, including such submodules. That is the
better choice for CI; see Scripts and CI.
git submodule update --remote¶
For branch-tracking submodules, git submodule update --remote does what
lazysubmodules update does, except for the lock file: it moves the
submodule to the tip of the configured branch.
Warning
For submodules in tag, tag-pattern or commit mode there is no
native branch key, so git submodule update --remote moves them to the
tip of the remote’s default branch instead. Name only branch-tracking
submodules, by path, when you use it.
On a clone of the finished demo, kernel follows the tag pattern
v6.6.*. --remote moves it to the tip of origin/HEAD, a pre-release
commit, and LazySubmodules reports the difference:
$ git submodule update --remote kernel bootloader/u-boot
Submodule path 'kernel': checked out '8ec67d38d377155f9933e80b3b64063a28aa4de7'
$ lazysubmodules status kernel u-boot
NAME PATH MODE REF LOCK HEAD STATE
kernel kernel tag-pattern v6.6.* 08dcd0d (v6.6.10) 8ec67d3 drift
u-boot bootloader/u-boot branch main 8e9fc7a 8e9fc7a ok
$ git -C kernel log -1 --format=%s
Linux v6.7-rc1
u-boot did not move, because it already was at the tip of
origin/main. Git takes paths here, not submodule names:
git submodule update --remote u-boot fails with
error: pathspec 'u-boot' did not match any file(s) known to git.
To undo the change, check out the recorded commit again:
$ git submodule update kernel
Submodule path 'kernel': checked out '08dcd0dc8f98ab3da3943153cad056f346d18ded'
$ lazysubmodules status kernel
NAME PATH MODE REF LOCK HEAD STATE
kernel kernel tag-pattern v6.6.* 08dcd0d (v6.6.10) 08dcd0d ok
When a commit made with plain Git changes a gitlink without updating
.lsm.lock, verify fails until someone runs lazysubmodules update
for that submodule:
$ git submodule update -q --remote kernel
$ git commit -q -m "move kernel" kernel
$ lazysubmodules verify kernel
kernel: failed (2 of 7 checks)
gitlink: HEAD of the superproject records 8ec67d38d377, locked 08dcd0dc8f98
head: HEAD 8ec67d38d377 differs from locked commit 08dcd0dc8f98
lazysubmodules: verification failed: kernel
Migrate from git submodule update --remote¶
A superproject that already follows branches with
submodule.<name>.branch needs one set per submodule. This loop puts
every unmanaged submodule with a native branch key under
LazySubmodules, tracking the same branch:
git config -z -f .gitmodules --get-regexp '^submodule\..*\.branch$' |
while IFS= read -r -d '' entry; do
key=${entry%%$'\n'*} # submodule.<name>.branch
branch=${entry#*$'\n'}
name=${key#submodule.}
name=${name%.branch}
if ! git config -f .gitmodules --get "submodule.$name.lsm-mode" >/dev/null; then
lazysubmodules set --branch "$branch" -- "$name"
fi
done
git config -zseparates entries with NUL and key from value with a newline, so names with spaces or dots are safe.--ends the options ofset, so a name that starts with-is safe as well.
Then record the current state in the lock file and commit it:
lazysubmodules update --dry-run # review
lazysubmodules update --commit
The first update records every newly managed submodule. A submodule
without a lock entry shows (unlocked) on the left side, and its
checkout moves to the tip of the branch as of your last fetch, just as
git submodule update --remote would move it.
After that, move release dependencies from branches to tags or tag
patterns one at a time, with lazysubmodules set <name> --tag-pattern '<pattern>'; see Change what a submodule tracks.
Stop using LazySubmodules for a submodule¶
Remove the tracking keys and the lock entry, then commit both files:
git config -f .gitmodules --unset submodule.sdk.lsm-mode
git config -f .gitmodules --unset submodule.sdk.lsm-ref
git config -f .lsm.lock --remove-section submodule.sdk
git commit -s -m "stop tracking sdk with lazysubmodules" -- .gitmodules .lsm.lock
The submodule is then unmanaged.
status still lists it, update and verify leave it out, and naming
it is refused:
$ lazysubmodules status sdk
NAME PATH MODE REF LOCK HEAD STATE
sdk sdk - - - 6308203 unmanaged
$ lazysubmodules verify sdk
lazysubmodules: sdk: refused: submodule is not managed by lazysubmodules
A submodule in branch mode keeps its native branch key, so
git submodule update --remote goes on working for it. To stop using
LazySubmodules altogether, do the same for every submodule and delete
.lsm.lock.
See also¶
Files: .gitmodules and .lsm.lock: every key in
.gitmodulesand.lsm.lock.States:
drift,unmanagedand the other states.Design and limitations: why the data lives where it does.