Git submodules
Tags: agilewebandappdevelo
Published: 2022-06-27 13:07:05

---
title: Git submodules
published: true
date: 2022-05-17 08:45:41 UTC
tags: Agilewebandappdevelo
canonical_url: https://apiumhub.com/tech-blog-barcelona/git-submodules/
---

## General overview

This article is based on [**Git Submodules**](https://git-scm.com/book/en/v2/Git-Tools-Submodules) **(**Git tools) and real implementation in a production-grade application with several µ-monoliths calling each other via REST APIS.  So, in this article, we’ll see a simplified example of a Spring RestTemplate modularization in the [Api Client submodule](https://github.com/davidgfolchApium/gitsubmodule-apiclient).

Git Submodules allows you to modularize your application components into modules with some **pros** and **cons**.

PROS

- Versability to modify main and submodules code in the same (IDE) project and commit/push to each remote repository separately.
- Enforces the Single Responsibility Principle decoupling specialized code into submodules from parent projects.  So, removes duplications.
- No need to create and publish a Nexus artifact jar file.

CONS

- As a submodule/library for several main projects, compatibility it’s a must.  There are some workarounds that can be applied like branching incompatible versions and/or using several pom-parentproject.xml in the submodule as explained later.

In addition, a git merge-request pipeline in the submodule should run all parent git repository pipelines to cover possible compilation and integration errors.

## Pre-requisites

- Git
- IDE (Optional)
- Maven 3.6
- JDK11

## Initial setup

### Git repositories

Examples created for this article:

- [Micro-service 1](https://github.com/davidgfolchApium/gitsubmodule-mss1)
- [Micro-service 2](https://github.com/davidgfolchApium/gitsubmodule-mss2)
- [Api Client submodule](https://github.com/davidgfolchApium/gitsubmodule-apiclient)

#### How to do for new projects from scratch

Steps to set up NEW projects with a common git submodule:

- Create Git repositories for all projects and submodules
- Clone mss1 and mss2 repositories and add submodule in each:

```
git submodule init
git submodule add -b main https://github.com/davidgfolchApium/gitsubmodule-apiclient
```

#### Clone example

Once we have the git repositories created and linked with the submodule, we can just clone the parent repository this way:

```
mkdir git-submodules && cd git-submodules/
git clone --recurse-submodules https://github.com/davidgfolchApium/gitsubmodule-mss1
git clone --recurse-submodules https://github.com/davidgfolchApium/gitsubmodule-mss2
```

![GGkAXwr HFpKajbfLY3JYPE8 lrSBjY6ptHYlgmvddSzK9Wq 030dP0a2rWybWcmiAUgrWOup BhHbo85b1yEida jyw aJvW kbQ7PquxmJr7](https://lh4.googleusercontent.com/GGkAXwr_HFpKajbfLY3JYPE8_lrSBjY6ptHYlgmvddSzK9Wq_030dP0a2rWybWcmiAUgrWOup_BhHbo85b1yEida-jyw_aJvW-kbQ7PquxmJr7--BtEUwxgTQrtg0ZKDDA_bLP5OUxAoNzYOdA "Git submodules 10")

### Maven dependencies

I’m going to explain the “child pom per parent module” strategy to solve the problem when parent projects have different library versions (Spring-Boot versions f.ex.).

As you can see in the **parent mss1** [pom.xml](https://github.com/davidgfolchApium/gitsubmodule-mss1/blob/main/pom.xml), it’s using spring-boot-starter-parent 2.6.7 and in the modules section it’s pointing to **api-client** [api-client/pom-mss1.xml](https://github.com/davidgfolchApium/gitsubmodule-apiclient/blob/main/pom-mss1.xml) and the **api** implementation module (that is a maven module but not a git submodule):

```
<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.6.7</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>com.apiumhub.articles.git-submodules</groupId>
<artifactId>mss1-parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<packaging>pom</packaging>

<name>mss1 parent</name>
<description>Parent mss1 git project using api-client git submodule</description>

<modules>
   <module>api</module>
   <module>gitsubmodule-apiclient/pom-mss1.xml</module>
</modules>

<properties>
   <java.version>1.11</java.version>
   <maven-compiler-plugin-java.version>11</maven-compiler-plugin-java.version>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <spring-boot.version>2.2.2.RELEASE</spring-boot.version>
   <start-class>com.apiumhub.articles.gitsubmodules.Application</start-class>
   <lombok.version>1.18.16</lombok.version>
   <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
   <maven-source-plugin.version>3.2.1</maven-source-plugin.version>
</properties>
```

In addition, defines common dependencies and versions.

In the api maven module we have the parent reference and the api-client dependency

```
<parent>
   <groupId>com.apiumhub.articles.git-submodules</groupId>
   <artifactId>mss1-parent</artifactId>
   <version>1.1.0-SNAPSHOT</version>
</parent>

<artifactId>api</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<dependencies>
   <dependency>
       <groupId>com.apiumhub.articles.git-submodules</groupId>
       <artifactId>api-client-mss1</artifactId>
       <version>1.0.0-SNAPSHOT</version>
       <scope>compile</scope>
   </dependency>
</dependencies>
```

And the submodule [api-client/pom-mss1.xml](https://github.com/davidgfolchApium/gitsubmodule-apiclient/blob/main/pom-mss1.xml) says that mss1 [pom.xml](https://github.com/davidgfolchApium/gitsubmodule-mss1/blob/main/pom.xml) is it’s parent pom.  So, it heritages all from both parents: Spring Boot maven parent module -> git-sumodules-mss1, and there is no need to put versions:

```
<parent>
   <groupId>com.apiumhub.articles.git-submodules</groupId>
   <artifactId>mss1-parent</artifactId>
   <version>1.1.0-SNAPSHOT</version>
</parent>

<artifactId>api-client-mss1</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
```

## Decoupled org.springframework.web.client package

Checkout that the dependency of org.springframework.web.client package is only used (and should be only used) in the submodule.  This completely decouples the implementations on this package in the base projects and it could be changed easily, for example, with a new WebFlux implementation of ApiClient.

![tozifGiBEg2Xox4PgZM99IjveOHxqo4QZg8I ktvtRDedIWSqpMVG0JUoQCv 6YLS1bGTYkAhWKHv7fBeAwRvEkkGuzmV6 FTCGN3xFDuOp5nKb e0hb0d0rUi5 vdnvq2FFOF vejyBIZRCBQ](https://lh4.googleusercontent.com/tozifGiBEg2Xox4PgZM99IjveOHxqo4QZg8I_ktvtRDedIWSqpMVG0JUoQCv-6YLS1bGTYkAhWKHv7fBeAwRvEkkGuzmV6-FTCGN3xFDuOp5nKb-e0hb0d0rUi5_vdnvq2FFOF_vejyBIZRCBQ "Git submodules 11")

In some cases like integration or feature tests, where you need to mock **RestClient** , should be also implemented in the **api-client** submodule **test/src/..** folder to keep source code decoupled from main the mssX.

## Working with submodules

We will have a project like that imported on intellij with the **mmsX** , **api** and **api-client** maven modules:

![kZaWYEM Z TZWmoZxXOGWBYi0DjEy6lPAY4saueqQ9Zeivzak14pI4gPM3w](https://lh5.googleusercontent.com/kZaWYEM_Z_TZWmoZxXOGWBYi0DjEy6lPAY4saueqQ9Zeivzak14pI4gPM3w-C9Ols3v1t97CgWTi7nB7QCenYEsY3ou303XJkSGDHlf0KBLMM8H6uUAtmHzMnWLgvxlNytX1mCmac6wCRBA2tg "Git submodules 12")

Just to show another example, committing changes in Intellij will look like this:

![wlYQ1o1W8yNHNVWk6PKQ1dqUAgqMQ7K8YTc6TAISi6MDjTRentAeh5comibL4twW Xba5FB le8J cZetmTHtk4eH6F7J fupteB8eDrRj4AObAFmYIF3AN jubz0WEOIt TZBOMC9JiHZNfw](https://lh5.googleusercontent.com/-wlYQ1o1W8yNHNVWk6PKQ1dqUAgqMQ7K8YTc6TAISi6MDjTRentAeh5comibL4twW-Xba5FB_le8J_cZetmTHtk4eH6F7J-fupteB8eDrRj4AObAFmYIF3AN-jubz0WEOIt-TZBOMC9JiHZNfw "Git submodules 13")

We can see the parent maven module & the child modules.  In this case, all are using the main branch from git, so Intellij doesn’t show any branch information, otherwise, you will see branch info in place.

In the push operations, we just see the 2 git repos for this mss:

![aK 0VTIOtATuhCGfu gXenD 0IbfRFIL Aa9z5V82VguRaIBQEieTRP EstBtl2vp048hg9bKatwC1io6oHURqFl8VeueGMmIUNPgX H5DsLnv1Ip3ClsHkBeRKO4a9V3HkfzOdl7HRjSlWA](https://lh3.googleusercontent.com/aK __0VTIOtATuhCGfu-gXenD__ 0IbfRFIL_Aa9z5V82VguRaIBQEieTRP-EstBtl2vp048hg9bKatwC1io6oHURqFl8VeueGMmIUNPgX-H5DsLnv1Ip3ClsHkBeRKO4a9V3HkfzOdl7HRjSlWA "Git submodules 14")

## Running the application

Run both mss1 and mss2 as any Spring Boot application. In the main folder of each mss compile and run:

```
mvn clean install
cd api
mvn spring-boot:run
```

NOTE: **application.properties** -> **server.port** not working in base parent modules, because the **RestTemplate @Bean** is defined in the child maven submodule and Spring is trying to get the properties files from it’s classpath, so a **ServerPortCustomizer.java** is needed to set ports.

In the mss1 and mss2, we have the same endpoints:

[http://localhost:8081/user/info](http://localhost:8081/user/info)

![sw7ZURrU01jo2GhKBNMA7qTdFIP 8z CIr9X8tDR1JWx3bYB7lrql 7OXdSf0dlhn9SBDP 9kR2ed4Q5Exw fRQmeNCtee AODN tb4Q V4rAew](https://lh6.googleusercontent.com/sw7ZURrU01jo2GhKBNMA7qTdFIP_8z-CIr9X8tDR1JWx3bYB7lrql_7OXdSf0dlhn9SBDP-9kR2ed4Q5Exw_fRQmeNCtee_AODN-tb4Q-V4rAew-biy8SozTvDsxVdd5AeZ3H7vWuTBrsvaYYw "Git submodules 15")

[http://localhost:8081/bank/info](http://localhost:8081/bank/info)

![](https://lh4.googleusercontent.com/HPGdvdjcbe21VvmkUb5Uk39EzzdyhaJlr5YZjHkBWnWbtwaKk8G38OEmjWAFFs9P48joFGVmt0gQSiJxNBg0fZjJFXgYaMVCFzDLhDBApjVR4U3oHjNM6Lxj_zo6V35RsPssgAXdxG9SOZATQw "Git submodules 16")

[http://localhost:8081/api/client/exception](http://localhost:8081/api/client/exception)

[http://localhost:8082/user/info](http://localhost:8082/user/info)

![GnFwlY2hiD3DA0mUSKMmOb mBZxIgizSwucLcPWardb0mf9eSG040v3aK5tSjrWRkMYfwbkQmI7UdN7e0 PUcGqNZElEF4WPJDE9am9KC3hlvonqD1Q4I9lb9 PWihD 90XWX68RPOO7 tDeEA](https://lh6.googleusercontent.com/GnFwlY2hiD3DA0mUSKMmOb_mBZxIgizSwucLcPWardb0mf9eSG040v3aK5tSjrWRkMYfwbkQmI7UdN7e0_PUcGqNZElEF4WPJDE9am9KC3hlvonqD1Q4I9lb9-PWihD-90XWX68RPOO7-tDeEA "Git submodules 17")

[http://localhost:8082/bank/info](http://localhost:8082/bank/info)

![hI2OVhDUUEVVyOeEzfHlWjd3 hrI0U2YN1h4f77 1p1uE68UStc9UN8gYBEWFb O4RGjcgWZvxrAdSMBC0oniLlzKRpUlkIh2vueLACbp 8CfLcYEk8y2cTB2Ar uUQdB hCTcFb IPgubDyeg](https://lh5.googleusercontent.com/hI2OVhDUUEVVyOeEzfHlWjd3-hrI0U2YN1h4f77-1p1uE68UStc9UN8gYBEWFb_O4RGjcgWZvxrAdSMBC0oniLlzKRpUlkIh2vueLACbp-8CfLcYEk8y2cTB2Ar_uUQdB-hCTcFb-IPgubDyeg "Git submodules 18")

[http://localhost:8082/api/client/exception](http://localhost:8082/api/client/exception)

As you can check on the implementation mss1 (in port 8081) is calling to mss2 (8082) via ApiClient on the /bank/info endpoint, and mss2/user/info is calling to mss1/user/info.