Tracking Git Reference History in Gerrit with Reflog Recorder Plugin

If you’ve ever wished Gerrit supported git reflog-style history natively, you’re not alone. While Gerrit keeps track of patch sets and reviews, it doesn’t provide a clean way to trace every ref update over time across all branches. To solve this gap, I built a plugin: gerrit-plugin-reflog-recorder.

What It Does

The plugin listens to every GitReferenceUpdatedListener event and logs it into an embedded H2 database. Each entry contains:

  • Project name
  • Reference (e.g., refs/heads/main)
  • Old revision SHA-1
  • New revision SHA-1
  • UTC timestamp
  • Gerrit user

This allows you to answer questions like:

What was the state of main at 10:00 UTC yesterday?

Why Not Use Gerrit’s Built-in Reflog API?

Gerrit does provide a reflog endpoint:

GET /projects/{project}/branches/{branch}/reflog

However, it has significant limitations:

  • It only works if Git reflogs are enabled and retained (not default in JGit-based Gerrit).
  • It shows recent ref changes but doesn’t allow querying by timestamp.
  • It’s tied to file-based Git storage and may expire due to garbage collection.

By contrast, this plugin:

  • Stores updates in an indexed, queryable database (H2)
  • Supports timestamp-based resolution
  • Is independent of Git’s internal reflog retention
  • Powers manifest rewriting for reproducible builds

Key Features

  • Reflog-style tracking of all Git ref updates in Gerrit
  • SSH commands to query historical revision state or resolve a manifest
  • Manifest resolver that rewrites default.xml to match the state of the repo at a given timestamp

SSH Commands

  • get-reflog: Returns the revision of a ref at a specific time
  • import-native-reflog: Imports JGit reflog from existing local repositories
  • resolve-manifest: Rewrites default.xml using reflog data to create a timestamp-pinned manifest

Manifest Cleanup

When resolving manifests, the plugin strips:

  • <superproject> and <contactinfo> elements
  • Projects with groups="notdefault"

The result mimics the output of:

repo manifest -r -o static.xml

Architecture

The plugin is structured in layers:

  • ReflogRepository: Handles database operations
  • ReflogService: Implements lookup and resolution logic
  • ManifestResolver: DOM manipulator for manifest editing
  • SSH commands: CLI tools for interacting with the data
  • ReflogRecorder: The listener that writes to the database

Install and Use

To install:

git clone https://github.com/maksonlee/gerrit-plugin-reflog-recorder.git
cd gerrit-plugin-reflog-recorder
mvn package
cp target/reflog-recorder.jar $GERRIT_SITE/plugins/
sudo systemctl restart gerrit

To query:

ssh -p 29418 user@host gerrit get-reflog \
  --project my-project \
  --ref refs/heads/main \
  --timestamp 2025-05-11T12:00:00Z

Sync Code Using Static Manifest

# Init repo with your manifest repo and branch
repo init -u git://gerrit/platform/manifest -b android-15.0.0_r30

# Override manifest with a pinned version generated from your plugin
ssh -p 29418 maksonlee@gerrit reflog-recorder resolve-manifest \
  platform/manifest \
  refs/heads/android-15.0.0_r30 \
  2025-05-04T08:30:00Z > .repo/manifest.xml

# Sync code to exact state
repo sync -c

Future Plans

  • Add REST APIs
  • Add automated tests (unit and integration)

Source

You can find the full source code here: 👉 https://github.com/maksonlee/gerrit-plugin-reflog-recorder

If you’re using Gerrit for Android or AOSP workflows where pinned manifests are crucial, this plugin may help you track historical state with more confidence.

Let me know what you’d improve or add next!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top