Skip to content

v0.12.0

Latest

Choose a tag to compare

@github-actions github-actions released this 07 Nov 10:05
· 3 commits to trunk since this release
4ea4534

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 git binary 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 by gh 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/config and dropped its comments
  • #1023 (2023): SSH did not work without an agent
  • #1075 (2023): git bug bug comment edit opened 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): include and includeIf in 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 data on push or pull
  • #1556: git bug termui held 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.

Two git-bug processes sharing one repository

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 push into 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.notifier lets 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, include and includeIf (including hasconfig: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 pushurl and pushInsteadOf, and applies insteadOf the 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 .lock files 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.0 works too, as it rebuilds its own. Either way, expect to see Building cache... once.
  • release file names no longer contain the version: git-bug_0.11.0_linux_amd64.tar.gz becomes git-bug_linux_amd64.tar.gz, and the same goes for the deb, rpm, apk and Arch packages. Every artifact can now be downloaded from releases/latest/download/<name>. Scripts using the versioned names need updating.
  • packagers: the deprecated build variables commands.GitCommit, commands.GitLastTag and commands.GitExactTag are removed. Set the version with -ldflags "-X main.version=v0.12.0". Since Go's linker silently ignores unknown -X flags, a build that still uses the old variables reports its version as undefined.
  • git bug bug new -t <title> -F <file> now takes the title from -t and the whole file as the description. Before, the file's first line silently replaced the title. Using -m together with -F is now an error on bug new, bug comment new and bug comment edit, instead of silently ignoring the file (#1641).
  • GraphQL subscriptions: bugEvents, identityEvents and allEvents are replaced by a single entitiesChanged(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.name is now non-null, and is an empty string for the default repository.
  • the build/debug make target is gone. build/noweb and install/noweb build without the web UI.
  • if you use git-bug as a Go library: context.Context is now passed everywhere, the repository is split into composable parts, and errors use the standard library instead of pkg/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, includeIf and hasconfig:remote are 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 pushurl and pushInsteadOf, and applies insteadOf like 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 edit opens the editor with the current text of the comment (#1075), by @beausea
  • fix conflicting -t, -m and -F flags (#1641)
  • Ctrl-C now stops everything, including push, pull, bridges and repository browsing
  • two concurrent edits no longer overwrite each other's message file
  • git bug termui shows 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 --bind exposes it beyond loopback, by @mcepl

API

  • entitiesChanged subscription, 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

🚀 ☀️

New Contributors

Full Changelog: v0.11.0...v0.12.0