In this post, we feature a comprehensive Example on Git Add Submodule.
An important concept in software development is reusability. When working on a software project you may have situations where a function or method is used in many places of an application. Rather than interspersing the function/method code throughout the application, it is useful to place it in a utility class. In a large project where you have many such classes, you may want to move them to a separate project.
If your codebase becomes very large, you may also want to consider creating subprojects. There are advantages to breaking up a large project into smaller projects. For example:
- Smaller projects allow for easier code maintenance.
- Child projects can be used in other parent projects, encouraging reuse.
- The developer or developers can focus on a specific area of the business solution.
Let’s assume that these separate projects have their own Git repositories. How can you use the utility project within the main project? In Git, you can include the utility project by adding it as a submodule to the main project.
A submodule is a repository that is contained inside a subdirectory of another repository. Logically, it can be thought of child project of a parent project. Git tracking for the submodule is managed separately from that of the main project. Code that is developed by a 3rd party is often included as a submodule in Git. Themes and plugins in WordPress too are typically included as submodules when Git is used as the Version Control System.
In Git you can add, clone, update and remove submodules within the main project. In this example, we will demonstrate how to add a repository as a submodule of another repository.
1.1 Tools Used in this Example
- Git 2.17
Git downloads are available here: https://git-scm.com/downloads.
2. Git Add Submodule Example
In this example, we will create a local repository that contains a utility class. We will then add the new repository as a submodule of an existing main project.
2.1 Download and Extract the Sample Project
First, download the “Submodule Demo” archive from the Download section and extract it in a directory of your choice.
$ ls -R .: demo/ ioutils/ ./demo: mvnw* mvnw.cmd pom.xml src/ ./demo/src: main/ test/ ./demo/src/main: java/ resources/ ./demo/src/main/java: com/ ./demo/src/main/java/com: javacodegeeks/ ./demo/src/main/java/com/javacodegeeks: example/ ./demo/src/main/java/com/javacodegeeks/example: demo/ ./demo/src/main/java/com/javacodegeeks/example/demo: DemoApplication.java ./demo/src/main/resources: application.properties ./demo/src/test: java/ ./demo/src/test/java: com/ ./demo/src/test/java/com: javacodegeeks/ ./demo/src/test/java/com/javacodegeeks: example/ ./demo/src/test/java/com/javacodegeeks/example: demo/ ./demo/src/test/java/com/javacodegeeks/example/demo: DemoApplicationTests.java ./ioutils: FileUtil.java
We have a main project (named “demo”) that is tracked in a local repository. If you view the Git config file, you will see configuration information for the main project.
$ cat .git/config [core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true symlinks = false ignorecase = true
Let us suppose that the “demo” project uses file input/output operations. Let us further assume that these operations are used in many places within the application. With these points in mind, we created a utility class for those operations and placed it into its own project named “ioutils”. We’ll add the “ioutils” project to its own local Git repository next.
2.2 Create a Local Repository
Open a terminal (shell) in the “ioutils” directory where the archive was extracted and run the following command:
$ git init
Git init Command Output
Initialized empty Git repository in /Users/gilbertlopez/ioutils/.git/
This creates an empty Git repository. The repository metadata has been generated in the “.git” folder.
(Note: This folder is hidden by default as you would, typically, not edit its contents.)
2.3 Add and Commit the File to the Project Repository
Let’s add the file to the repository. Run the following command:
$ git add FileUtil.java
This will add the
FileUtil.java file to the repository index. The file is now in the staging area.
Commit the file from the staging area to the repository with the following command:
$ git commit -m 'Initial commit of project'
Note: The -m option allows us to add a commit message inline.
Git commit Command Output
[master (root-commit) 45e1f63] initial commit 1 file changed, 49 insertions(+) create mode 100644 FileUtil.java
2.4 Add a Submodule to the Main Project
Now that we have our utility class in its own Git repository, let’s add it as a submodule to the “demo” project. Run the following command:
git submodule add -f ../ioutils src/main/java/com/javacodegeeks/example/ioutils
Note: The -f option is used to force the creation of
src/main/java/com/javacodegeeks/example/ioutils, the directory where we want the submodule to reside.
- The first parameter (../ioutils) to the
submodule addcommand specifies the location of the repository to be added as a submodule. This could be a local repository (“ioutils” in this example) or a remote repository, e.g. https://github.com/gilbertlopez/example.git. It probably goes without saying that you need to be able to clone the repository in order to add it as a submodule.
- The second parameter (src/main/java/com/javacodegeeks/example/ioutils) specifies the subdirectory path of the main project where you want the
ioutilsrepository to be integrated. If you omit this parameter, Git will add the subproject to directory named the same as the repository (in this case, “ioutils”).
Git Submodule Add Command Output
Cloning into 'C:/Users/Gilbert/gittest/demo/src/main/java/com/javacodegeeks/example/ioutils'... done. warning: LF will be replaced by CRLF in .gitmodules. The file will have its original line endings in your working directory.
add submodule command registered the
ioutils repository within the main project repository’s configuration. It also cloned the repository into the
If you view the Git config file for the main project after running the
submodule add command, you will notice an additional section.
$ cat .git/config [core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true symlinks = false ignorecase = true [submodule "src/main/java/com/javacodegeeks/example/ioutils"] url = C:/Users/Gilbert/gittest/ioutils active = true
This submodule is identified by the path where the
ioutils repository resides. The ‘url’ value in the submodule section shows the repository URL link (or directory path for a local repository) of the submodule that Git uses to clone the project.
Next, check the status of the main project with the following command:
$ git status
Git status Command Output
On branch master Changes to be committed: (use "git reset HEAD ..." to unstage) new file: .gitmodules new file: src/main/java/com/javacodegeeks/example/ioutils
submodule add command staged two new files: “.gitmodules” and “src/main/java/com/javacodegeeks/example/ioutils”. (Submodule directories and their contents appear as a single file when viewed by the main project’s Git repository.) If you look in the
ioutils subdirectory of the main project, you will see that
FileUtil.java from the “ioutils” repository was cloned into that location.
It is important to note that main and submodule repositories track independently of each other. Go to the submodule’s directory (“src/main/java/com/javacodegeeks/example/ioutils”) and run the Git status command:
$ git status On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean
As you can see, the submodule’s Git is unaware of any changes made to the main project.
The Git status for the main project provides some basic information about the staged files. You can get additional information by making the status command submodule-aware. Navigate back to the ‘demo’ directory and run the following command:
$ git config --global status.submoduleSummary true
Now run the Git status command again.
$ git status On branch master Changes to be committed: (use "git reset HEAD ..." to unstage) new file: .gitmodules new file: src/main/java/com/javacodegeeks/example/ioutils Submodule changes to be committed: * src/main/java/com/javacodegeeks/example/ioutils 0000000...a3255ca (1): > Initial commit
The status now shows that the remote repository has 1 commit and that the commit was an addition with the commit message ‘Initial commit’.
To commit the files from the staging area to the repository, run the following command:
$ git commit -m 'Added ioutils submodule'
Git commit Command Output
[master 992ad34] Added ioutils submodule 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 src/main/java/com/javacodegeeks/example/ioutils
2.5 View the .gitmodules File
Let’s take a look at the .gitmodules file.
$ cat .gitmodules [submodule "src/main/java/com/javacodegeeks/example/ioutils"] path = src/main/java/com/javacodegeeks/example/ioutils url = ../ioutils
The .gitmodules file holds all the submodule configuration information for this project. The data contained in this file is read by Git when anyone clones our project. It is used to locate the submodule repository (url = ../ioutils) and to specify the subdirectory of the main project where the submodule will be integrated (path = src/main/java/com/javacodegeeks/example/ioutils).
2.6 View the Status of Submodules
If you simply want to see the locations of your submodules, use the following command:
$ git submodule status
Git submodule status Command Output
e51bafee08eff11e55817d789d40fe96a216c4a7 src/main/java/com/javacodegeeks/example/ioutils (heads/master)
The output displays the SHA-1 of the currently checked out commit for each submodule in the main project and the path locations where the submodules reside. (In our example, there is only one submodule.)
Adding submodules is a great way of integrating other Git repositories to your main project, whether these repositories are from a 3rd party or projects you created yourself for reuse.
That was Git Add Submodule Example.
You can download the full source code of this example here: Submodule Demo