Include a Git revision in firmware with PlatformIO

Posted on 20 May 2021 in Mechatronics

How to include a Git revision in your firmware at build time with PlatformIO.


This article is a comprehensive write up of two PlatformIO issues I responded to on in late 2020:

PlatformIO supports the generation of dynamic build flags. This feature allows the creation of build flags by executing a user defined script. The script should output one or more gcc -D options to standard output. For example:

-D SRC_REVISION="b4837070c4b10d37acfbf0283b758d38e739a670"

The -D option allows the defination of a macro. From the gcc(1) man page:

-D name
Predefine name as a macro, with definition 1.
-D name=definition
The contents of definition are tokenized and processed as if they appeared during translation phase three in a #define directive. In particular, the definition will be truncated by embedded newline characters.

Project structure

This example uses a typical PlatformIO project structure:

├── src
│   └── main.cpp
└── platformio.ini

Configuration file

The script to run is defined by the build_flags option in platformio.ini. Scripts are indicated by prepending them with a !.

description = Include Git revision in firmware with PlatformIO

board = esp32dev
framework = arduino
monitor_speed = 115200
platform = espressif32
build_flags =

Download platformio.ini.

User defined script

The following Python script will set two predefined macros:

  1. SRC_REVISION containing the Git revision, for example 97c333a4b3c732523e09742318d7acc52b33dbcc, and
  2. SRC_STATE defining the state of the working tree as either clean or dirty.
#!/usr/bin/env python3
"""Git revision and working tree state"""

import subprocess

REVISION = subprocess.check_output(["git", "rev-parse", "HEAD"]).strip()

if subprocess.check_output(["git", "diff", "--stat"]).strip() == "":
    STATE = "clean"
    STATE = "dirty"

print("-D SRC_REVISION='\"{}\"'".format(REVISION.decode("UTF-8")))
print("-D SRC_STATE='\"{}\"'".format(STATE))



The predefined macros may be used in src/main.cpp as follows:

#ifndef UNIT_TEST

#include <Arduino.h>

#define SRC_REVISION "(revision not defined)"

#ifndef SRC_STATE
#define SRC_STATE "(state not defined)"

void setup() {

void loop()



Download main.cpp.


Example output on the PlatformIO device monitor:

> Executing task: platformio device monitor <

--- Available filters and text transformations: colorize, debug, default, direct, esp32_exception_decoder, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at
--- Miniterm on /dev/ttyUSB0  115200,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---