GitWorktree.org logoGitWorktree.org

Git Worktree in Neovim

Neovim is a natural fit for git worktree workflows. Terminal-native editors make it easy to jump between worktree directories, and the Neovim plugin ecosystem includes purpose-built tools for worktree management. This guide covers the most popular plugins, configuration with lazy.nvim, and keyboard mappings that make worktree switching seamless.

Popular Plugins

git-worktree.nvim (ThePrimeagen)

The most widely used Neovim worktree plugin, created by ThePrimeagen. It wraps git worktree commands and provides hooks that run when you switch worktrees — useful for automatically changing directories, reloading LSP servers, and refreshing file trees.

Key features:

  • Create, switch, and delete worktrees from within Neovim
  • Hooks for pre/post switch actions (restart LSP, update statusline)
  • Telescope picker for fuzzy-finding worktrees
  • Automatic directory change on worktree switch

Telescope Integration

git-worktree.nvim integrates with Telescope to provide a fuzzy picker for your worktrees. You can search by branch name or path, preview the worktree, and switch with a single keypress. This is the fastest way to navigate between worktrees when you have several active at once.

Setup with lazy.nvim

Here is a complete configuration for git-worktree.nvim using lazy.nvim as the plugin manager:

lazy.nvim configuration
-- In your lazy.nvim plugin spec (e.g., lua/plugins/git-worktree.lua)
return {
  "ThePrimeagen/git-worktree.nvim",
  dependencies = {
    "nvim-telescope/telescope.nvim",
    "nvim-lua/plenary.nvim",
  },
  config = function()
    local worktree = require("git-worktree")

    worktree.setup({
      -- Change directory command (default: "cd")
      change_directory_command = "cd",
      -- Update on switch (refresh buffers, etc.)
      update_on_change = true,
      -- Update on change notification
      update_on_change_command = "e .",
      -- Clear jumps on switch
      clearjumps_on_change = true,
      -- Autopush on create (push new branch to remote)
      autopush = false,
    })

    -- Load the Telescope extension
    require("telescope").load_extension("git_worktree")

    -- Hook: run after switching worktrees
    worktree.on_tree_change(function(op, metadata)
      if op == worktree.Operations.Switch then
        print("Switched to worktree: " .. metadata.path)
      end
    end)
  end,
}

Key Mappings

Add these keymaps to your Neovim configuration to quickly access worktree commands:

Recommended keymaps
-- Keymaps for git-worktree.nvim
local keymap = vim.keymap.set

-- Switch worktrees (Telescope picker)
keymap("n", "<leader>wt", function()
  require("telescope").extensions.git_worktree.git_worktrees()
end, { desc = "Switch git worktree" })

-- Create a new worktree (Telescope prompt)
keymap("n", "<leader>wn", function()
  require("telescope").extensions.git_worktree.create_git_worktree()
end, { desc = "Create git worktree" })

-- Quick switch to a specific worktree by path
keymap("n", "<leader>ws", function()
  local path = vim.fn.input("Worktree path: ")
  if path ~= "" then
    require("git-worktree").switch_worktree(path)
  end
end, { desc = "Switch to worktree by path" })

With these mappings, pressing <leader>wt opens a Telescope picker showing all active worktrees. Select one to switch your entire Neovim session to that worktree directory.

Workflow: Switching Between Worktrees

A typical Neovim worktree workflow looks like this:

Complete worktree workflow
# 1. Create worktrees from the terminal (or from Neovim)
git worktree add ../feature-api feature/api
git worktree add ../bugfix-login fix/login-error

# 2. Open Neovim in your main worktree
nvim .

# 3. Inside Neovim, press <leader>wt to see all worktrees
#    Select "feature-api" to switch

# 4. Neovim changes directory to ../feature-api
#    All buffers refresh, LSP restarts, file tree updates

# 5. Press <leader>wt again to switch back to main

The key advantage over terminal-based switching is that Neovim handles the directory change, buffer refresh, and LSP restart in one action. You stay in the same Neovim process the entire time.

Integration with Fugitive & Gitsigns

vim-fugitive

Fugitive works correctly inside linked worktrees. Commands like :Git status, :Git diff, and :Git log all operate on the correct worktree. Fugitive detects the .git file (not directory) that linked worktrees use and follows it back to the main repository's object store.

gitsigns.nvim

Gitsigns provides inline diff markers in the sign column. It works out of the box with worktrees — when you switch worktrees using git-worktree.nvim, gitsigns automatically updates to show the correct diff state for the new branch. No additional configuration is needed.

Handling LSP Restarts

When switching worktrees, the LSP server may need to be restarted to pick up the new project root. You can automate this with a worktree hook:

Auto-restart LSP on worktree switch
-- Restart LSP when switching worktrees
local worktree = require("git-worktree")

worktree.on_tree_change(function(op, metadata)
  if op == worktree.Operations.Switch then
    -- Stop all LSP clients
    vim.lsp.stop_client(vim.lsp.get_active_clients())
    -- Restart after a short delay
    vim.defer_fn(function()
      vim.cmd("edit")  -- Re-trigger LSP attach
    end, 100)
  end
end)