Using Git Submodules with Local Overrides
Introduction
Managing your own libraries as Git submodules can be awkward: normally, you'd have to push and pull between different directories to keep everything in sync.
But there's a handy trick: keep the submodule pointing at your public remote (for others who clone your project), while locally overriding the submodule's URL to use your own local checkout. This way you get fast iteration, and others still have a smooth experience.
One-Time Setup (Public Default)
In the superproject:
# Add the submodule pointing at your public GitHub repo
git submodule add https://github.com/you/mylib.git mylib
# Optionally track a branch
git submodule set-branch --branch master mylib
git commit -m "Adding [mylib] as submodule (tracks master)"
Local Override (Work With Your Local Repo)
Point the submodule at your local repo path, but only in .git/config
:
git config --local submodule."mylib".url /Users/you/mylib
git submodule sync mylib
git submodule update --init mylib
From now on:
git submodule update --remote
pulls from your local path- Others will still pull from GitHub
Switching Back to Remote
If you move to another machine or want to reset:
git config --local --unset submodule."mylib".url
git submodule sync mylib
git submodule update --init mylib
Notes & Gotchas
Submodules always pin a commit, even when tracking a branch. To advance the library version in your superproject:
(cd mylib && git fetch && git checkout master && git pull) git add mylib git commit -m "Bump mylib submodule"
- Use quotes in config if the path contains slashes:
submodule."path/to/mod".url
You can also use a
file://
URL instead of a plain path:git config --local submodule."mylib".url file:///Users/you/mylib
Handy Bash Helpers
Drop these functions into your ~/.bashrc
or ~/.zshrc
:
# Point submodule at local path
submod_use_local() {
local path="$1" localrepo="$2"
git config --local submodule."$path".url "$localrepo" &&
git submodule sync "$path" &&
git submodule update --init "$path"
}
# Revert to remote URL
submod_use_remote() {
local path="$1"
git config --local --unset submodule."$path".url 2>/dev/null || true
git submodule sync "$path" &&
git submodule update --init "$path"
}
# Example:
# submod_use_local libs/mylib /Users/you/dev/mylib
# submod_use_remote libs/mylib
Alternatives
Sometimes language-level tools are easier:
- Python:
pip install -e ../mylib
- Node.js:
npm link ../mylib
- Or use
git worktree
for multiple checkouts of the same repo.
Conclusion
This workflow keeps everything tidy:
- Others pull your libraries from GitHub
- You work directly with your local repos
- No messy pushes/pulls just to test changes
It's a simple, scriptable, FOSS-friendly way to streamline submodule development.