From 1c98ac6793c1bbce82296375e34859e29f3332af Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:14:42 -0400 Subject: [PATCH 1/5] feat: add on_before_switch hook Signed-off-by: x1unix <9203548+x1unix@users.noreply.github.com> --- README.md | 32 +++++++++++++++++++++++++++++++- lua/worktrees/init.lua | 16 +++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 19555eb..6b4cc14 100644 --- a/README.md +++ b/README.md @@ -120,12 +120,16 @@ or with lua ## Hooks You can provide hooks to perform additional actions on worktree addition, removal and switching + ```lua require('worktrees').setup { hooks = { on_add = function(name, path, branch) -- your action here end, + on_before_switch = function(from, to, git_path_info) + -- your action here + end, on_switch = function(from, to, git_path_info) -- your action here end, @@ -170,6 +174,32 @@ require('worktrees').setup { } ``` + +### Example - save worktree session before switch + +```lua +require('worktrees').setup { + swap_current_buffer = false, + hooks = { + on_before_switch = function(from, to, git_path_info) + -- Persist worktree session before worktree switch. + require('mini.session').write(nil, { force = true, verbose = false }) + vim.cmd('silent! %bwipeout!') + + -- Out of the box, worktrees.nvim changes a working directory on worktree switch. + -- Optionally, you may prevent this by returning "false". + -- return false + end, + on_switch = function(from, to, git_path_info) + -- Restore session after worktree changes. + if vim.fn.filereadable('Session.vim') then + require('mini.session').read(nil, { force = true, verbose = false }) + end + end, + } +} +``` + ## Telescope The extension can be loaded with telescope @@ -226,4 +256,4 @@ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" ## TODO -- [ ] Options to customize behavior +- [ ] Options to customize behavior diff --git a/lua/worktrees/init.lua b/lua/worktrees/init.lua index 99f09f6..2e97e73 100644 --- a/lua/worktrees/init.lua +++ b/lua/worktrees/init.lua @@ -3,6 +3,7 @@ local utils = require("worktrees.utils") local status = require("worktrees.status") ---@class worktrees.Hooks +---@field on_before_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo): boolean | nil ---@field on_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo) ---@field on_add fun(name: string, path: string, branch: string) ---@field on_remove fun(name: string) @@ -162,6 +163,20 @@ M.switch_worktree = function(path) end vim.schedule(function() + local prev_path = vim.loop.cwd() --[[@as string]] + + if M._options.hooks.on_before_switch then + -- on_before_switch can intercept worktree switch logic if returns 'false'. + local continue = M._options.hooks.on_before_switch( + prev_path, + found_path, + before_git_path_info + ) + if continue ~= nil and not continue then + return + end + end + -- Clear jumplist so that no file in the old worktree is present -- in the jumplist for accidental switching of worktrees vim.cmd("clearjumps") @@ -177,7 +192,6 @@ M.switch_worktree = function(path) -- Change neovim cwd if M._options.hooks.on_switch then - local prev_path = vim.loop.cwd() --[[@as string]] vim.cmd("cd " .. found_path) M._options.hooks.on_switch( prev_path, From 3f89784944c67500bd1c622f31ed5219851a561c Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:30:44 -0400 Subject: [PATCH 2/5] chore: update example Signed-off-by: x1unix <9203548+x1unix@users.noreply.github.com> --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 6b4cc14..5a9b60f 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,9 @@ require('worktrees').setup { require('mini.session').write(nil, { force = true, verbose = false }) vim.cmd('silent! %bwipeout!') + -- Prevent dangling LSP sessions. + vim.lsp.stop_client(vim.lsp.get_clients()) + -- Out of the box, worktrees.nvim changes a working directory on worktree switch. -- Optionally, you may prevent this by returning "false". -- return false From 255007f16d0d2a2a8ef69086e39964ed09e49277 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:55:15 -0400 Subject: [PATCH 3/5] feat: add on_before_remove hook Signed-off-by: x1unix <9203548+x1unix@users.noreply.github.com> --- README.md | 17 +++++++++++++---- lua/worktrees/init.lua | 5 +++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5a9b60f..8d410eb 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ require('worktrees').setup { ``` -### Example - save worktree session before switch +### Example - `mini.sessions` integration ```lua require('worktrees').setup { @@ -183,7 +183,7 @@ require('worktrees').setup { hooks = { on_before_switch = function(from, to, git_path_info) -- Persist worktree session before worktree switch. - require('mini.session').write(nil, { force = true, verbose = false }) + MiniSessions.write(nil, { force = true, verbose = false }) vim.cmd('silent! %bwipeout!') -- Prevent dangling LSP sessions. @@ -195,10 +195,19 @@ require('worktrees').setup { end, on_switch = function(from, to, git_path_info) -- Restore session after worktree changes. - if vim.fn.filereadable('Session.vim') then - require('mini.session').read(nil, { force = true, verbose = false }) + if vim.fn.filereadable(MiniSessions.config.file) then + MiniSessions.read(nil, { force = true, verbose = false }) end end, + on_before_remove = function(path) + if path ~= vim.loop.cwd() or vim.v.this_session == '' then + return + end + + -- Detach session if active worktree will be removed. + MiniSessions.delete(nil, { force = true, verbose = false }) + vim.v.this_session = '' + end } } ``` diff --git a/lua/worktrees/init.lua b/lua/worktrees/init.lua index 2e97e73..04164fb 100644 --- a/lua/worktrees/init.lua +++ b/lua/worktrees/init.lua @@ -6,6 +6,7 @@ local status = require("worktrees.status") ---@field on_before_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo): boolean | nil ---@field on_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo) ---@field on_add fun(name: string, path: string, branch: string) +---@field on_before_remove fun(path: string) | nil ---@field on_remove fun(name: string) ---@class worktrees.Options @@ -225,6 +226,10 @@ M.remove_worktree = function(path) return end + if M._options.hooks.on_before_remove then + M._options.hooks.on_before_remove(found_path) + end + if found_path == vim.loop.cwd() then local before_git_path_info = utils.get_git_path_info() if before_git_path_info == nil then From 07c1608e9545b9b60a88c9cd6fb7fb886090be7b Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:56:51 -0400 Subject: [PATCH 4/5] feat: update README.md Signed-off-by: x1unix <9203548+x1unix@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d410eb..2058ccb 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ require('worktrees').setup { ``` -### Example - `mini.sessions` integration +### Example - per-worktree sessions using `mini.sessions` ```lua require('worktrees').setup { From 4cd2505cf9cfc7988e7f9545e34be5446e463541 Mon Sep 17 00:00:00 2001 From: x1unix <9203548+x1unix@users.noreply.github.com> Date: Sat, 4 Apr 2026 23:05:44 -0400 Subject: [PATCH 5/5] fix: make hooks optional Signed-off-by: x1unix <9203548+x1unix@users.noreply.github.com> --- lua/worktrees/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/worktrees/init.lua b/lua/worktrees/init.lua index 04164fb..c032aba 100644 --- a/lua/worktrees/init.lua +++ b/lua/worktrees/init.lua @@ -5,9 +5,9 @@ local status = require("worktrees.status") ---@class worktrees.Hooks ---@field on_before_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo): boolean | nil ---@field on_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo) ----@field on_add fun(name: string, path: string, branch: string) +---@field on_add fun(name: string, path: string, branch: string) | nil ---@field on_before_remove fun(path: string) | nil ----@field on_remove fun(name: string) +---@field on_remove fun(name: string) | nil ---@class worktrees.Options ---@field hooks? worktrees.Hooks,