gwtui is a Bubble Tea terminal UI for browsing Git worktrees, opening the selected worktree in your editor or terminal, and running Git commands inside it.
- Detects the current repository root when launched inside a Git repository
- Loads worktrees via
git worktree list --porcelain - Shows per-worktree status badges for remote tracking, merge state, and dirty state
- Scrolls through worktrees with keyboard navigation
- Shows selected worktree details, including branch, commit, upstream, ahead/behind counts, merge state, and dirty state
- Opens the selected worktree in a configurable editor command, defaulting to VS Code via
code . - Opens the selected worktree in a configurable terminal command
- Opens the selected branch on GitHub in the browser using the worktree's remote repository URL
- Opens the selected branch's pull request in the browser via GitHub CLI when one exists
- Shows a per-worktree action list with shortcuts for terminal commands, editor launch, staging, commit, branch creation, and delete
- Lets you create a branch for detached or branchless worktrees
- Lets you delete a worktree and its local branch with a confirmation prompt
- Opens a command mode to run raw Git commands like
git status,git fetch, orgit log --oneline -5 - Stages all files in the selected worktree with
git add . - Runs a built-in
hot pushworkflow with confirmation that fetches, pulls, stages, commits withhot push, and pushes, retrying on a new remote branch if the original push is rejected for being behind remote - Opens a commit message prompt and runs
git commit -m "..."in the selected worktree - Displays command output directly inside the TUI
- Optionally auto-refreshes the worktree list and status on a configurable interval
go install github.com/seanmayer/citadel/cmd/gwtui@latestFrom anywhere inside a Git repository:
go run ./cmd/gwtuiOr run the installed binary:
gwtuiup/k: move selection updown/j: move selection downo: open the selected worktree in the configured editort: open the selected worktree in a new terminalg: open the selected branch on GitHub in the browserp: open the selected branch's pull request in the browser when one existsa: stage all files in the selected worktree withgit add .h: start the built-inhot pushworkflow in the selected worktree and confirm withyc: open commit mode and write the commit message forgit commit -m "..."b: create a branch for the selected detached or branchless worktreed: delete the selected worktree and confirm withyenter: open command mode or run the commandspace/enter: continue from the command output view back to the worktree listr: refresh worktrees and branch status, optionally fetching first ifgit.fetch_on_refreshis enabledR: always rungit fetch --prune, then refresh worktrees and branch statusesc: leave command mode or output view?: show helpq/ctrl+c: quit
In command mode, you can also run hot push or git hot push as a built-in workflow instead of a raw Git subcommand. Citadel will ask for confirmation before it runs.
Worktree rows can include compact badges such as:
cleandirtylocal↑N↓Nmergednot mergederror
Merge status is checked against the configured git.base_branch, which defaults to origin/main.
By default gwtui loads config from:
~/.config/gwtui/config.yaml
If the file is missing, the app falls back to sane defaults.
Example config:
default_command: "git status"
keybindings:
open_editor: "o"
open_terminal: "t"
refresh: "r"
fetch_refresh: "R"
quit: "q"
help: "?"
editor:
command: "code"
args:
- "."
terminal:
command: "open"
args:
- "-a"
- "Terminal"
- "{path}"
git:
base_branch: "origin/main"
fetch_on_refresh: false
auto_refresh_interval: "30s"
show_remote_status: true
show_merge_status: true
show_dirty_status: true
ui:
show_commit_hash: true
show_branch: trueConfig notes:
git.base_branch: branch or ref used for merge checks, such asorigin/maingit.fetch_on_refresh: iftrue,rrunsgit fetch --prunebefore status refreshgit.auto_refresh_interval: duration such as30sor2m;0sdisables automatic refresh. Auto-refresh runs only on the main list view and uses the same refresh behavior asr.git.show_remote_status: showlocaland↑N/↓Nbadgesgit.show_merge_status: showmerged/not mergedbadgesgit.show_dirty_status: showclean/dirtybadgeskeybindings.open_editor: key used to launch the selected worktree in the editorkeybindings.open_terminal: key used to launch the selected worktree in a new terminaleditor.command: executable used to launch the editor, such ascode,zed, oropeneditor.args: optional args passed before launch; the selected worktree is the command working directory, and{path}expands to its full pathterminal.command: executable used to launch a terminal app, such asopen,wezterm, orwtterminal.args: optional args passed before launch; the selected worktree is the command working directory, and{path}expands to its full path
The default terminal launcher is platform-specific. The example above shows the macOS default.
gopenshttps://<remote-host>/<owner>/<repo>/tree/<branch>using the selected branch's remote URL and your system browserpusesgh pr view <branch> --web, so it requires the GitHub CLI to be installed and able to resolve the branch's pull request
See config.example.yaml for a ready-to-copy example.
Run formatting and tests:
gofmt -w ./cmd ./internal
go test ./...