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.