Git Submodules are the concept related to modularity. One git repository can be added to another as a submodule and maintained separately. Instead of being tightly coupled, it is loosely coupled and is easy to maintain. Suppose you are working with softwareA which depends on libraryA, instead of copy-pasting the libraryA over and over again when a new version of the library is released what we can do is use submodule to make this process DRY and elegant.
While you read this post, take a moment to connect with me on LinkedIn.
1. Setting Up the Repo Structure
For this example I will we demonstrating this concept with my blogging engine Hugo and the submodule which is a theme for Hugo. I keep theme as a separate module because want to reduce overhead when updating to the new theme version, which will be deleting and adding a whole new version of theme repo.
If you are following this tutorial with me, you need to install Hugo on your system. Consult your OS’s package manager or if you using Windows, consult getting started guide at Hugo’s site.
Easiest method for me to install hugo is to use
go get command.
$ go get -u github.com/gohugoio/hugo go: golang.org/x/net upgrade => v0.0.0-20200904194848-62affa334b73 go: github.com/hashicorp/golang-lru upgrade => v0.5.4 go: github.com/spf13/cobra upgrade => v1.0.0 go: github.com/Azure/azure-pipeline-go upgrade => v0.2.3 go: golang.org/x/sys upgrade => v0.0.0-20200905004654-be1d3432aa8f go: github.com/google/wire upgrade => v0.4.0 go: github.com/yuin/goldmark upgrade => v1.2.1 go: github.com/pkg/errors upgrade => v0.9.1 go: github.com/niklasfasching/go-org upgrade => v1.3.2 go: github.com/bep/golibsass upgrade => v0.7.0 [...output trimmed...]
As I already have Hugo installed, this command will upgrade it to latest version. Command output will differ if you are installing a fresh Hugo.
Create a Hugo Site
Now I have the latest version of Hugo. Let’s start and create our main/parent git repository for my blog.
$ hugo new site myblog Congratulations! Your new Hugo site is created in /home/sntshk/repos/myblog. Just a few more steps and you're ready to go: 1. Download a theme into the same-named folder. Choose a theme from https://themes.gohugo.io/ or create your own with the "hugo new theme <THEMENAME>" command. 2. Perhaps you want to add some content. You can add single files with "hugo new <SECTIONNAME>/<FILENAME>.<FORMAT>". 3. Start the built-in live server via "hugo server". Visit https://gohugo.io/ for quickstart guide and full documentation. $ cd myblog $ git init Initialized empty Git repository in /home/sntshk/repos/myblog/.git/ $ git add . $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: archetypes/default.md new file: config.toml $ git commit -m "Initial commit" [master (root-commit) 0f1d8e5] Initial commit 2 files changed, 24 insertions(+) create mode 100644 archetypes/default.md create mode 100644 config.toml
Above I have created a bare Hugo site, entered and initialized that directory as a git repo and did the initial commit. As you can see below, our site has no theme at this point in time.
$ ls .git/ resources/ content/ layouts/ themes/ config.toml archetypes/ data/ static/ $ ls themes
Add a theme
Now instead of picking up a theme and slamming into my
themes/ directly (which will obviously work out of the box), I’ll add it as submolule.
$ git submodule add https://github.com/Track3/hermit.git themes/hermit Cloning into '/home/sntshk/repos/myblog/themes/hermit'... remote: Enumerating objects: 16, done. remote: Counting objects: 100% (16/16), done. remote: Compressing objects: 100% (11/11), done. remote: Total 787 (delta 1), reused 9 (delta 1), pack-reused 771 Receiving objects: 100% (787/787), 460.32 KiB | 615.00 KiB/s, done. Resolving deltas: 100% (344/344), done.
Before we start the local server, we need to configure our
config.toml file. For sake of simplicity, we’ll use sample theme hermit already comes with.
$ cp themes/hermit/exampleSite/config.toml .
At present the status of the repo is like so:
$ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: .gitmodules new file: themes/hermit
.gitmodule file stores all the git modules added to the current repo. At current, it looks like this:
[submodule "themes/hermit"] path = themes/hermit url = https://github.com/Track3/hermit.git
It start with a section about the submodule.
path is relative to the root,
url tracks the URL for future updates. Also you’ll see
themes/hermit is now listed as file and not a subdirectory.
It’s time to commit the changes.
$ git commit -m "Add hermit theme" [master 651c044] Add hermit theme 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 themes/hermi
I will start the server and head over to http://127.0.0.1:1313 which is the default address for local prototyping in Hugo.
$ hugo server- D Start building sites … | EN -------------------+----- Pages | 10 Paginator pages | 0 Non-page files | 0 Static files | 10 Processed images | 0 Aliases | 0 Sitemaps | 1 Cleaned | 0 Built in 56 ms... [...output trimmed...]
2. Working with Submodules
At this stage, you can keep adding new post (or making changes) to the main repository. Let’s make a few post to demonstrate this:
$ hugo new posts/my-first-post.md /home/sntshk/repos/myblog/content/posts/my-first-post.md created $ hugo new posts/my-second-post.md /home/sntshk/repos/myblog/content/posts/my-second-post.md created $ echo Hello world >> content/posts/my-first-post.md $ echo Hello Mars >> content/posts/my-first-post.md
My git log tree looks like this:
$ git log * 61087cf - (HEAD -> master) Add a few posts (63 seconds ago) <Santosh Kumar> * b5a80a7 - Update config.toml for hermit (5 minutes ago) <Santosh Kumar> * 651c044 - Add hermit theme (7 minutes ago) <Santosh Kumar> * 0f1d8e5 - Initial commit (45 minutes ago) <Santosh Kumar>
Submodules are tracked by the exact commit specified in the parent project, not a branch, a ref, or any other symbolic reference.
We have two repository now, the main repository which is maintained by you and hermit theme repository. At this stage the main repository can be pushed to remote, say at
Mostly you’ll be working with the main repo doing commits. Submodule resides in the repo and only get updated when you want to. If you add commits to a submodule, the parent project won’t know. You have to inform it manually.
Removing a Submodule
My website at present is in similar state as shown in the log above. Just that I have many blog post made and each commit represent a post made. Now I want to change my theme to something else. git doesn’t comes with a magic command to replace theme in my situation. We need to first delete the submodule and then add it back. Let’s get started. We’ll divide the process into 4 parts.
- Delete relevant files from the
At present, my files
.gitmodules looks like this:
I’ll go ahead and delete the first 3 lines.
- Delete the relevant section from
.gitmodules is a file which stores information about modules and should be commited to the repo. There is one other location where this data is stored i.e.
.git/config file. This is all your local configuration of your repo.
I removed these lines from the config file.
[submodule "themes/hermit"] url = https://github.com/Track3/hermit.git active = true
git rm --cached themes/hermit
This command will remove the
themes/hermit path from the git tracking. Be sure you don’t have a trailing slash in the module path when executing this command.
- Delete the now untracked submodule and commit the changes.
This is half the way of my journey to replace my theme. I will delete my themes/hermit directory and commit the changes.
Adding a Submodule
Installation process is same as described early in the tutorial. I’ll add Zzo theme now.
git submodule add https://github.com/zzossig/hugo-theme-zzo.git themes/zzo git submodule update --remote --merge
The above submodule update command is run for all the submodule in the repo, which is kinda overkill in this situation, but it updates all the existing submodules to their latest.
After some themes specific settings, my site is now ready to charm in the new theme.
Today we’ve got familiar with some git submodule stuff. If you like this post, you may want to subscribe to my newsletter.