Git commit id Plugin with Spring Actuator

The git commit-id plugin is very useful to depict the state of the git repository when a binary has been created. Imagine the case of multiple deployments in a shared staging environment using the same version. You did not cut off your new version yet and multiple deployment are executed, having that information included helps.

We will start by a simple maven Project with a hello world application.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <artifactId>git-commit-id-example</artifactId>
    <groupId>com.gkatzioura</groupId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

</project>

Then a main class

package com.gkatzioura.commitid;

public class Application {
    public static void main(String[] args) {
    }
}

Let’s add the plugin

<build>
        <plugins>
            <plugin>
                <groupId>io.github.git-commit-id</groupId>
                <artifactId>git-commit-id-maven-plugin</artifactId>
                <version>5.0.0</version>
                <executions>
                    <execution>
                        <id>get-the-git-infos</id>
                        <goals>
                            <goal>revision</goal>
                        </goals>
                        <phase>initialize</phase>
                    </execution>
                </executions>
                <configuration>
                    <dotGitDirectory>${project.basedir}/../.git</dotGitDirectory>
                    <generateGitPropertiesFile>true</generateGitPropertiesFile>
                </configuration>
            </plugin>
        </plugins>
    </build>

Obviously this will work, the file will be located at target/classes/git.properties, but we do want to make it easier to retrieve that information.
It’s much easier to have an endpoint that exposes this piece of information, than checking binaries.

This brings us to actuator.
On Spring we have actuator endpoints that show various information like health or in our case info.
Eventually we can inject this information to the info actuator endpoint.

So let’s import our Spring boot dependencies

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <artifactId>git-commit-id-example</artifactId>
    <groupId>com.gkatzioura</groupId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>io.github.git-commit-id</groupId>
                <artifactId>git-commit-id-maven-plugin</artifactId>
                <version>5.0.0</version>
                <executions>
                    <execution>
                        <id>get-the-git-infos</id>
                        <goals>
                            <goal>revision</goal>
                        </goals>
                        <phase>initialize</phase>
                    </execution>
                </executions>
                <configuration>
                    <dotGitDirectory>${project.basedir}/../.git</dotGitDirectory>
                    <generateGitPropertiesFile>true</generateGitPropertiesFile>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Also we shall update our main class in order to spin up our Spring Boot Application

package com.gkatzioura.commitid;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
    }

}

Then you need to enable the info endpoint. Can be done by adding the setting on the properties or env variables.

management.endpoints.web.exposure.include=health,info

Once up and running by going to

curl http://localhost:8080/actuator/info

We shall be presented with the git information

{
  "git": {
    "branch": "master",
    "commit": {
      "id": "e77882e",
      "time": "2021-06-20T09:32:36Z"
    }
  }
}

This was pretty seamless so let’s explain what happens behind the scenes.

By doing mvn clean compile the git.properties file get’s generated.
By running the application, the info endpoint will be enabled based on the properties
The Spring environment will pickup the git.properties files.
Actuator will identify that the file exists and will expose it on the properties.

You can find the source code on github.

My most used Git commands on open source projects.

The basic step when committing to open source projects is to fork the project.
Then the process is easy you create your branch and you make a pull request. However from time to time you need to adjust you branch based on the latest changes.

Sync fork

This is how you sync your fork to the original one.

#set remote if it does not exist. This is the project you forked from
git remote add upstream git@github.com:account/project-name.git
git fetch upstream
git checkout master
git merge upstream/master

Synchronize from original Repo

This is pretty easy but you might want something more than just synchronizing with the original repository.

For example there might be a pull request which never got merged for various reasons and you wan’t to pick up from where it was left.

The first step is to add the repository needed

git remote add $remote_repo_identifier $remote_repo_url

So we just added another remote to our repository.

The next step is to fetch the branches from the remote.

git fetch $remote_repo_identifier

Then you can switch to the branch of your choice, continue make a new branch and continue with a pull request.

git fetch $remote_branch

Remove the upstream

 git remote remove $remote_repo_identifier

Set upstream to the current repo

git branch -u $remote_repo_identifier/$remote_branch $remote_branch
git branch --set-upstream-to=$remote_repo_identifier/$remote_branch $remote_branch

For example change the upstream to the origin one

git push --set-upstream origin $remote_branch

Continue on an abandoned Pull Request

It is very common to see PRs getting left behind for various reasons. If the value, the PR was to deliver, is what you seek, it makes sense to pick up where it was left improve it and make it up to date. Obviously in those cases chances are you just pick up the changes from the original fork to your own fork and continue from there (it can be difficult to contribute to the original forked PR).

#Add the fork of the PR as a remote
git remote add $remote_repo_identifier $remote_repo_url
#Fetch the branch from the fork
git fetch $remote_repo_identifier
#checkout to a new branch taken from the original PR
git checkout -b $remote_branch $remote_repo_identifier/$remote_branch
#set upstream to your fork
git branch $remote_branch --set-upstream-to origin/$remote_branch

Rebase from original repo

Now that we got the upstream commands in place let’s see how to rebase from the origin fork.
The rebase is a very common thing.
Branch starts from fork code is added, then a merge is getting closed and as expected a rebase is asked because master had some changes.

First let’s add and fetch from the upstream

git remote add upstream http://the-repo
git fetch upstream

Then checkout to the branch of your choice and rebase

git checkout branch-under-pr
git rebase upstream/master

Once your rebase is successful proceed on pushing

git push -f origin branch-under-pr

Git repositories through ssh.

So you have an ssh server?
Great!!! Time to setup some git repos.

If you don’t already have a git user and git installed

sudo adduser -m git
sudo apt-get install git

You can use the git account either through normal password authentication or by using private and public ssh keys. Your choice 🙂

Then set up the repo.

cd /home/git/
mkdir mygit.git
cd mygit.git
git --bare init

And you are ready to go.
Open a terminal on your pc and just do

git clone git@yourserverip:/home/git/mygit.git

In order to share the project with other users you can share the project with a specific group, for example the ‘developers’ group.

chgrp -R developers gitrepo
chmod -R g+swX gitrepo