Work in progress. Currently vibecoded (AI-assisted), being extended manually and robustly over time.
Worktree lifecycle manager for bare git repos in Neovim.
Git bare repos with worktrees are a powerful workflow: one .bare directory holds the repo, and sibling directories are lightweight worktrees — each on its own branch, fully independent. You can have main/, feature-x/, and hotfix-y/ all checked out simultaneously with zero stashing or context-switching.
But the tooling hasn't caught up. Editors don't know about bare repo structure. You can't open lazygit from the bare root for a specific worktree. Creating and tearing down worktrees means juggling git worktree add, git fetch, branch tracking, buffer cleanup, and directory removal — all manually.
tree-bear treats the bare repo as a first-class workspace:
- Create worktrees that properly track upstream branches (no more detached HEADs)
- Navigate between worktrees with a picker and open tools scoped to each one
- Clean up finished worktrees with a guided pipeline that audits buffers, removes the git reference, and handles directory deletion (including Windows file-lock fallbacks)
- Source project config (
.nvim.lua) from the bare repo root into any worktree session
The pattern is simple: your bare repo root is the forest, worktrees are trees, and tree-bear manages the lifecycle.
tree-bear.nvim/
├── lua/tree-bear/
│ ├── core.lua -- portable backend: zero vim.* deps, pure Lua
│ └── init.lua -- Neovim frontend: pickers, notifications, buffer mgmt
core.lua is intentionally free of any Neovim dependency. It takes plain Lua tables in and returns plain Lua tables out — path utilities, branch parsing, worktree list parsing, buffer categorization, deletion planning, and stump serialization. This module can be consumed by any Lua host.
init.lua is the Neovim frontend. It gathers environment data via vim.* APIs and delegates all logic to core.lua.
The core logic will be extracted into a standalone Go binary (treebear) that provides worktree lifecycle management for any editor or CLI workflow. Pre-built binaries (.exe for Windows, ELF for Linux) will be published as GitHub releases. Go will only be needed to build from source.
When the binary ships:
core.luawill be replaced by RPC/CLI calls totreebear- The Neovim frontend will remain Lua, calling the binary instead of shelling out to
git - A
buildhook will be added to the lazy.nvim spec for source builds - Other editors (VS Code, etc.) can integrate via the same binary
Until then, the plugin is pure Lua with a git dependency.
- Neovim >= 0.10
- git on
$PATH - lazygit on
$PATH - fzf-lua
- snacks.nvim (lazygit integration + dashboard)
{
"jack-work/tree-bear.nvim",
dependencies = {
"folke/snacks.nvim",
"ibhagwan/fzf-lua",
},
event = "VeryLazy",
config = function()
require("tree-bear").setup()
end,
keys = {
{ "<leader>gw", function() require("tree-bear").lazygit_worktree() end, desc = "Lazygit (worktree picker)" },
{ "<leader>gWt", function() require("tree-bear").track_worktree() end, desc = "Worktree: track remote branch" },
{ "<leader>gWn", function() require("tree-bear").new_worktree() end, desc = "Worktree: new branch from remote" },
{ "<leader>gWc", function() require("tree-bear").cleanup_worktree() end, desc = "Worktree: cleanup" },
},
}| Key | Description |
|---|---|
<leader>gw |
Pick a worktree via fzf and open lazygit in it |
<leader>gWt |
Create a worktree tracking a remote branch |
<leader>gWn |
Create a worktree with a new branch from a remote base |
<leader>gWc |
Guided cleanup: audit buffers, spare what you need, tear down the rest |
<leader>gWc walks you through tearing down a finished worktree:
- Audit — categorizes all buffers (clean, dirty, terminal, plugin/other)
- Triage — delete all / choose by category / browse everything
- Spare — multi-select individual buffers to keep
- Confirm — final stats before execution
- Execute — moves CWD to bare root, deletes buffers, unregisters worktree, prompts to delete directory
- Stumps — failed directory deletions (Windows file locks, etc.) are recorded in
.tree-bear-stumps.jsonfor later cleanup
When CWD is inside a worktree of a bare repo, tree-bear sources <bare-root>/.nvim.lua via vim.secure.read(). This runs on startup and on DirChanged. Use :TreeBearSource to force re-source.
This solves the problem that Neovim's built-in exrc only looks in CWD, but your project config lives at the bare repo root — a sibling directory, not a parent.
MIT