Category: Uncategorized

Demystifying ‘git submodule’ – part 2

In part1 we learnt how we can create submodule and register them inside a git repository and how to fetch sources of git submodule.

Well in this blog I want to revisit init and update command and discuss little more about it.

submodule init

This command reads the .gitmodules files to find out submodule information and puts that information in .git/config file.


[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/

 ======before issuing 'init' command'====== 
[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

[root@kashish super_project]# git submodule init
Submodule 'src/submodule' (https://github.com/kashishbhatia/dummy_project.git) registered for path 'src/submodule'

 ======after issuing 'init' command====== 
[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

Note .git/config will only capture url information of submodule.

submodule deinit

This command is complementary of init command. It unregister the submodule from parent repository and remove entries of submodule from .git/config file.

Other way of removing submodule is as follows :


    1. Delete the relevant section from the .gitmodules file.
    2. Stage the .gitmodules changes git add .gitmodules
    3. Delete the relevant section from .git/config.
    4. Run git rm --cached path_to_submodule (no trailing slash).
    5. Run rm -rf .git/modules/path_to_submodule
    6. Commit git commit -m "Removed submodule "
    7. Delete the now untracked submodule files
    8. rm -rf path_to_submodule

 

submodule update

This command reads out the .git/config and .gitmodules file and actually fetches the sources of submodule into submodule path from the submodule URL.


[root@kashish super_project]# git submodule update
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'

We can also use git submodule update –init instead of 2-step way of issuing init and the update command.

submodule status

This command is very handy to know whats going on with the submodule used by parent repository; to know whether the sources of submodule are stale and needs update; or does submodule has any changes in your git namespace which are required to be commit; or does it have any merge conflicts.

It displays following symbols in the status when :
– (minus) when submodule is not initialized.
+ when top of the tree commit-id does not match with what is saved in index file.
M when it has merge conflicts.



[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.

 shows '-' sign as submodule is not yet initialized 
[root@kashish super_project]# git submodule status
-eb7bcff141a113f81509084be21350afaedc1281 src/submodule

[root@kashish super_project]# git submodule init
Submodule 'src/submodule' (https://github.com/kashishbhatia/dummy_project.git) registered for path 'src/submodule'

[root@kashish super_project]# git submodule status
-eb7bcff141a113f81509084be21350afaedc1281 src/submodule

[root@kashish super_project]# git submodule update
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'

 After updating and checking out sources, it should not show '-' sign. 
[root@kashish super_project]# git submodule
 eb7bcff141a113f81509084be21350afaedc1281 src/submodule (heads/master)

 Note : we can use only 'git submodule' also to know status of submodule 

 

Let see what happens if I add a new file in submodule which is not staged yet.



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

[root@kashish submodule]# touch tmp.c

[root@kashish submodule]# cd ../../
[root@kashish super_project]# git submodule status 
+eb7bcff141a113f81509084be21350afaedc1281 src/submodule (heads/master) 
Note: started showing '+' sign

submodule foreach

This can be used to perform same operation on all the submodules.
Syntax : git submodule foreach

For Example : to pull latest changes done in all submodules registered within a parent repository.



[root@kashish super_project]# git submodule foreach git pull origin master
Entering 'src/submodule'
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/kashishbhatia/dummy_project
 * branch            master     -> FETCH_HEAD
Updating eb7bcff..075f413
Fast-forward
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README

Advertisements

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’.