TicGit is a Git-native issue tracker. Tickets live in the repository as structured git-meta metadata instead of files on an orphan branch.
This is a clean Rust reimplementation of the old ticgit-ng idea. It does not
read or migrate legacy ticgit-ng branches.
All TicGit data is written on the git-meta project target under the
ticgit: namespace:
ticgit:schema-version string
ticgit:owners set
ticgit:views:<name> set of ticket UUIDs
ticgit:tickets:<uuid>:title string
ticgit:tickets:<uuid>:state string
ticgit:tickets:<uuid>:assigned string
ticgit:tickets:<uuid>:points string
ticgit:tickets:<uuid>:milestone string
ticgit:tickets:<uuid>:tags set
ticgit:tickets:<uuid>:comments list
ticgit:tickets:<uuid>:created-at string
ticgit:tickets:<uuid>:created-by string
Ticket existence is implied by the presence of fields under
ticgit:tickets:<uuid>:*; there is no separate ticket index.
The local query database is git-meta's .git/git-meta.sqlite. Exchange with
other clones happens through refs/meta/* using normal Git transfer.
From a checkout:
cargo install --path crates/ticgitAfter the crates are published:
cargo install ticgitThe binary is named ti.
git init
git config user.email you@example.com
git config user.name "Your Name"
ti init
ti new --title "fix the parser" --tags bug,parser --comment "fails on empty input"
ti list
ti show <ticket-id-or-prefix>Most commands accept a full UUID or any unique UUID prefix.
Create tickets:
ti new --title "add docs"
ti new --title "fix crash" --tags bug,cli --assigned you@example.com
ti new --title "investigate flaky test" --comment "seen on CI twice"List and filter:
ti list
ti list --state open
ti list --tag bug
ti list --assigned you@example.com
ti list --order title.desc
ti list --jsonShow details:
ti show <id>
ti show <id> --jsonSelect a current ticket:
ti checkout <id>
ti show
ti comment "follow-up note"
ti checkout --clearMutate tickets:
ti state resolved --ticket <id>
ti assign you@example.com --ticket <id>
ti assign --clear --ticket <id>
ti points 3 --ticket <id>
ti milestone v1.0 --ticket <id>
ti tag --ticket <id> bug ui
ti tag --ticket <id> --remove ui
ti comment --ticket <id> "fixed in the latest patch"Recent tickets:
ti recent
ti recent --limit 20Saved views are named snapshots of ticket UUIDs:
ti save-view bugs --tag bug
ti views
ti views bugs
ti list --view bugsTicGit delegates storage and transfer to git-meta-lib.
ti pull
ti push
ti syncti sync performs a pull followed by a push. If you pass --remote <name>, the
named git-meta remote is used; otherwise git-meta resolves the default metadata
remote from Git config.
The workspace has two crates:
ticgit-lib: domain model and git-meta-backedTicketStore.ticgit: theticommand-line application.
Example:
use ticgit_lib::{NewTicketOpts, TicketStore};
let store = TicketStore::discover()?;
let ticket = store.create("fix parser", NewTicketOpts::default())?;
println!("{}", ticket.id);
Ok::<(), ticgit_lib::Error>(())Run the full test suite:
cargo testRun just the library tests:
cargo test -p ticgit-libRun the CLI integration tests:
cargo test -p ticgit --test cliBuild the CLI:
cargo build -p ticgitPackage the crates before publishing:
cargo package -p ticgit-lib
cargo publish -p ticgit-lib
# After ticgit-lib 0.1.0 is available in the crates.io index:
cargo package -p ticgit
cargo publish -p ticgitThe CLI crate depends on ticgit-lib by both local path and published
version, so publish ticgit-lib first.
This project intentionally avoids the old ticgit-ng branch format. The new
format uses structured string, set, and list values with deterministic git-meta
merge behavior, which keeps ticket metadata queryable locally and shareable via
Git refs.