Repository navigation
Six weeks and about 90 commits after v0.11.0, git-bug v0.12.0 is available.
This is a maintenance release. There is no big new feature to show off, but there are a lot of bug fixes, and among them a good number of problems that had been open for years. Some of them go back to 2020.
Most of the work went into three places:
- the cache, largely rebuilt: there is no more repository-wide lock, and it now follows changes made outside of git-bug
- go-git, the git library git-bug uses, which needed many workarounds. If it has been getting in your way, git-bug can now use your
gitbinary for push and pull. - the git configuration, now handled by gitconfig, a new Go library that reads and edits git configuration exactly as git does. It lives in its own repository, so other Go projects can use it too.
Long-standing problems, resolved
- #409 (2020): the cache of a hosted repository was not updated when someone pushed to it
- #688 (2021):
branch config: invalid merge, for example with a branch created bygh pr checkout - #940 (2022): git-bug did not load your SSH configuration
- #1014 (2023):
the repository you want to access is already locked - #1022 (2023): git-bug rewrote
.git/configand dropped its comments - #1023 (2023): SSH did not work without an agent
- #1075 (2023):
git bug bug comment editopened an empty editor instead of the current comment - #1129 (2023): text validation let invisible and control characters through
- #1316 (2024): push and pull could not use different remotes
- #1402, #1475 (2025):
includeandincludeIfin the git configuration were not followed, so an identity configured that way was not found - #1416 (2025): authenticated HTTP(S) remotes did not work
- #1474 (2025): the deprecated
[section.subsection]syntax in a git config broke git-bug with an obscure error - #1485 (2025):
knownhosts: illegal base64 dataon push or pull - #1556:
git bug termuiheld a lock, and blocked every other git-bug command while it was running - #1589: a repository receiving a push only showed the changes once a git-bug command ran in it
The cache, rebuilt
The cache sits between the entities stored in git and everything else: the CLI, the terminal UI, the web UI, the bridges. It used to make two assumptions: that the process holding it is the only one touching the repository, and that nothing changes behind its back. Neither was true, and a lot of the bugs above came from there.
The command commits its change to git atomically, and updates that bug in the shared index. The web UI process notices the change in git, whether it comes from another git-bug process or from a git push. It reads what's already up to date from the index, rebuilds only what isn't and writes it back, and tells the browser through a GraphQL subscription.
Both assumptions are gone:
- no more repository-wide lock. Any number of git-bug processes can work on the same repository at the same time, safely. You can keep the web UI or the terminal UI open while using the CLI, or while an agent does (#1014, #1556).
- changes made outside are followed. The web UI and the terminal UI see a
git pushinto the repository, a pull, or another git-bug command, and show it shortly after (#409, #1589). They watch the filesystem where the operating system supports it, poll where it doesn't (network filesystems, for instance), and also compare every ref once a minute, as a backstop for anything those missed.git-bug.changes.notifierlets you choose, or turn it all off. - incremental repair. The cache records which commit each entity's derived data was built from, so on startup or on a change it rebuilds exactly what is out of date, no more and no less.
- a single SQLite index. The bleve search index and the excerpt files are replaced by one SQLite database, shared by all processes, using full-text search (FTS5). It is pure Go, so the binaries are still built without cgo. On the way, it fixes a bug few people noticed: full-text search returned at most 10 results.
Writes and failures got the same attention:
- the mutations of a single GraphQL request form one unit: everything they change on a bug becomes one commit, and if any of them fails, nothing is written. Creating a bug is no longer a special case committed on its own.
- a change written to git is no longer reported as a failure because refreshing the cache afterwards failed.
- on a pull, an entity that can't be merged no longer stops the merge of the others, and a failed sync is retried in the background.
- the Lamport clocks are safe with several processes writing to them, and protected from overflow.
- the ordering of a DAG entity's commits was wrong for some histories. It is now a real topological sort, and malformed DAGs are rejected.
Working around go-git
git-bug talks to git through go-git rather than running the git binary. That is safer, as nothing in a repository's configuration or hooks gets to run commands, and much easier to work with than parsing the output of git commands. But go-git also has gaps, and a good share of the issues reported against git-bug actually came from there. This release goes around a lot of them.
The biggest one is opt-in: a native git transport for push and pull.
git config git-bug.git-transport git
With it, git-bug runs your git binary to talk to remotes, so your SSH configuration, SSH agent, credential helpers and authenticated HTTPS remotes behave exactly as they do with git. This closes a whole family of issues: #940, #1023, #1316, #1416 and #1485. go-git stays the default, and git-bug fails to start if you ask for git but there is none on your PATH.
The rest is automatic:
- git configuration: git-bug no longer uses go-git for the git configuration, but gitconfig. It follows git's rules: every scope,
includeandincludeIf(includinghasconfig:remote), the deprecated syntaxes, git's locking. Edits only touch the lines they change, so your comments and layout are kept (#1022, #1402, #1474, #1475). The configuration go-git can't parse is kept away from it, so such a repository opens anyway (#688). - remotes: the go-git transport now honors
pushurlandpushInsteadOf, and appliesinsteadOfthe way git does. - refs: git-bug no longer relies on go-git to read and write refs. A failed update could leave an empty ref file behind, which then broke ref listing for the whole repository; it could not create a ref atomically; its locks were ignored by git; and it read the
.lockfiles of an update in progress as refs. - packs: go-git did not notice a pack written by another process, such as git itself.
- extensions: go-git refuses to open a repository using any git extension. The ones that make no difference to git-bug are now kept away from it, so sparse checkouts, blobless clones and worktrees with relative paths open (#1743).
Multiple PRs have been opened upstream to fix those issues at the source.
Breaking changes
- the local index format changed (bleve → SQLite). This goes both ways automatically: upgrading builds the new index and removes the old files, and going back to
v0.11.0works too, as it rebuilds its own. Either way, expect to seeBuilding cache...once. - release file names no longer contain the version:
git-bug_0.11.0_linux_amd64.tar.gzbecomesgit-bug_linux_amd64.tar.gz, and the same goes for thedeb,rpm,apkand Arch packages. Every artifact can now be downloaded fromreleases/latest/download/<name>. Scripts using the versioned names need updating. - packagers: the deprecated build variables
commands.GitCommit,commands.GitLastTagandcommands.GitExactTagare removed. Set the version with-ldflags "-X main.version=v0.12.0". Since Go's linker silently ignores unknown-Xflags, a build that still uses the old variables reports its version asundefined. git bug bug new -t <title> -F <file>now takes the title from-tand the whole file as the description. Before, the file's first line silently replaced the title. Using-mtogether with-Fis now an error onbug new,bug comment newandbug comment edit, instead of silently ignoring the file (#1641).- GraphQL subscriptions:
bugEvents,identityEventsandallEventsare replaced by a singleentitiesChanged(type, ids). It reports which entities changed, at most once per second, and leaves it to the client to refetch what it displays. - GraphQL:
Repository.nameis now non-null, and is an empty string for the default repository. - the
build/debugmake target is gone.build/nowebandinstall/nowebbuild without the web UI. - if you use git-bug as a Go library:
context.Contextis now passed everywhere, the repository is split into composable parts, and errors use the standard library instead ofpkg/errors.
Core
- no repository-wide lock: several processes can use a repository at once (#1014, #1556)
- the cache follows changes made outside of it, and repairs incrementally (#409, #1589)
- the search index and excerpts are stored in a single SQLite database
- full-text search is no longer capped at 10 results
- entity IDs are validated as hexadecimal, as they are (#1512)
- text validation catches more invisible and control characters (#1129)
- Lamport clocks are safe for concurrent writers and protected from overflow
- fix the ordering of DAG entity commits, and reject malformed DAGs
- cache files are written atomically
- fix a crash in query filters on unreachable entities
- faster ref listing, and a fix for a performance regression in the cache
- several long-standing flaky tests are gone (#1194, #1226, #1230)
Git
- optional native git transport:
git config git-bug.git-transport git(#940, #1023, #1316, #1416, #1485) - the git configuration is handled by gitconfig:
include,includeIfandhasconfig:remoteare followed, comments are preserved (#1022, #1402, #1474, #1475) - repositories with git config that go-git can't parse open anyway (#688)
- sparse checkouts, blobless clones and worktrees with relative paths open with go-git (#1743), by @trevor-vaughan
- go-git honors
pushurlandpushInsteadOf, and appliesinsteadOflike git (longest match wins) - git-bug handles refs itself instead of relying on go-git
- fix go-git not seeing a pack written by another process
CLI
git bug bug comment editopens the editor with the current text of the comment (#1075), by @beausea- fix conflicting
-t,-mand-Fflags (#1641) Ctrl-Cnow stops everything, including push, pull, bridges and repository browsing- two concurrent edits no longer overwrite each other's message file
git bug termuishows changes made outside of it
Web UI
- live updates from changes made outside the web UI
- drafts of new issues and comments survive a reload
- a failed save no longer loses what you typed: editors stay open, text and label choices are kept
- fix commit links in the commit history of the default repository (#1683), by @Ramdek
- HTTP server timeouts, as hardening when
--bindexposes it beyond loopback, by @mcepl
API
entitiesChangedsubscription, batched, replacing the previous per-entity subscriptions- all the mutations in a GraphQL request are committed together, or not at all
BugCommentHistoryStep.author: the author of each version of a comment
Bridges
- a dedicated lock prevents two bridge runs at the same time
- a cancelled import no longer moves its resume point forward
- fix the handling of cancellation
- the GitLab bridge accepts the newer personal access tokens, which contain dots, and also checks a token given on the command line (#1745), by @Ramdek
Documentation
- a reference of every configuration option
- the token permissions required by each bridge, in the docs and in
git bug bridge new --help, by @mcepl - simpler build-from-source instructions (#1578)
🚀 ☀️
New Contributors
- @lajawi made their first contribution in #1631
- @beausea made their first contribution in #1637
- @Ramdek made their first contribution in #1684
- @thrashbag made their first contribution in #1716
- @trevor-vaughan made their first contribution in #1744
Full Changelog: v0.11.0...v0.12.0
