Skip to content

malkoG/gtr.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 

Repository files navigation

gtr.nvim

Neovim plugin for gtr (git worktree runner). Manage git worktrees from Neovim with a picker UI, commands, and statusline integration.

Requirements

  • Neovim >= 0.10
  • gtr CLI installed and in PATH
  • snacks.nvim (picker backend)

Installation

lazy.nvim

{
  "malkoG/gtr.nvim",
  opts = {},
  keys = {
    { "<leader>gw", function() require("gtr").list() end, desc = "Git Worktrees" },
  },
}

Configuration

require("gtr").setup({
  -- Path to gtr binary (nil = auto-detect from PATH)
  cmd = nil,

  -- Picker backend: "snacks" (telescope/fzf-lua planned)
  picker = "snacks",

  -- How :GtrGo changes directory
  -- "global" = :cd, "tab" = :tcd, "window" = :lcd
  cd_strategy = "tab",

  -- Keymaps inside the picker
  picker_actions = {
    { key = "<CR>",  action = "go" },
    { key = "<C-n>", action = "new" },
    { key = "<C-e>", action = "editor" },
    { key = "<C-d>", action = "rm" },
    { key = "<C-r>", action = "run" },
  },

  -- Statusline
  statusline = {
    icon = "",
    show_status = true,
  },

  -- Output display for :GtrRun, :GtrDoctor
  output_display = "float", -- "float" | "split" | "notify"

  -- Callbacks
  on_worktree_new = nil, -- fun(branch: string, path: string)
  on_worktree_rm = nil,  -- fun(branch: string)
  on_worktree_go = nil,  -- fun(branch: string, path: string)
})

Commands

Command Description
:GtrList Open worktree picker
:GtrNew <branch> [flags] Create a new worktree
:GtrGo <branch> Change cwd to worktree
:GtrRm <branch> [flags] Remove a worktree (with confirmation)
:GtrEditor <branch> Open worktree in external editor
:GtrRun <branch> <cmd...> Run a command inside a worktree
:GtrMv <old> <new> Rename worktree and branch
:GtrCopy <target> Copy configured files to worktree
:GtrClean [flags] Remove stale worktrees
:GtrDoctor Health check

All branch-accepting commands support tab completion.

Picker

The picker (:GtrList or Lua require("gtr").list()) shows all worktrees with:

  • Active worktree marked with *
  • Branch name, status, and path
  • Preview showing git log of commits ahead of the default branch

Picker keymaps

Key Action
<CR> Switch to worktree (change cwd)
<C-n> Create new worktree
<C-e> Open in external editor
<C-d> Remove worktree
<C-r> Run command in worktree

Statusline

lualine.nvim

Add "gtr_worktree" to your lualine config:

require("lualine").setup({
  sections = {
    lualine_b = { "branch", "gtr_worktree", "diff", "diagnostics" },
  },
})

Manual

Use require("gtr.statusline").get() in your custom statusline.

Lua API

local gtr = require("gtr")

gtr.list()                        -- Open picker
gtr.new("feature/foo")            -- Create worktree
gtr.new("feature/foo", {          -- Create with flags
  from = "develop",
  ["no-fetch"] = true,
})
gtr.go("feature/foo")             -- Change cwd to worktree
gtr.rm("feature/foo")             -- Remove worktree
gtr.editor("feature/foo")         -- Open in external editor
gtr.run("feature/foo", {"npm", "test"}) -- Run command
gtr.mv("old-name", "new-name")   -- Rename
gtr.copy("feature/foo")           -- Copy files
gtr.clean()                       -- Clean stale worktrees
gtr.clean({ merged = true })      -- Clean merged worktrees
gtr.doctor()                      -- Health check

Behavior on worktree switch

When switching worktrees via the picker or :GtrGo, all buffers are refreshed:

  • Fugitive/git buffers are wiped. These cache git directory state internally and cannot be reliably refreshed in place. Reopen with :Git after switching.
  • Oil buffers are wiped. Oil caches directory listings tied to the old worktree path. Reopen with :Oil after switching.
  • Regular file buffers are force-reloaded (:edit!) to pick up content from the new worktree.
  • Lualine/statusline is refreshed via BufEnter + fugitive#DidChange().

This ensures a clean slate — no stale git state leaking across worktrees.

Integrations

vim-fugitive

Fugitive is automatically refreshed when switching worktrees. The plugin clears stale b:git_dir on all buffers, calls FugitiveDetect() + fugitive#DidChange(), and fires BufEnter so the statusline branch updates correctly. Gitgutter also picks up the change via FugitiveChanged.

Health check

Run :checkhealth gtr to verify your setup (gtr binary, git, Neovim version, picker backend, git repo detection).

About

Neovim plugin for gtr (git worktree runner). Manage git worktrees from Neovim with a picker UI, commands, and statusline integration.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages