
Maintaining a custom Chromium fork is an expensive endeavor — not just in engineering hours, but in CI/CD resources.
In a recent project optimizing a patched Chromium fork, I inherited a GitHub Actions pipeline where the checkout and setup phase averaged 1 hour and 37 minutes. This delay occurred before a single line of code was ever compiled. By re-evaluating the source acquisition strategy, I was able to reduce that time to 1 minute and 15 seconds.
This was not achieved through minor caching tweaks. It required a fundamental architectural shift.
The Strategic Insight
CI environments do not require Git history — even for patched forks.
In our CI context, only two things were required: a deterministic source snapshot and a reproducible patch layer.
By treating Chromium as an immutable artifact rather than a living repository, the overhead of the Git protocol was eliminated entirely. The following architecture made this possible.
The Traditional Bottleneck
The official Google documentation is designed for developer flexibility. It typically follows this workflow:
- Clone depot_tools.
- Execute gclient sync.
- Perform a rebase against upstream.
- Build.
While this is vital for a developer workstation, flexibility introduces overhead that CI does not benefit from. In this context, branch navigation is unnecessary; the requirement is simply to build a specific revision with a defined set of modifications.
Analyzing the Overhead of gclient sync
When a sync is triggered, a complex orchestration is performed:
- Dependency Resolution: DEPS are parsed to resolve hundreds of sub-repositories.
- Git Negotiation: Hundreds of handshakes and packfile transfers are initiated.
- Metadata Overhead: Refs, tags, and history — none of which are utilized by the CI — are downloaded.
- Hook Execution: DEPS specify "hooks"—arbitrary scripts that are executed to download pre-built binaries (like the Clang toolchain, Node.js runtime, and sysroots) and configure the local environment.
Even with --no-history, packfile negotiation and object inflation still occur across hundreds of repositories.
On a GitHub Actions runner, this resulted in nearly two hours of high-latency network I/O.
The Transition to Stateless Patching
A common misconception in modern DevOps is that patching necessitates Git. While Git is an excellent tool for creating patches, utilizing a full Git tree in CI simply to apply them is often overkill.
Before Git dominated the landscape, large-scale projects like the Linux Kernel were maintained via patch-based workflows on mailing lists relying on the standard Linux patch utility to apply changes deterministically.
The asymmetry is obvious: A patch file is typically kilobytes of text, whereas a full multi-repository Git checkout transfers gigabytes of objects and history. By decoupling modifications from the Git history, the process was shifted from Stateful Patching (rebasing branches) to Stateless Patching (applying diffs directly to a directory).
The Implementation
To achieve maximum velocity, a model was implemented based on three deterministic layers:
- The Source Tree: Official source tarballs (e.g., chromium-100.0.4845.0-lite.tar.xz) are utilized. These represent the fully materialized state of the superproject at a pinned revision. These are fully resolved snapshots that require no Git negotiation.
- The Patch Layer: The standard Linux patch command is used to apply modifications directly to the extracted filesystem.
- Manual Orchestration: Only the essential toolchain scripts are triggered.
# 1. Acquisition of the snapshot (completed in seconds)
# Using the "Lite" tarball to minimize transfer size.
curl -O https://commondatastorage.googleapis.com/chromium-browser-official/chromium-[VERSION]-lite.tar.xz
tar -xf chromium-[VERSION]-lite.tar.xz
# 2. Patch application without Git
# This is performed as a pure filesystem transformation.
patch -p1 < ./my_patches/custom_feature.patch
# 3. Manual toolchain orchestration
python3 ./tools/rust/update_rust.py
python3 ./tools/clang/scripts/update.py
./third_party/node/update_node_binaries
./build/linux/sysroot_scripts/install-sysroot.py
Note on the Lite Version: The lite version is smaller because it excludes documentation and other non-essential artifacts. For CI systems, especially ephemeral runners, the lite archive is often preferable: smaller transfer size, faster extraction, and identical build correctness.
The Results: A 96x Reduction
By eliminating Git negotiation and multi-repo resolution, a staggering improvement was observed in the pipeline:
+--------------------+----------------------+------------------------------------+
| Phase | Previous (Git-based) | Optimized (Snapshot + Linux Patch) |
+--------------------+----------------------+------------------------------------+
| Source Acquisition | 1h 22m | 45s |
| Setup & Hooks | 15m | 30s |
| Total Setup Time | 1h 37m | 1m 15s |
+--------------------+----------------------+------------------------------------+
Trade-offs and Application
- Recommended for: Ephemeral CI runners and production release builds. This ensures idempotency — every build begins from the exact same bytes.
- Not recommended for: Local developer environments or workflows requiring git bisect, dynamic DEPS modifications, iterative patch stack rebasing, or any process that depends on Git metadata at build time. In those scenarios, gclientand a full repository checkout remain the correct and necessary tools.
For those seeking a reference implementation, the Ungoogled-Chromium project demonstrates a similar snapshot and patch model. Upstream is treated as an immutable base, and changes are maintained as a transparent patch set.
Final Thoughts
This experience reinforced an important lesson: tools designed for developer flexibility are not always optimal for automated systems.
gclient is a masterpiece of dependency management, but it was built for people, not automated pipelines. By moving to a stateless, snapshot-based model, nearly two hours were reclaimed from every build cycle.
In high-performance engineering, sometimes the most effective tool is the one that has been in the Linux /bin/ folder for decades.
96x Faster: Why Your Chromium CI Doesn’t Need Git was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.