How to Build Git Version Control Into Your Apps
LibGit2 lets developers embed Git functionality directly into applications. Here's what that actually looks like in practice, and why it matters.
Written by AI. Tyler Nakamura
April 11, 2026

Photo: Utah Cpp Programmers / YouTube
Your app probably has configuration files. Maybe user settings, maybe JSON exports, maybe something custom. And if you're like most developers, you've probably thought: "wouldn't it be cool if users could undo changes to this?"
Turns out, you can just... build Git into your app. LibGit2 is the library that makes this possible, and developer Richard Thomson recently walked through exactly how to do it in a presentation for the Utah C++ Programmers group.
The demo app is dead simple—a text editor that tracks every save as a Git commit. Users can browse their edit history, jump back to previous versions, and restore old content. All the version control goodness of Git, but invisible to the user. No command line, no repository cloning, no merge conflicts to explain.
The Licensing Catch That Isn't Really a Catch
First thing you're probably wondering: can I actually use this commercially? LibGit2 is GPL2, which normally means "open source your entire app or don't touch this." But there's a linking exception that changes everything.
"As long as you don't modify libgit2 itself, you can link it into your application and you're not required to distribute the source code of your application," Thomson explains. "If you modify the library itself, you have to make your modifications available in source code form."
That's actually pretty reasonable. Use the library as-is, and your proprietary code stays proprietary. Fork the library to add features, and you contribute those features back. Most developers will never need to modify LibGit2 itself.
The Problem: LibGit2 Is Written in C
Here's where it gets interesting. LibGit2 is a C library, not C++. Everything's done with opaque pointers, handle types, and C-style functions. The official C++ binding exists, but it's coupled to Qt—which means if you're not already using Qt, you're dragging in a massive framework just to get some C++ syntax sugar.
Thomson's approach: write your own lightweight wrappers. Just the parts you need, nothing more.
His demo app needs exactly five things from the version control system:
- Get a configuration string from the repository
- Commit files
- Get the history of a file
- Get the content of a file
- Check if the repository is empty
That's it. Git has hundreds of operations available. Thomson's application facade exposes five methods.
The Simplifying Facade Pattern
This is the clever part. Instead of wrapping LibGit2's entire API surface, Thomson created an abstract interface that only exposes what his app actually needs. The implementation uses LibGit2, but the app never touches LibGit2 directly.
"I'm not writing a git client in the sense of like you would interact from the command line when you're managing the source control versions of your source code," he says. "I am just controlling the needs of my application here."
The benefits stack up fast:
- Your app code stays clean and simple
- You can mock the interface for unit testing
- You could theoretically swap Git for Mercurial or another VCS without touching app code
- You don't accidentally use Git features you don't understand
It's the classic software architecture move: add a layer of indirection that constrains what you can do, which paradoxically makes everything easier.
Handling the C API Without Losing Your Mind
C APIs return error codes, not exceptions. C APIs use opaque pointers that you have to manually free. C APIs require library initialization before you can call anything.
Thomson's wrapper types solve all of this:
- Every wrapper holds a lifetime member that ensures LibGit2 stays initialized as long as the wrapper exists
- Destructors automatically free the opaque handles
- A simple error-checking function converts LibGit2's error codes into C++ exceptions
- The wrappers are non-copyable and non-movable—you can't accidentally double-free a handle
The wrappers ended up covering about a dozen LibGit2 types: repository, index, tree, signature, object ID, commit, revision walker, blob, config, diff, and tree entry. Each one is just enough wrapper to make the C API feel like C++.
The Copilot Shortcut
Here's a detail that matters: Thomson used GitHub Copilot to help write these wrappers. He'd write the first wrapper by hand, then let Copilot generate the rest following the same pattern.
"I'd already extracted a wrapper by hand for the repository. So when it was extracting new wrappers, it was just following my examples," he notes. "I didn't have to get specific about things like, you know, they're not copy constructable, they're not move constructible."
This is actually how AI coding tools should work—you establish the pattern, the tool handles the repetitive parts while maintaining consistency.
What This Actually Enables
The demo shows version control for a single text file, but the pattern scales to way more interesting use cases:
- Configuration files that users can revert when they break something
- Auto-saving drafts with full undo history beyond simple undo/redo
- Application state that can be rolled back to any previous point
- Settings that track who changed what and when in multi-user environments
- Automatic backups that don't duplicate unchanged data
All without users knowing what Git is. The repository lives in the standard user data directory for your app. The GUI shows "version history" instead of "commits." Users click "restore previous version" instead of running git checkout.
The Part Nobody Mentions
What's missing from most LibGit2 tutorials is the messy middle—how do you actually decide which parts of the API to wrap? Thomson's answer is pragmatic: let your use case drive it. Start with the abstract interface your app needs. Implement just enough wrapper to support that interface. Add more wrappers only when you need them.
"The reason I recommend doing this is because it keeps you from getting seduced into creating elaborate sets of APIs around the entire functionality of Git that you'll never use," he explains. "So, it's just wasted effort, right?"
The full source code is on GitHub. The approach works. And it raises a question worth sitting with: how many other "power user" tools could we embed invisibly into apps, making advanced features accessible to people who'd never touch a terminal?
—Tyler Nakamura
Watch the Original Video
Managing Versions Programmatically with LibGit2
Utah Cpp Programmers
48m 0sAbout This Source
Utah Cpp Programmers
More Like This
Navigating Git Workflows: Which One Fits Your Team?
Explore GitFlow, GitHub Flow, and Trunk-Based Development to find the best workflow for your team.
Age of Empires' 25-Year Pathfinding Bug Had a Wild Cause
How a compiler flag change accidentally broke Age of Empires pathfinding for years—and why the community was right all along about the units walking through walls.
Explore GitHub's Hottest Open-Source Projects
Dive into GitHub's top trending projects this week, from AI tools to web enhancements.
Linear Says Issue Tracking Is Dead. Here's What's Next
Linear, the issue tracker beloved by engineers, just declared its own category obsolete. AI agents are changing how software gets built—for better or worse.