Git: Simplistic Submodules

Posted in tech; tagged with git, tips

My use of submodules in git repos tends towards the simple. This tip illustrates using other Git repositories as submodules in the use case where we intend to be a mere consumer of the other project within ours. It’s a common pattern utilized by web themes and vim/Neovim scripts.

tl;dr cheat sheet:

# within myrepo add another repo as a submodule
git submodule add path/to/other/repo
git commit -m 'submodule added'

# clone and prepare a repo containing submodule
git clone myrepo newrepo
cd newrepo
git submodule init
git submodule update

# update submodules down the road / when needed
cd somerepo
git submodule update --remote

Working through the detail

Example problem: How to include a SCSS module within a Hugo theme project:

# let's create a new theme project
mkdir -p ~/project
cd ~/project
git init basetheme
mkdir -p basetheme/scss


# and another project we'll use as a submodule in basetheme
git init otherproject
cd otherproject
cat >_font.scss <<EOF
// First commit
EOF
git add _font.scss
git commit -m 'First commit'

# In basetheme add otherproject as submodule 
cd ~/project/basetheme
git submodule add ~/project/otherproject scss/otherproject
# git add .gitmodules
git commit -m 'submodule added'

# see what we got
cat scss/otherproject/_font.scss # "// First commit"

That was easy enough and the mechanics are the same whether the repos involved are local or remote.

Let’s add a second commit to otherproject now so that we can demonstrate how to manage changing subprojects later in this demo:

cd ~/project/otherproject
cat >> _font.scss <<EOF
// Second commit
EOF
git commit -am 'Second commit'

Now let’s reuse basetheme:

cd ~/project
git clone basetheme newtheme
cd newtheme
ll scss/otherproject/
total 0 

At this point the directory newtheme/otherproject exists but includes none of the repo’s files. Fix that:

git submodule init
git submodule update
cat scss/otherproject/_font.scss
// First commit

Our newtheme project now has the otherproject submodule included but note its state: the file _font.scss is at the version where the original project included it. Switch into the newtheme otherproject submodule directory to explore:

cd scss/otherproject
git status

The status command reports: HEAD detached at f97b7c5. This is a heads up warning to you that there is no local working branch tracking changes to otherproject. For this simple use case - being a consumer only of otherproject - that’s perfectly ok. For other use cases consult the Git SCM book.

Back to our consumer-only use case now, let’s be sure we have the latest commit to subproject. Note we need to move back into our basetheme repo (which is tracking changes):

cd ~/project/newtheme
git submodule update --remote

update --remote assumes you want to update your submodule to the current master branch of otherproject and reports:

Submodule path 'scss/otherproject': checked out 'df32d339f4482793b59135f6536dee3ba14c8180'

Checking _font.scss we see it has been brought up to date:

$ cat scss/otherproject/_font.scss 
// First commit
// Second commit

At this point otherproject in newtheme is at HEAD while in basetheme it’s a version back. We can fix that, if we desire to, with a git submodule update --remote in the basetheme project.

See the Git SCM book chapter on submodules for much more.