Your issue tracker and your code live in different places, and every so often that arrangement blows up in your face. GitHub's own status page shows what that looks like: on September 13, 2026, 96% of attempts to create an issue through the web interface failed for a stretch of about two hours. The code repositories were fine. The bug tracker was not. If a blocker had shown up during that window, you could not have filed it where your team was looking.
On September 22, the git-bug project shipped version 0.11.0, its first release in 16 months and close to 300 commits. Three days later it hit the Hacker News front page with 148 points and climbing. The pitch is one sentence: a distributed, offline-first bug tracker embedded in your git repository, using your existing git remote for sync, with no files added to your project.
That pitch raises obvious questions. Where does the data actually go? What happens when two people edit the same bug offline? Does a plain clone carry the bugs? To answer them, every command in this article was executed against the real v0.11.0 release binary on a scratch repository during preparation: identity creation, bug reports, comments, labels, closing, and a two-node sync with an offline edit on each side. Every output below is from that session, not from the README.
A disclosure first: this is not a production team story. What this article offers is a verified walkthrough: each command was run against the actual binary while writing, so what follows is tested output, plus an honest list of limits at the end.
Installing it takes two minutes
git-bug ships as a single static binary. From the releases page you can grab a tar.gz, a deb, an rpm, an apk, or an Arch package. The tar.gz worked cleanly in testing:
curl -LO https://github.com/git-bug/git-bug/releases/download/v0.11.0/git-bug_0.11.0_linux_amd64.tar.gz
tar xzf git-bug_0.11.0_linux_amd64.tar.gz
cp git-bug_0.11.0_linux_amd64/git-bug /usr/local/bin/
git-bug version
Output from the test run:
git-bug v0.11.0 d1819bd1dbd6 go1.27.1 linux amd64
The binary registers itself as a git subcommand, so once installed you can type either git-bug or git bug and both work. Everything is scoped to the repository you are standing in.
Creating an identity and your first bug
git-bug has no accounts and no server. An identity is just a signed git object. Create one:
git bug user new --non-interactive --name "Test User" --email test@example.com
Now file a bug. The --message flag takes the body from the command line, or -F - reads it from stdin:
git bug bug new --title "Login fails with 401 when token expires mid-session" \
-m "Steps: log in, wait for token expiry, call the profile endpoint.
Expected: refresh flow triggers.
Actual: hard 401, no refresh."
This prints the new bug's short hash:
0fdc4f7 created
Listing is one command, and it is fast. A git bug bug show round trip took 91 milliseconds on the scratch repo, cold:
git bug bug
0fdc4f7 open Login fails with 401 when token expires mid-session
Comments, labels, and status all work through the same implicit-selection model: select a bug once with git bug bug select 0fdc4f7, then run commands against it:
git bug bug comment new -m "Reproduced on staging, adding to this sprint"
git bug bug label new auth
git bug bug label new backend
git bug bug status close
Queries filter and sort without flags, which is where it starts feeling like a real tracker:
git bug bug status:closed sort:edit-desc
git bug bug "token expires" # full text search
That is the whole daily loop: new, list, comment, label, close. No server was running at any point.
Where the data actually lives
This is the part worth seeing with your own eyes. The project promises "no files are added to your project," and it delivers. After creating a bug, adding two labels, and commenting:
-
git ls-filesshows nothing new. -
git statusis clean. - The bug data lives under one ref:
refs/bugs/0fdc4f7d2dcfd8..., a chain of git commits whose blobs hold JSON operation packs.
You can inspect it with plain git plumbing:
git cat-file -p refs/bugs/0fdc4f7d2dcfd8cc4826cbbbcabe36d344aab689fe6980846ee8ea2fb271881d
tree 4b44ba1dad764c20930f494d897375f812b8ed57
parent 47f6be4509a2a8a863e50cc835dcc77e0b362353
author <> 1790352296 +0000
Each edit you make (comment, label change, status flip) is stored as an operation, and the current state of a bug is computed by replaying operations in order. The project documents this as an operation-based CRDT stored in git objects, and the on-disk format has a formal specification in its own repository. Because it is just git objects, your bug history inherits the things you already trust about git: hashing, signed authorship, and no overwrite without a merge.
The distributed test: two nodes, offline edits, one merge
Sync is the obvious question, so it got the full round trip. The result: it works, but the first step contains a gotcha you need to know.
The gotcha: a plain clone does not carry the bugs. Running git clone on the demo repo into a second directory fetched zero refs under refs/bugs/. git bug bug there printed an empty list. Git's default refspec only fetches branches and tags. So "teammates get the bugs for free on clone" is not true as-is.
The fix is built in. From the fresh clone, pointing at the same remote:
git bug pull origin
Output:
8c50061: new
f1d8f98: new
0fdc4f7: new
The bug list in the clone now shows everything, identities included. From there, the interesting test: playing a teammate working offline, commenting and reopening the bug in the clone, while the original repo stayed closed. Then, back in the original repo:
git remote add peer /tmp/scratch-repo/peer
git bug pull peer
Merging data ...
8c50061: new
0fdc4f7: updated
After the pull, the original repo showed the bug as open, with the teammate's comment ("Reopening, still fails on the iOS client") appended to the timeline. Two offline edit streams, merged without conflict, through nothing but git remotes. Pushing works the same way in reverse with git bug push. No bridge, no server, no API token. The clone test also answered the recovery question: any machine holding a clone of your repo holds a full backup of your tracker.
What v0.11.0 changed
The 16-month gap between 0.10.1 and 0.11.0 was not idle, and the release notes are worth reading. The headline items:
- The web UI became a code browser. File tree, syntax-highlighted files with linkable line ranges, commit history scoped to a file or directory, and collapsible diffs, all served by the same local binary. The backend learned to browse refs, trees, and blobs over the GraphQL API.
- The cache shrank dramatically. The old index was replaced by a new one that rebuilds automatically on upgrade. On the git-bug repository itself, the index went from about 51 MiB to under 4 MiB.
-
GraphQL subscriptions arrived.
bugEvents,identityEvents, andallEventslet tooling react to changes without polling. - A public format specification now lives in its own repo, so a third-party implementation or reader tool is possible.
The terminal UI (git bug termui) and web UI (git bug webui) both ship in the release binary. One note for people building from source: go install no longer bundles the web UI. Use the official release or make build.
The honest limits
This is a v0.x project and you should go in clear-eyed:
- The bridges are the whole story for team use, and they are incomplete. git-bug can import from and export to GitHub, Gitlab, Jira, and Launchpad. But the project itself runs on GitHub issues, and the web UI's public portal workflow (letting external users file bugs through OAuth) is explicitly marked not ready. The maintainer's README even lists an "inflatable raptor" under planned features, which tells you the tone of the roadmap.
- Everyone needs git-bug installed to read the bugs. Your PM on the web tracker does not. A bridge-based workflow (GitHub as source of truth, git-bug as your fast local offline mirror) is the realistic adoption path for most teams today.
-
Two decades of muscle memory do not move easily.
git bug bug newreads awkwardly, even with shell completion available for bash, zsh, fish, and powershell. Small thing, but it shows up in the first five minutes.
When I would actually reach for it
A decision list you can run against your situation:
- You work on code in places with no tracker access: air-gapped environments, client sites with restricted networks, ships, planes, or countries with unreliable connectivity. This is the killer use case, and it works today.
- Your tracker and your code have divorced: a hosted tracker you cannot query locally, an internal tracker that goes down more often than your forge. A read-only bridge mirror gives you searchable bugs in your terminal.
- You maintain an open-source project and want a fully self-hosted fallback: the spec plus plain git gives you an escape hatch from any single provider, which pairs naturally with the exit-planning mindset more teams are adopting this year.
- You need a polished hosted tracker with mentions, SLAs, and dashboards: not this, not yet.
The short version: git-bug is no longer a demo. v0.11.0 is a real tool with a real format spec, and the core distributed loop is exactly as advertised. I verified that myself, command by command.
I write about developer tools, backend engineering, and AI infrastructure every week. Subscribe, it is free.
Have you tried git-bug, or any tracker that lives in the repo? Did it survive contact with your team, and what did the bridge workflow look like in practice?
Top comments (0)