(no title)
remenoscodes | 6 days ago
In April 2007, during a flame war about the Linux 2.6.21 release, Linus wrote:
"There must be some better form of bug tracking than bugzilla. Some really distributed way of letting people work together, without having to congregate on some central web-site kind of thing. A 'git for bugs', where you can track bugs locally and without a web interface."
Source: https://lore.kernel.org/all/alpine.LFD.0.98.0704290848360.99...
19 years later, nobody shipped this. 10+ tools tried (Bugs Everywhere, ticgit, git-bug, git-dit, git-appraise, git-issue). All failed for similar reasons — mostly file-based storage that breaks on merge, and no format spec for ecosystem adoption.
The core insight: issues are append-only event logs, and Git is a distributed append-only database. So I mapped issue tracking directly to Git primitives:
- Commits = issue events (creation, comments, state changes)
- Refs = issue identity (refs/issues/<uuid>)
- Trailers = structured metadata (same format as Signed-off-by)
- Merge commits = conflict resolution
- Fetch/push = sync
Usage: $ git issue create "Fix login crash" -l bug -p high
$ git issue ls -f full
$ git issue show a7f3b2c
$ git issue sync github:owner/repo
The architecture follows Git's own philosophy: the core only knows commits, refs, and trailers. Platform bridges (GitHub, GitLab, Gitea/Forgejo) are separate scripts that translate between APIs and git primitives. New platform = new bridge, core doesn't change.The real deliverable is ISSUE-FORMAT.md — a standalone spec that any tool can implement. If this project dies tomorrow, the spec survives. That's the key difference from prior art: none of them produced a standalone format specification.
282 tests across 22 suites. POSIX shell, zero dependencies beyond Git for the core. Platform bridges need jq + their respective CLIs (gh, glab, or curl for Gitea/Forgejo).
Honest limitations: shell is slow with large repos (10k+ issues work but not fast). A C rewrite is on the roadmap, inspired by the path git-subtree took into contrib/.
Feedback I'm looking for: Is the format spec (ISSUE-FORMAT.md) clear and implementable? What edge cases did I miss? Would you actually use this?
Install:
brew install remenoscodes/git-native-issue/git-native-issue
# or
curl -sSL https://raw.githubusercontent.com/remenoscodes/git-native-issue/main/install.sh | sh
hunvreus|6 days ago
remenoscodes|6 days ago
Three key differences:
1. Plain Git primitives — git-bug uses CRDTs with JSON operation logs. git-native-issue uses commits as events, Git trailers for metadata (same format as Signed-off-by), and merge commits for conflict resolution. No custom serialization.
2. Standalone format spec — git-bug's "format" is whatever its Go code produces. git-native-issue ships ISSUE-FORMAT.md, a standalone specification that any tool in any language can implement. The spec is the deliverable, not the CLI.
3. Simplicity — CRDTs are powerful but overkill here. Git already solves distributed conflict resolution with three-way merge. Why rebuild that in userspace?
git-bug validated that storing issues in Git refs works. I built on that lesson with a simpler data model and a spec-first approach.
kwhkim|6 days ago
On CRDTs: I assume tools like git-bug adopted CRDTs primarily to avoid merge conflicts, but "last-writer-wins" via timestamps is risky — clocks are notoriously unreliable or set incorrectly. While CRDTs aren't "accurate" either, they do their best to converge. Personally, I'm uncomfortable with systems that silently overwrite edits when multiple people change the same issue differently. If two users modify state concurrently, I'd rather see an explicit conflict than an automatic resolution.
Related to that, I couldn't fully determine from the docs how your merge behavior works in practice. It seems like there are no conflicts, but how they are resolved is unclear to me. This is easily one of the hardest design decisions in a distributed issue system. One approach might be restricting certain edits (e.g., only authors can modify specific fields) or explicitly raising conflicts when a semantic disagreement occurs. I prefer the latter. With the help of AI, we could likely distinguish semantic conflicts from trivial syntactic differences (like LF vs. CRLF).
Regarding UUIDs: I understand why Git uses hashes — collision avoidance is critical in a distributed system. However, from a UX perspective, long, opaque identifiers are difficult to remember or reference in conversation. I've explored using shorter, human-friendly identifiers that still minimize collisions. I think Ergonomics matter immensely if this is intended for daily use.
A practical concern: using custom refs per issue can clutter the namespace. In tools like VS Code's Git graph, enabling "Show Remote Branches" causes remote issue refs to appear visually, adding significant noise. It's not a dealbreaker, but it does affect usability in some Git clients (speaking from my experience with git-bug).
Broadly speaking, I'm still undecided about storing issues directly as Git commits. Whatever the merge policy or conflict resolution strategy, it can be implemented in a custom merge engine (I think — and it's on my to-do list). You can track how issues evolved over time with commits, but it makes managing them in batch or bulk more difficult. A file-based system can achieve the same effect using `git log -- $FILENAME`.
That said, I really like that you extracted a standalone ISSUE-FORMAT.md. A format spec that outlives the implementation is arguably the most important part of this effort — especially if it includes a specification for attachments. Even though I'd prefer the issue format to be more flexible and casual, trying to establish a standard is worth the effort.
remenoscodes|6 days ago
Timestamps: You're right that the current merge uses committer timestamps (LWW), and clocks can disagree. The spec is explicit about this tradeoff — Principle 4: "Last-writer-wins over Lamport clocks." The reasoning: for issue tracking (as opposed to, say, collaborative editing), the practical risk of clock skew producing a wrong merge result is low, and when it does happen, a follow-up commit corrects it. The format is versioned (Format-Version: 1), so a future version can introduce logical clocks if production use reveals timestamp-related bugs. In 8+ months of use — including imports from multi-contributor projects (GitHub, GitLab, Gitea) — clock-skew issues haven't surfaced. I'm now adopting it in a team setting at work, which will be the real stress test for the merge heuristics.
UUIDs: In practice, users interact with 7-character short IDs (a7f3b2c). The CLI resolves abbreviations unambiguously, similar to how git log abc1234 works. Sequential IDs would require a central counter, which breaks in distributed systems.
Namespace: refs/issues/* doesn't appear in branch listings (git branch, git log --all with default config). Most Git GUIs filter to refs/heads/* and refs/remotes/*. For fetch performance with many issues, Git protocol v2 does server-side ref filtering, so only requested refs transfer. Valid concern though worth documenting.
Attachments: Agreed, that's tracked for Format-Version 2 — binary blobs in the tree object instead of the empty tree. The spec's Section 12 outlines this.
The format spec is designed to evolve. Appreciate the detailed feedback.
michaelmure|6 days ago
FYI, git-bug doesn't use timestamps to figure out the ordering. It first uses the git DAG topology (it defines ancestors), then Lamport clocks (increment for any changes on any bugs), then order by hash if there is still an ambiguity. Note that the git DAG could also be signed, which would also provide some form of reliance against abuse.
I had an interesting discussion recently about how to handle conflict for bug trackers. In my opinion it's a great use-cases for CRDTs (as it avoids data corruption), as long as all user intents are visibly captured in a timeline and easily fixable. It turned out though that there is an interesting middle ground: as the CRDT captures *when* a concurrent editing happen, it's 100% doable to highlight in the UI which event are concurrent and might need attention.