tbd

module
v2.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2026 License: MIT

README

tbd

tbd is a workflow-aware Git CLI for trunk-based delivery. Version 2 uses Cobra flags only; the old colon argument syntax is intentionally gone.

The core rule is still simple: deployable work must be rebased onto the current configured trunk before it moves through deploy or release refs.

Install

go build -o tbd ./cmd/tbd

Quick Start

tbd init --yes
tbd feature --id JIRA-123 --desc "Add login"
# edit files
tbd commit
tbd lease dev-deploy
tbd release rc 1.2.3
tbd release complete 1.2.3

tbd commit stages all changes, keeps the branch to one commit, fast-forwards the local trunk from the remote when possible, rebases onto trunk, and amends tbd workflow metadata into that same commit.

For generic Git graph surgery:

tbd sr
tbd sr another-branch
tbd squash-rebase

Defaults

tbd init --yes writes .tbd.yaml with these defaults:

version: 2
trunk-name: main
remote: origin
auto-rebase: true
rerere: true
branches:
  feature-template: feature/{id}-{slug}
  fix-template: bugfix/{id-}{slug}
  collab-suffix: -collab
  stack-suffix: -stack
release:
  strategy: tag
  branch-prefix: release/
  tag-template: v{semver}
  rc-tag-template: rc-{semver}
  bad-tag-template: bad-{timestamp}
  default-revert-bump: patch
  delete-remote-rc-on-uat-reset: true
deploy:
  strategy: tag
  refs: [dev-deploy, test-deploy, prod-deploy]
push:
  branch: force-with-lease
  tag: force-with-lease
locks:
  ref-prefix: refs/tbd/locks/
  default-ttl: 3h

Use branch mode when a CD system only watches branches:

tbd init --yes \
  --release-strategy branch \
  --deploy-strategy branch \
  --deploy-ref deploy-dev \
  --deploy-ref deploy-uat \
  --deploy-ref prod-deploy

In branch release mode, deploy branches are mutable lease refs, but release/<semver> branches are immutable. A successful release creates v<semver> and fast-forwards the configured trunk branch to the release commit.

Workflows

Feature:

tbd feature --id JIRA-123 --desc "Add login"

Fix:

tbd fix --desc "Patch production login"
tbd fix --id JIRA-456 --desc "Patch production login"

Collab creates one aggregate branch and tracks each feature in metadata and release notes:

tbd collab --id JIRA-1 --desc "Feature one" --id JIRA-2 --desc "Feature two"
tbd collab add --id JIRA-3 --desc "Feature three"

Stack creates one branch with at most one commit per issue. Touching an item moves it to the top of the stack metadata, and tbd stack remove --id JIRA-2 removes it and rebuilds from remaining recorded commits where possible.

tbd stack --id JIRA-1 --desc "Feature one" --id JIRA-2 --desc "Feature two"
tbd stack add --id JIRA-1 --desc "Feature one"
tbd stack remove --id JIRA-2

git rerere.enabled=true is set by default during init because stack/collab rebases deliberately reuse conflict resolutions.

Releases

Tag strategy:

tbd release rc 1.2.3
tbd release complete 1.2.3

release rc deletes/replaces rc-<semver> locally and remotely. The RC tag only exists when the candidate is rebased onto the current trunk and marked good.

Branch strategy:

tbd release prepare 1.2.3
tbd release complete 1.2.3

release prepare creates immutable release/<semver>. release complete tags v<semver> and fast-forwards trunk to that release commit. Numbers only go up; bad commits are marked with tbd tag <ref> bad, which creates bad-<timestamp>.

Release metadata is written to RELEASE.json and rendered to RELEASE.md. Draft notes can move with the same topology as the commits while a feature set is still being worked.

Reverts

tbd revert --ref <sha-or-tag-or-version> --why "remove feature"
tbd revert --all-past v1.2.3 --why "rollback to last good production"
tbd revert --ref JIRA-123 --minor --why "remove larger feature"

Before a production/RC tag exists, feature removal does not force a semver bump. After an RC or production tag exists, revert metadata defaults to a patch bump unless --minor or --major is passed.

Deploy Leases

tbd lease dev-deploy
tbd steal dev-deploy
tbd relinquish dev-deploy
tbd lease deploy-uat --to HEAD

Deploy refs are tags or branches depending on deploy.strategy, but the semantics are identical: the ref is moved by compare-and-swap where a remote is available. lease borrows an unheld deploy mutex or advances your own held mutex. It refuses to silently take a ref held by another branch. steal is the explicit takeover verb. relinquish releases your held mutex by moving the deploy ref back to the current trunk head. Do not work while checked out on deploy branches; tbd refuses those operations.

Locks

tbd lock acquire uat
tbd lock status uat
tbd lock acquire uat --steal
tbd lock release uat

Locks are stored under refs/tbd/locks/<name> as metadata commits and pushed with CAS. The default TTL is three hours. Expired locks still require --steal so taking ownership is explicit.

See docs/locks.md for raw Git recovery commands.

Visualization

Terminal:

tbd graph
tbd graph --limit 200

Browser:

tbd serve --addr 127.0.0.1:8087

The server fetches on an interval, exposes /api/graph with commits, parent edges, refs, and tbd workflow state, and serves a Go/WASM SVG visualizer inspired by LearnGitBranching. The command console runs in the repository as a local daemon; it accepts quoted arguments and can run tbd ... or explicit git ... commands. The legacy /graph endpoint still returns the terminal DAG text. The WASM renderer is compiled on first request with the local Go toolchain, so source checkouts need go on PATH when serving the browser UI.

Demo simulation:

tbd demo
tbd demo stack
tbd demo collab
tbd demo --addr 127.0.0.1:8088 --dir .tbd-demo --no-open

The demo creates a marked workspace with one bare remote and four local clones for Ada, Ben, Cy, and Dee. tbd demo runs the basic path with four independent feature branches. tbd demo stack runs one standalone feature plus three three-item stack workflows. tbd demo collab runs one standalone feature plus three three-item collab workflows. The browser shows the four repos as a 2x2 desktop grid and only stacks them vertically on narrow screens. A toolbar zoom control keeps the graphs readable without losing access to the controls, and each step animates the repos and command logs it touched. Every demo uses real tbd commands and moves deployable work through dev-deploy, then qa-deploy, then prod-deploy, including amend/rebase behavior, lease refusal, explicit steal/recovery, relinquish-to-trunk, RCs, and production releases. The demo directory is deleted on normal shutdown and recreated fresh on the next run.

Development

go test ./...

The legacy internal/commands, internal/cli, and colon parser packages remain in the repository for regression coverage and reusable Git behavior. The binary entrypoint is the Cobra V2 app in internal/app.

Directories

Path Synopsis
cmd
tbd command
Command tbd is a trunk-based development wrapper over git's DAG.
Command tbd is a trunk-based development wrapper over git's DAG.
internal
app
Package app is the Cobra-based tbd v2 command surface.
Package app is the Cobra-based tbd v2 command surface.
app/visualwasm command
argv
Package argv is a self-contained command-line parser for the poly-style argument syntax used across the goforge tools:
Package argv is a self-contained command-line parser for the poly-style argument syntax used across the goforge tools:
cli
Package cli provides tbd's command dispatcher: a small registry that commands join from their init() functions, plus the Context handed to each handler.
Package cli provides tbd's command dispatcher: a small registry that commands join from their init() functions, plus the Context handed to each handler.
config
Package config loads and saves tbd's per-repository configuration from a .tbd.yaml file found by walking up from the working directory.
Package config loads and saves tbd's per-repository configuration from a .tbd.yaml file found by walking up from the working directory.
git
Package git is a thin wrapper over the git CLI.
Package git is a thin wrapper over the git CLI.
invariant
Package invariant enforces tbd's central rule: before any mutating operation, the head of the trunk must be an ancestor of the ref being operated on or produced.
Package invariant enforces tbd's central rule: before any mutating operation, the head of the trunk must be an ancestor of the ref being operated on or produced.
render
Package render provides terminal output helpers: optional ANSI color, simple aligned tables, and an ASCII commit-graph used to visualize rebases.
Package render provides terminal output helpers: optional ANSI color, simple aligned tables, and an ASCII commit-graph used to visualize rebases.
v2/config
Package config defines tbd v2's repository configuration.
Package config defines tbd v2's repository configuration.
v2/gitops
Package gitops contains reusable tbd v2 operations over git.
Package gitops contains reusable tbd v2 operations over git.
v2/hooks
Package hooks runs configured workflow hooks from the repository root.
Package hooks runs configured workflow hooks from the repository root.
v2/state
Package state persists tbd v2 workflow metadata in repository files.
Package state persists tbd v2 workflow metadata in repository files.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL