Demystifying ‘git submodule’

What are git submodules

It is a way through which a git repository can be considered as sub-repo of an existing/current(parent) git repository. This gives you a feeling of nested git repositories for a project. Nested git repositories are nothing but submodules of parent repository.

Submodules let repositories to presented in nested fashion but are maintained independently. i.e. history, configurations of submodules and parent repository will be logged, captured in their respective branches.

Usecase / Application

Submodules can be used if a project requires some modules/applications/libraries which are maintained as separate git repository.

In such a case, user of the project can register dependent repositories as submodules with the project and can fetch sources of submodules along with project sources; and use it to link libraries or use its modules.

For instance, if I am working on, lets say, on a application(stroed in repo X) where I have to calculate md5 hash of all objects and store hashes in a BST (binary search tree). Then rather than implementing BST for this application again, I can add existing repo Y, which implements BST, and add it as submodule of repo X.

Creating submodule

Just to demonstrate I am creating 2 repositories; dummy_project.git and super_project.git

super_project contains a C file for which to compile and complete the app, needs sources of dummy_project. Hence dummy_project would be submodule of super_project.

Create a project which you want to make a submodule of super_project

[root@kashish reps]# git init dummy_project.git
Initialized empty Git repository in /root/git_client/reps/dummy_project.git/.git/

[root@kashish dummy_project.git]# git remote add origin https://kashishbhatia@github.com/kashishbhatia/dummy_project.git

[root@kashish dummy_project.git]# git remote -v
origin  https://kashishbhatia@github.com/kashishbhatia/dummy_project.git (fetch)
origin  https://kashishbhatia@github.com/kashishbhatia/dummy_project.git (push)

[root@kashish dummy_project.git]# touch func.h
[root@kashish dummy_project.git]# touch func.c


[root@kashish dummy_project.git]# cat func.h
 extern void func(void);


[root@kashish dummy_project.git]# cat func.c
#include <stdio.h>

void func(void)
{
    printf("Hi! you are in %s of submodule\n", __FUNCTION__);
}

[root@kashish dummy_project.git]# git add func.c func.h

[root@kashish dummy_project.git]# git commit
[master (root-commit) eb7bcff] dummy project initial checkin. Will be used as submodule of super_project.git
 2 files changed, 7 insertions(+), 0 deletions(-)
 create mode 100644 func.c
 create mode 100644 func.h

[root@kashish dummy_project.git]# git push origin master
Password:
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 413 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)

Create a new super project

[root@kashish reps]# git init super_project.git
Initialized empty Git repository in /root/git_client/reps/super_project.git/.git/

[root@kashish super_project.git]# git remote add origin https://kashishbhatia@github.com/kashishbhatia/super_project.git

[root@kashish super_project.git]# git remote -v
origin  https://kashishbhatia@github.com/kashishbhatia/super_project.git (fetch)
origin  https://kashishbhatia@github.com/kashishbhatia/super_project.git (push)

[root@kashish super_project.git]# mkdir src

[root@kashish super_project.git]# cd src/

[root@kashish src]# touch main.c
[root@kashish src]# cat main.c
#include <stdio.h>
#include "submodule/func.h"

int main(void)
{
    func();
    return 0;
}

[root@kashish src]# touch Makefile
[root@kashish src]# cat Makefile
DIR=$(PWD)/submodule
app: main.c $(DIR)/func.c
        gcc -o app main.c $(DIR)/func.c


[root@kashish super_project.git]# cd ..

[root@kashish super_project.git]# touch .gitmodules
[root@kashish super_project.git]# cat .gitmodules
[submodule "src/submodule"]
        path = src/submodule
        url = https://github.com/kashishbhatia/dummy_project.git

[root@kashish super_project.git]# git add src
[root@kashish super_project.git]# git add .gitmodules


[root@kashish super_project.git]# git commit -m "Initial commit of super_project"

[root@kashish super_project.git]# git push origin master
Password:
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 585 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)


Register submodule with super project

Syntax : git submodule add <submodule_url> <submodule_path>


[root@kashish super_project.git]# git submodule add https://github.com/kashishbhatia/dummy_project.git src/submodule
Initialized empty Git repository in /root/git_client/reps/super_project.git/src/submodule/.git/
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 4 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.

This will register dummy_project as submodule and set its default path (where it will be checked out) as src/submodule. And it will create a /src/submodule folder also.

and finally commit the changes of super_project.git …

[root@kashish super_project.git]# git push origin master
Password:
Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 485 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)

Fetching sources of a project and its submodules

Now clone super_project and fetch sources of submodule as well

[root@kashish tmp]# git clone https://github.com/kashishbhatia/super_project.git
Initialized empty Git repository in /root/git_client/reps/tmp/super_project/.git/
remote: Counting objects: 10, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 10 (delta 1), reused 9 (delta 0), pack-reused 0
Unpacking objects: 100% (10/10), done.

[root@kashish tmp]# cd super_project/

[root@kashish super_project]# cd src/
[root@kashish src]# ls
main.c  Makefile  submodule


[root@kashish src]# cd submodule/
[root@kashish submodule]# ls

Note : submodule directory in super_project is empty. To fetch sources of
dummy_project, fire following commands

Go back to ‘src’ directory where .gitmodules exist

[root@kashish submodule]# cd ..
[root@kashish src]# ls
main.c  Makefile  submodule

Now fetch registered submodule sources

[root@kashish super_project]# git submodule update --init --recursive
Submodule 'src/submodule' (https://github.com/kashishbhatia/dummy_project.git) registered for path 'src/submodule'
Initialized empty Git repository in /root/git_client/reps/tmp/super_project/src/submodule/.git/
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 4 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.
Submodule path 'src/submodule': checked out 'eb7bcff141a113f81509084be21350afaedc1281'

Above command is combination of two commands :
1. git submodule init
It will read .gitmodules file and copy submodule details in .git/config file.

Check git configuration …

[root@kashish super_project]# git config -l
...
submodule.src/submodule.url=https://github.com/kashishbhatia/dummy_project.git

[root@kashish super_project]# cat .git/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        fetch = +refs/heads/*:refs/remotes/origin/*
        url = https://github.com/kashishbhatia/super_project.git
[ branch "master"]
        remote = origin
        merge = refs/heads/master
[submodule "src/submodule"]
        url = https://github.com/kashishbhatia/dummy_project.git

2. git submodule update
It will fetch sources of registered submodules from git.submodule.url and download sources of submodule in git.submodule.path.

Now check whether sources of submodules are fetched or not…

[root@kashish super_project]# ls src/submodule/
func.c  func.h

Now Build the code and execute it

[root@kashish submodule]# cd ..
[root@kashish src]# ls
main.c  Makefile  submodule

[root@kashish src]# make
gcc -o app main.c /root/git_client/reps/tmp/super_project/src/submodule/func.c

[root@kashish src]# ls
app  main.c  Makefile  submodule


[root@kashish src]# ./app
Hi! you are in func of submodule

TADA…..! Stay tuned to know more about other commands of ‘git submodule’.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s