Installation
Requirements
- Git 2.28 or later
- A terminal with UTF-8 support (virtually all modern terminals qualify)
- macOS, Linux, or Windows
One-line install
macOS / Linux
curl -fsSL https://raw.githubusercontent.com/AgusRdz/bonsai/main/install.sh | sh
The script downloads the latest release binary for your platform and places it in ~/.local/bin (or /usr/local/bin if that is writable). It adds the directory to your $PATH if needed.
Windows (PowerShell)
irm https://raw.githubusercontent.com/AgusRdz/bonsai/main/install.ps1 | iex
Manual install
- Download the binary for your platform from the releases page.
- Make it executable:
chmod +x bonsai - Move it somewhere on your
$PATH:mv bonsai ~/.local/bin/
Build from source
Requires Go 1.21 or later.
git clone https://github.com/AgusRdz/bonsai.git
cd bonsai
go build -ldflags="-s -w" -o bonsai .
mv bonsai ~/.local/bin/
Update
bonsai update
Checks GitHub releases and replaces the current binary in-place.
Uninstall
bonsai uninstall
Removes the binary. You can also delete the global config manually:
rm -rf ~/.config/bonsai/
First run
The first time you run bonsai inside a repo it will automatically open the setup wizard if no global config exists. You can also run it explicitly at any time:
bonsai setup
TUI Guide
Opening bonsai
cd your-repo
bonsai
bonsai must be run from inside a Git repository. If no global config exists it opens the setup wizard first.
Layout
main ↑2 [trunk] [mode:standard] ← header
Conflicts (1)
! src/auth.go both modified ← conflict section (shown first)
Staged (2)
M src/api.go ← staged section
A src/middleware.go
Changed (1)
M README.md ← changed section
Untracked (1)
? scratch.txt ← untracked section
$ git commit -m "fix: auth token refresh"
[space] stage/unstage [c] commit ... ← command bar
The header shows your current branch, how many commits you are ahead/behind the remote, the active workflow flow, and the current mode.
The file list is divided into four sections in fixed order: conflicts (if any), staged, changed, untracked. Navigate with ↑/↓ or j/k.
The command bar at the bottom shows the most common keys. Press ? for the full reference.
Navigation
| Key | Action |
|---|---|
↑ / k | Move selection up |
↓ / j | Move selection down |
esc | Close current panel / go back |
q / ctrl+c | Quit |
File operations
| Key | Action |
|---|---|
space | Stage a changed/untracked file; unstage a staged file |
+ | Stage all changes at once (git add .) |
h | Open the hunk stage panel |
d | View diff for the selected file |
H | Open file history |
e | Open blame view |
x | Discard all working tree changes to the selected file (confirm required) |
o | Restore the selected file to HEAD or a specific ref |
Hunk staging
Press h on any changed file to open the hunk panel. Each hunk shows its @@ ... @@ header and a short preview. All hunks are selected by default - deselect the ones you want to leave out, then press enter to apply.
| Key | Action |
|---|---|
↑/↓ | Move between hunks |
space | Toggle selected / deselected |
a | Select all hunks |
enter | Apply selected hunks |
esc | Cancel |
File history
Press H on any file to see every commit that touched it. Press enter on a commit to open its full detail view.
Branch graph
Press g to open the branch graph (git log --graph --all). Use ↑/↓ to scroll, esc to close.
Committing
Press c to open the commit panel. Type your message and press enter to commit. Press esc to cancel.
In guided mode the education panel appears after the commit and explains what happened in plain language along with the exact command that ran.
Pushing and pulling
Press p to open the push menu. Choose between:
| Option | Command | When to use |
|---|---|---|
| Push | git push | Normal push |
| Force with lease | git push --force-with-lease | After a rebase; fails safely if the remote has new commits |
| Set upstream | git push --set-upstream origin <branch> | First push of a new branch |
Press P to pull, f to open the fetch menu (origin / all / prune).
Branches
| Key | Action |
|---|---|
b | Create a new branch (or open the flow picker in gitflow mode) |
B | List all branches - switch, merge, rebase, delete, rename, delete remote |
Log
Press l to open the commit log.
| Key | Action |
|---|---|
↑/↓ | Scroll |
enter | Open commit detail |
/ | Open search / filter input |
ctrl+/ or ctrl+r | Clear active filter |
m | Load more commits |
esc | Back (first esc clears any active filter) |
From commit detail, press d to view the full diff, p to cherry-pick, or y to copy the hash.
Stash
| Key | Action |
|---|---|
s | Stash all current changes (opens a message input to name the stash) |
S | Open stash list - pop, apply, or drop an entry |
Advanced operations
Reset
Press z to open the reset menu. Choose between soft (keep staged), mixed (keep unstaged), or hard (discard all changes).
Tags
Press t to list tags. From the tag list you can create a new tag at HEAD, delete one, or push a tag to origin.
Blame
Select a file and press e to open the blame view. Each line is annotated with the commit hash, author, and date.
Bisect
Press i to open the bisect panel. Mark commits as good or bad to find the commit that introduced a bug.
Interactive rebase
Press R to open the interactive rebase panel. Enter a base ref (e.g. HEAD~5 or a commit hash), then reorder and relabel commits (pick, reword, squash, fixup, drop).
Amend
Press A to open the amend panel. You can change the commit message, author, date, or use --no-edit to amend without changing the message.
Only amend commits that have not been pushed to a shared remote.
Undo
Press U to undo the last commit, merge, or rebase.
Worktrees
Press W to list linked worktrees. You can add a new worktree (checked out to a different branch) or remove an existing one.
Remotes
Press O to open remote management. From there you can list all configured remotes, add a new one, remove, or rename an existing one.
Submodules
Press M to open the submodule panel. You can list all submodules, add a new one, run update --init, or deinit a submodule.
Git notes
Press n to view the note attached to the HEAD commit. You can edit the note inline or delete it.
Reflog
Press L to open the reflog. Scroll through all HEAD movements, copy a hash with y, or reset to an entry with r.
Clean
Press X to preview untracked files that would be removed by git clean -fd. A confirmation is required before anything is deleted.
Conflicts
When merge conflicts exist they appear at the top of the file list marked with !. Select a conflicted file and press d to open the conflict viewer.
| Key | Action |
|---|---|
o | Accept ours (discard their changes) |
t | Accept theirs (discard our changes) |
b | Accept base (common ancestor) |
r | Remove conflict markers, keep both sides |
e | Manual edit mode |
Press a from the main panel to abort an in-progress merge, rebase, or cherry-pick.
Configuration manager
Press C to open the configuration manager:
- Global config - view and edit
~/.gitconfig - Local config - view and edit
.git/config - Global gitignore - view and edit the global ignore file
- Local .gitignore - view and edit the project ignore file
- Recommendations - best-practice settings with one-key apply
- Profiles (includeIf) - manage conditional config includes
Education panel
After every action bonsai briefly shows a feedback panel:
- standard mode: shows the command that ran (e.g.
git commit -m "...") - guided mode: shows the command plus a plain-language explanation and contextual tips
- pro mode: no panel (except for complex operations like rebase or bisect)
Press any key to dismiss the panel immediately. The duration is configurable:
[education]
panel_duration = 4 # seconds; 0 disables it entirely
Usage tracking and mastery
bonsai tracks how many times you run each command. When you reach the mastery threshold for a command, it asks whether you want to keep seeing the education panel for it or suppress it.
| Command | Threshold |
|---|---|
add, commit | 20 uses |
push, pull | 15 uses |
branch, checkout | 12 uses |
stash, merge | 10 uses |
rebase, cherry-pick | 8 uses |
reset, restore | 6 uses |
bisect, worktree, notes | 5 uses |
You can re-enable suppressed panels at any time from the Education & Usage section of the configuration manager (C).
CLI Commands
All commands that do not open the TUI accept no positional arguments other than subcommands. Options use --flag syntax.
bonsai (no args)
Opens the interactive TUI. Runs the setup wizard on first launch.
bonsai
bonsai clone
Clones a remote repository and opens bonsai in the resulting directory.
bonsai clone <url> [<directory>]
# Clone into a directory named after the repo
bonsai clone https://github.com/example/repo.git
# Clone into a custom directory
bonsai clone https://github.com/example/repo.git my-project
bonsai setup
Interactive wizard that walks you through flow, branch prefixes, mode, and validation. Writes to the global config.
bonsai setup
bonsai setup --local # per-project overrides
bonsai init
Creates a commented .bonsai.toml template in the current directory without running the wizard. Does not overwrite an existing file.
bonsai init
bonsai config
Opens the global config in your editor.
bonsai config
bonsai config --local # open per-project config
bonsai config --path # print the path to the global config file
bonsai doctor
Checks global and local Git configuration health. See the Doctor page for details.
bonsai doctor
bonsai doctor --verbose
bonsai stats
Prints repository statistics. Must be run inside a Git repo.
bonsai stats
Output includes commit count, date range, recent activity, branch and tag counts, top contributors, file type breakdown, and most-changed files.
bonsai patch
Wraps git format-patch and git am.
patch –create
bonsai patch --create --base=<ref> [--output=<dir>]
| Flag | Description |
|---|---|
--base=<ref> | Required. Create patches for commits since this ref |
--output=<dir> | Directory to write .patch files into. Defaults to the current directory |
bonsai patch --create --base=HEAD~3
bonsai patch --create --base=main --output=patches/
patch –apply
bonsai patch --apply <file> [<file>...]
bonsai patch --apply patches/0001-fix-auth.patch
bonsai patch --apply patches/*.patch
If conflicts occur, resolve them manually and run git am --continue, or git am --abort to cancel.
bonsai archive
Exports the repository at a given ref as a compressed archive.
bonsai archive [--format=<fmt>] [--output=<file>] [--ref=<ref>]
| Flag | Default | Description |
|---|---|---|
--format | tar.gz | tar.gz or zip |
--output | archive.<format> | Destination file path |
--ref | HEAD | Git ref to archive |
bonsai archive
bonsai archive --format=zip --ref=v1.2.0 --output=release-v1.2.0.zip
bonsai bundle
Wraps git bundle for offline repository transfer.
bonsai bundle --create <file> # bundle all branches
bonsai bundle --verify <file> # verify a bundle file
bonsai bundle --create repo.bundle
bonsai bundle --verify repo.bundle
bonsai ssh
Manage SSH keys and check connectivity.
bonsai ssh --status # SSH key, agent status, connectivity to the repo's remote
bonsai ssh --keygen # generate ~/.ssh/id_ed25519
bonsai ssh --show # print your public key
bonsai ssh --status detects the remote host from the current repo’s remotes and tests SSH auth against it. Works with GitHub, GitLab, Bitbucket, Gitea/Forgejo, and Azure DevOps.
Press ` inside the TUI to open the SSH key manager panel.
bonsai lfs
Manage Git LFS tracked files and objects.
bonsai lfs --status # show pending LFS objects
bonsai lfs --track <pattern> # track a file pattern (e.g. *.psd, *.zip)
bonsai lfs --untrack <pattern> # stop tracking a pattern
bonsai lfs --pull # download all LFS objects for the current checkout
bonsai lfs --install # install LFS hooks into this repository
bonsai standup
Shows your recent commits, defaulting to today.
bonsai standup
bonsai standup --days 3
bonsai standup -w # last 7 days
bonsai standup -a "Jane Doe" # filter by author name
| Flag | Description |
|---|---|
--days N | Show commits from the last N days (default: 1) |
-w | Shorthand for --days 7 |
-a <name> | Filter by author name (defaults to user.name from git config) |
bonsai repo
Create and open remote repositories.
bonsai repo --create <name> [--private] # create a new remote repo (GitHub / GitLab)
bonsai repo --open # open the current repo in the browser
bonsai repo --create my-new-repo
bonsai repo --create my-new-repo --private
bonsai repo --open
bonsai update
Updates bonsai to the latest release by downloading the new binary in-place.
bonsai update
bonsai uninstall
Removes the bonsai binary from the system. Prompts for confirmation.
bonsai uninstall
bonsai changelog
Prints the full changelog to stdout.
bonsai changelog
bonsai changelog | less
bonsai version
Prints the current version.
bonsai version
# bonsai v0.29.0
Keybindings
Open bonsai and press ? for the full in-app reference. Key highlights by panel:
Main panel
File navigation
| Key | Action |
|---|---|
↑ / k | Move selection up |
↓ / j | Move selection down |
File operations
| Key | Action |
|---|---|
space | Stage an unstaged file / unstage a staged file |
+ | Stage all changes at once (git add .) |
h | Stage / unstage individual hunks within a file |
H | View commit history for the selected file |
d | View diff for the selected file |
e | Blame - who last changed each line |
x | Discard working tree changes (confirm required) |
o | Restore file to HEAD or a specific ref |
Sync
| Key | Action |
|---|---|
c | Open commit panel |
p | Open push menu (push / force-with-lease / set-upstream) |
P | Pull from remote |
f | Fetch menu |
g | Open branch graph (git log --graph --all) |
Stash
| Key | Action |
|---|---|
s | Stash all changes (opens message input) |
S | Open stash list |
Branches
| Key | Action |
|---|---|
b | Create a new branch (or flow picker in gitflow mode) |
B | List all branches |
History
| Key | Action |
|---|---|
l | Open commit log |
L | Open reflog |
Advanced operations
| Key | Action |
|---|---|
z | Reset menu (soft / mixed / hard) |
t | Tag list |
i | Bisect panel |
R | Interactive rebase |
A | Amend HEAD |
U | Undo last commit / merge / rebase |
W | Worktree list |
O | Remote management |
M | Submodule management |
n | Notes for HEAD commit |
X | Clean untracked files |
a | Abort in-progress merge / rebase / cherry-pick |
Configuration and tools
| Key | Action |
|---|---|
C | Configuration manager |
` | SSH key manager |
V | LFS panel |
D | Multi-repo dashboard |
Meta
| Key | Action |
|---|---|
? | Help panel |
q / ctrl+c | Quit |
Log panel
| Key | Action |
|---|---|
↑ / k | Scroll up |
↓ / j | Scroll down |
enter | Open commit detail |
/ | Open search / filter input |
ctrl+/ or ctrl+r | Clear active filter |
m | Load more commits |
esc | Back (first esc clears any active filter) |
Commit detail panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
d | View full diff of this commit |
y | Copy commit hash to clipboard |
p | Cherry-pick onto current branch |
esc | Back |
File history panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
enter | View commit detail |
esc | Back |
Branch graph panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
esc | Back |
Branch list panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
enter | Switch to the selected branch |
m | Merge selected branch into current (confirm required) |
r | Rebase current onto selected branch (confirm required) |
d | Delete the selected branch (confirm required) |
n | Rename the selected branch |
D | Delete the remote tracking branch (confirm required) |
esc | Back |
Stash list panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
enter | Pop the selected stash |
a | Apply without removing |
d | Drop the selected stash |
esc | Back |
Conflict panel
| Key | Action |
|---|---|
↑ / ↓ | Move between conflict hunks |
o | Accept ours |
t | Accept theirs |
b | Accept base (common ancestor) |
r | Remove conflict markers (keep both sides) |
e | Manual edit mode |
esc | Back |
PR / MR panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
enter | Open PR in browser |
d | View full diff |
a | Approve |
A | Request changes (with reason) |
c | Post a general comment |
n | Create a new PR for the current branch |
esc | Back |
Tag list panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
n | Create a new tag at HEAD |
d | Delete the selected tag |
p | Push the selected tag to origin (confirm required) |
esc | Back |
Worktree list panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
a | Add a new worktree |
d | Remove the selected worktree |
esc | Back |
Remote list panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
a | Add a new remote |
d | Remove the selected remote |
r | Rename the selected remote |
esc | Back |
Submodule list panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
a | Add a new submodule |
u | Update –init all submodules |
d | Deinit the selected submodule |
esc | Back |
Reflog panel
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
r | Reset HEAD to the selected entry |
y | Copy hash to clipboard |
esc | Back |
Interactive rebase panel
Step 1: enter a base ref (e.g. HEAD~3) and press enter to load commits.
Step 2: edit the todo list, then press enter to execute.
| Key | Action |
|---|---|
↑ / k | Move cursor up |
↓ / j | Move cursor down |
K | Move selected commit up (reorder) |
J | Move selected commit down (reorder) |
p | pick |
r | reword |
e | edit |
s | squash |
f | fixup |
d | drop |
enter | Execute rebase |
esc | Cancel |
Hunk stage panel
| Key | Action |
|---|---|
↑ / ↓ | Move selection |
space | Toggle hunk selected / deselected |
a | Select all / deselect all |
enter | Apply selected hunks |
esc | Back |
Push menu
| Key | Action |
|---|---|
↑ / ↓ | Move selection |
enter | Execute selected push option |
esc | Back |
SSH panel (`)
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
t | Test SSH connection for selected key |
esc | Back |
LFS panel (V)
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
t | Track a new file pattern |
u | Untrack selected pattern |
p | Pull LFS objects |
P | Push LFS objects |
esc | Back |
Multi-repo dashboard (D)
| Key | Action |
|---|---|
↑ / ↓ | Scroll |
enter | Open selected repo in bonsai |
esc | Back |
Bisect panel
| Key | Action |
|---|---|
s | Start bisect |
b | Mark current as bad |
g | Mark current as good |
r | Reset bisect |
esc | Back |
Diff panel
| Key | Action |
|---|---|
↑ / k | Scroll up |
↓ / j | Scroll down |
e | Blame for the file being diffed |
esc | Back |
Remappable keys
The following keys can be changed in [keybindings] in your config:
| Default | Config key |
|---|---|
c | commit |
p | push |
l | pull |
s | stash |
z | undo |
q | quit |
b | branch |
g | graph |
All other keys are fixed.
[keybindings]
graph = "g"
commit = "c"
branch = "b"
push = "p"
pull = "l"
stash = "s"
undo = "z"
quit = "q"
Configuration
Config file locations
| Scope | Path |
|---|---|
| Global | ~/.config/bonsai/config.toml |
| Per-project | .bonsai.toml in the repo root |
The per-project file inherits every value from global and overrides only what it defines. On Windows the global config is at %APPDATA%\bonsai\config.toml.
Quick setup
bonsai setup # global wizard
bonsai setup --local # per-project wizard (inside a repo)
To create a commented template without the wizard:
bonsai init # creates .bonsai.toml in the current directory
To open the config in your editor:
bonsai config # global
bonsai config --local # per-project
bonsai config --path # print the path to the global file
Full config reference
[modes]
default = "standard" # standard | guided | pro
[flow]
type = "auto" # auto | trunk | gitflow | githubflow | forking
[conventions.branches.feature]
prefix = "feat/"
pattern = "feat/{ticket-id}-{description}"
example = "feat/PROJ-123-login-oauth"
[conventions.branches.bugfix]
prefix = "fix/"
pattern = "fix/{ticket-id}-{description}"
example = "fix/PROJ-456-crash-on-login"
[conventions.branches.release]
prefix = "release/"
[conventions.branches.hotfix]
prefix = "hotfix/"
[conventions.validation]
mode = "strict" # strict | warn | off
[education]
panel_duration = 4 # seconds; 0 disables the feedback panel
[editor]
command = "" # e.g. "vim", "nano", "code --wait", "hx"
[keybindings]
graph = "g"
commit = "c"
branch = "b"
push = "p"
pull = "l"
stash = "s"
undo = "z"
quit = "q"
[metrics]
enabled = false
[metrics.track]
errors = true
conventions = true
commits = false
habits = false
Modes
| Mode | Behavior |
|---|---|
standard | Shows the command that ran after each action - default |
guided | Full explanation after every action, contextual tips |
pro | No feedback panel - clean interface |
Per-project example
A minimal .bonsai.toml that switches to guided mode and enforces stricter branch names:
[modes]
default = "guided"
[conventions.branches.feature]
prefix = "feature/"
example = "feature/auth-oauth"
[conventions.branches.bugfix]
prefix = "bugfix/"
[conventions.validation]
mode = "strict"
Mode migration
If you have an older config with deprecated mode names, bonsai migrates them automatically on load:
| Old name | New name |
|---|---|
novice | guided |
learning | standard |
Keybinding remapping
Only eight keys are remappable. All other keys (l, B, d, x, o, f, t, W, O, M, n, L, X, C, R, A, i, e, ?, a) are fixed.
Example - swap push and pull:
[keybindings]
push = "l"
pull = "p"
Flows and Conventions
Workflow flows
A “flow” tells bonsai how your team organises branches and where pull requests land. It affects the branch creation picker and the contextual hints shown after each action.
| Flow | Description |
|---|---|
auto | Detected from your branch conventions (default) |
trunk | Short-lived branches merged frequently into main |
gitflow | feature / bugfix / release / hotfix; PRs target develop |
githubflow | Feature branches with PRs directly into main |
forking | Fork-based contribution model |
[flow]
type = "auto" # auto | trunk | gitflow | githubflow | forking
auto (default)
bonsai inspects your [conventions.branches] config and infers the flow:
- If all four gitflow types are present (feature, bugfix, release, hotfix) - gitflow
- Otherwise - trunk
Use auto if you want bonsai to adapt without manual configuration.
trunk
Short-lived topic branches that merge directly into main. The branch picker shows a simple name input.
[flow]
type = "trunk"
[conventions.branches.feature]
prefix = "feat/"
[conventions.branches.bugfix]
prefix = "fix/"
gitflow
Feature branches off develop; releases and hotfixes have their own prefixes. The branch picker shows four options:
1) feature feat/PROJ-123-description
2) bugfix fix/PROJ-456-description
3) release release/1.2.0
4) hotfix hotfix/critical-fix
[flow]
type = "gitflow"
[conventions.branches.feature]
prefix = "feat/"
pattern = "feat/{ticket-id}-{description}"
example = "feat/PROJ-123-login-oauth"
[conventions.branches.bugfix]
prefix = "fix/"
example = "fix/PROJ-456-crash-on-login"
[conventions.branches.release]
prefix = "release/"
[conventions.branches.hotfix]
prefix = "hotfix/"
githubflow
Feature branches with PRs into main. Simpler than gitflow - only two branch types:
[flow]
type = "githubflow"
[conventions.branches.feature]
prefix = "feat/"
[conventions.branches.bugfix]
prefix = "fix/"
forking
Same branch structure as githubflow but the hints remind you to push to your fork and open a PR upstream.
Branch conventions
Conventions let you enforce a consistent naming scheme across your team.
[conventions.branches.feature]
prefix = "feat/"
pattern = "feat/{ticket-id}-{description}"
example = "feat/PROJ-123-login-oauth"
| Field | Required | Description |
|---|---|---|
prefix | yes | Branch names must start with this string |
pattern | no | Human-readable template shown in the convention panel |
example | no | Concrete example shown as a hint |
Validation modes
[conventions.validation]
mode = "strict" # strict | warn | off
| Mode | Behavior |
|---|---|
strict | Blocks actions that would result in a non-conforming branch name |
warn | Shows a warning in the main panel header but does not block |
off | No validation at all |
Custom branch types
You can define as many types as you need:
[conventions.branches.chore]
prefix = "chore/"
example = "chore/update-dependencies"
[conventions.branches.docs]
prefix = "docs/"
example = "docs/api-reference"
Protected branch names
The following branch names are always allowed regardless of conventions: main, master, develop, HEAD, and any branch whose name matches a configured prefix exactly.
Per-project conventions
Add a .bonsai.toml to override conventions for a specific repo without changing your global defaults:
# .bonsai.toml
[conventions.branches.feature]
prefix = "feature/"
example = "feature/auth-oauth"
[conventions.validation]
mode = "warn"
Interactive setup
Run the wizard to configure conventions interactively:
bonsai setup # global
bonsai setup --local # this repo only
Doctor
bonsai doctor audits your Git configuration and reports findings as a structured health check. It covers both the global ~/.gitconfig and the local repo config.
Usage
bonsai doctor # standard output
bonsai doctor --verbose # adds a one-line explanation per check
Output format
Global
✓ git version 2.50.1
✓ user.name Jane Doe
✓ user.email jane@example.com
⚠ credential.helper not set
fix: run: git config --global credential.helper osxkeychain
⚠ init.defaultBranch set to "master" (recommended: main)
fix: run: git config --global init.defaultBranch main
✓ pull.rebase true
✓ ssh key /Users/jane/.ssh/id_ed25519
✓ ssh-agent running (2 key(s) loaded)
✓ ssh github.com Hi jane! You've successfully authenticated...
Local (my-project)
✓ remote origin git@github.com:org/my-project.git
✓ upstream tracking origin/main
✓ .gitignore present
Summary: 0 errors, 2 warnings, 17 passed
Exit code is 1 if any check has level error (✗), 0 otherwise.
Global checks
| Check | What it looks for |
|---|---|
git version | Git 2.28 or later |
user.name | Must be set; used on every commit |
user.email | Must be set and look like an email address |
credential.helper | Prevents re-entering passwords on every push |
init.defaultBranch | Should be main to match GitHub/GitLab defaults |
pull.rebase | true keeps history linear by rebasing instead of merging on pull |
fetch.prune | true auto-removes stale remote-tracking refs |
push.autoSetupRemote | true eliminates the need for -u origin <branch> on first push |
rerere.enabled | true memorises conflict resolutions so git can replay them |
core.editor | Checks $VISUAL, $EDITOR, and core.editor |
global gitignore | Checks core.excludesfile and standard locations |
gpg signing | If commit.gpgsign=true, verifies user.signingkey is set |
ssh key | Looks for an SSH key in ~/.ssh |
ssh-agent | Checks SSH_AUTH_SOCK is set and at least one key is loaded |
ssh <host> | Tests SSH connectivity against the repo’s remote host |
Local checks
| Check | What it looks for |
|---|---|
remote origin | An origin remote must be configured |
upstream tracking | Current branch must track a remote branch |
.gitignore | A project-level .gitignore must exist |
merge/rebase state | No interrupted merge, cherry-pick, or rebase |
uncommitted changes | Reports how many files have uncommitted changes |
stale remote branches | Detects refs that would be pruned by git remote prune origin |
branch conventions | If .bonsai.toml is present, checks current branch name |
repo size | Warns if the pack size exceeds 100 MB |
Verbose mode
Adds a dimmed explanation line under each check:
⚠ pull.rebase not set
'git pull' merges by default, which creates noisy merge commits on every
sync. With pull.rebase=true it rebases instead, keeping history linear.
fix: run: git config --global pull.rebase true
Fixing issues
Each warning and error includes a fix: line with the exact command to run. You can copy and run it directly, or apply global settings from the Configuration manager inside the TUI (C key → Recommendations).
Advanced Git
All advanced operations are accessible from the main TUI panel. This page explains what each one does, how to reach it, and what to expect.
Hunk staging (h)
Stage or unstage individual hunks within a file instead of the whole file.
- Navigate to a changed or staged file in the main panel.
- Press
hto open the hunk panel. - Each hunk shows its
@@ ... @@header and a short preview of the changed lines.
| Key | Action |
|---|---|
↑/↓ | Move selection |
space | Toggle the selected hunk on/off |
a | Select all / deselect all |
enter | Apply selected hunks (stage or unstage) |
esc | Cancel |
All hunks are selected by default. Deselect the ones you want to leave out, then press enter.
Staging hunks uses git apply --cached. Unstaging reverses the patch with git apply --cached --reverse.
Untracked files cannot be partially staged - press
spaceto stage the full file first.
Push menu (p)
Opens a menu instead of pushing immediately, so you can choose the push mode.
| Option | Git command | When to use |
|---|---|---|
| Push | git push | Normal push to the tracking remote |
| Force with lease | git push --force-with-lease | Force-push after a rebase; fails if the remote has commits you have not fetched |
| Set upstream | git push --set-upstream origin <branch> | First push of a new branch |
Navigate with ↑/↓ and press enter to execute.
Reset (z)
Opens a menu with three reset modes. Resets apply to the current HEAD.
| Option | Git command | Effect |
|---|---|---|
| soft | git reset --soft HEAD~1 | Undoes the last commit; changes remain staged |
| mixed | git reset --mixed HEAD~1 | Undoes the last commit; changes remain unstaged |
| hard | git reset --hard HEAD~1 | Undoes the last commit and discards all changes |
Hard reset is destructive and requires confirmation.
Merge
Available from the log panel (l - select a commit - m). Merges the selected commit into the current branch.
If the merge produces conflicts they appear in the Conflicts section at the top of the main panel. Use the conflict panel (d on a conflicted file) to resolve them.
Cherry-pick
Also available from the log panel. Select a commit and press p to cherry-pick it onto the current branch.
Tags (t)
The tag list panel shows all local tags.
| Key | Action |
|---|---|
n | Create a new lightweight tag at HEAD |
d | Delete the selected tag |
p | Push the selected tag to origin (confirm required) |
esc | Back |
Interactive rebase (R)
- Press
Rfrom the main panel. - Enter a base ref - the rebase will include all commits between that ref and HEAD. Examples:
HEAD~5,main, a specific hash. - The commit list appears. Each commit shows its action, hash, and message.
| Key | Action |
|---|---|
↑/↓ | Move selection |
K / J | Reorder commits up / down |
enter | Cycle action (pick - reword - squash - fixup - drop) |
r | Start the rebase |
esc | Cancel |
| Action | Description |
|---|---|
pick | Keep the commit as-is |
reword | Keep the commit but edit the message |
squash | Merge into the previous commit, edit combined message |
fixup | Merge into the previous commit, discard this message |
drop | Remove the commit entirely |
Amend (A)
Opens the amend panel for HEAD.
| Option | Description |
|---|---|
| message | Change the commit message |
| author | Change the author name and email |
| date | Change the commit date |
| –no-edit | Amend without changing the message (absorbs staged changes) |
Only amend commits that have not been pushed to a shared remote.
Blame (e)
Select a file from the main panel and press e to open the blame view.
Each line shows the abbreviated hash, author, date, and source line. Scroll with ↑/↓. Press esc to close.
Bisect (i)
Binary search for the commit that introduced a bug.
- Press
ito open the bisect panel. - Press
sto start. - Mark the current state as
b(bad) org(good). - Git checks out the midpoint commit. Test it and mark again.
- Repeat until bisect identifies the culprit.
- Press
rto reset and return to the original branch.
Worktrees (W)
Linked worktrees let you check out a different branch in a separate directory without disturbing your current work.
| Key | Action |
|---|---|
a | Add a new worktree (enter path and branch name) |
d | Remove the selected worktree |
esc | Back |
Example: check out a hotfix while keeping your feature branch work intact:
~
├── my-project/ ← main worktree (feat/login branch)
└── my-project-hotfix/ ← linked worktree (hotfix/critical-fix branch)
Remotes (O)
| Key | Action |
|---|---|
a | Add a new remote (enter name and URL) |
d | Remove the selected remote |
r | Rename the selected remote |
esc | Back |
Submodules (M)
| Key | Action |
|---|---|
a | Add a submodule (enter URL and optional local path) |
u | Run git submodule update --init on all submodules |
d | Deinit the selected submodule |
esc | Back |
Status icons:
| Icon | Meaning |
|---|---|
(space) | Clean, matches parent recorded hash |
M | Checked out commit differs from the recorded hash |
? | Not initialised |
! | Merge conflict |
Restore (o)
Select a file and press o to restore it to a specific state.
Enter a ref in the input (defaults to HEAD). Valid values:
HEAD- discard all changes and return to the last commitHEAD~2- restore to two commits agoabc1234- restore to a specific commit hashmain- restore to the tip of another branch
The restore appears as a modification in your working tree; you still need to stage and commit it if you want to keep it.
Reflog (L)
Shows all recent HEAD movements - commits, checkouts, resets, merges, rebases.
| Key | Action |
|---|---|
↑/↓ | Scroll |
r | Reset HEAD to the selected entry (mixed reset, confirm required) |
y | Copy the hash to clipboard |
esc | Back |
Use the reflog to recover commits that appear to be lost after a hard reset or accidental branch deletion.
Notes (n)
Git notes attach metadata to a commit without changing the commit itself.
| Key | Action |
|---|---|
e | Edit the note (opens inline input) |
d | Delete the note (confirm required) |
esc | Back |
Notes are stored in refs/notes/commits and are not transferred on push/pull by default. To share notes:
git push origin refs/notes/*
git fetch origin refs/notes/*:refs/notes/*
Clean (X)
Shows a preview of all untracked files and directories that would be removed by git clean -fd. Requires confirmation before deleting anything.
This is a destructive operation. Untracked files are not in Git history and cannot be recovered once removed.
Conflict resolution
When a merge, cherry-pick, or rebase produces conflicts:
- The conflicts appear at the top of the main panel.
- Select a conflicted file and press
dto open the conflict viewer.
| Key | Action |
|---|---|
o | Accept ours - keep our version, discard theirs |
t | Accept theirs - keep their version, discard ours |
b | Accept base (common ancestor) |
r | Remove markers - keep both sides concatenated |
e | Manual edit mode - type a custom resolution |
After resolving all conflicts, stage the files and commit.
Press a from the main panel to abort an in-progress operation entirely.
File history (H)
Shows the commit history for a single file - every commit that touched it.
- Select any tracked file in the main panel.
- Press
Hto open the file history panel. - Each line shows the hash, date, author, and subject of the commit.
- Press
enteron a commit to open the commit detail panel. - From the commit detail panel press
dto see the full diff, orescto return.
Branch graph (g)
Opens a full git log --graph --all --oneline --decorate view showing the commit and branch topology of the whole repository.
Scroll with ↑/↓ and press esc to close.
Branch operations (from branch list B)
| Key | Action |
|---|---|
enter | Switch to selected branch |
m | Merge selected branch into current |
r | Rebase current onto selected branch |
d | Delete selected local branch |
n | Rename selected branch |
D | Delete the remote tracking branch for the selected branch |
d uses git branch -d (safe delete - fails on unmerged work). Both require confirmation.
Stash operations (from stash list S)
| Key | Action |
|---|---|
enter | Pop the selected stash (git stash pop) |
a | Apply without removing (git stash apply) |
d | Drop the selected stash (git stash drop) |
Use a when you want to apply a stash to multiple branches. Both d and enter require confirmation.
Configuration manager (C)
The configuration manager panel gives you a read/edit view of all config files without leaving bonsai.
| Section | File |
|---|---|
| Global config | ~/.gitconfig |
| Local config | .git/config |
| Global gitignore | ~/.config/git/ignore or core.excludesfile |
| Local .gitignore | .gitignore |
| Recommendations | Best-practice settings with one-key apply |
| Profiles (includeIf) | Conditional config includes |
Press enter on a section to view it. Press e to open it in your configured editor. In the Recommendations section press enter to apply a setting directly.