Skip to content

Commit a49bf8c

Browse files
committed
Add option to select base branch for new worktrees
- Thanks to @Juksuu - ThePrimeagen#59
1 parent d409de4 commit a49bf8c

3 files changed

Lines changed: 138 additions & 54 deletions

File tree

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,12 @@ Three primary functions should cover your day-to-day.
107107
The path can be either relative from the git root dir or absoulute path to the worktree.
108108

109109
```lua
110-
-- Creates a worktree. Requires the path, branch name, and the upstream
111-
-- Example:
110+
:-- Creates a worktree. Requires the path, branch name, and the upstream,
111+
-- Optionally the base branch from which to create the new worktree and branch can be added
112+
-- Examples:
113+
-- Creating new worktree and branch `feat-69` based on develop branch to path `feat-69`
114+
:lua require("git-worktree").create_worktree("feat-69", "feat-69", "origin", "develop")
115+
-- Creating new worktree `master` based on master to path `feat-69`
112116
:lua require("git-worktree").create_worktree("feat-69", "master", "origin")
113117

114118
-- switches to an existing worktree. Requires the path name

lua/git-worktree/init.lua

Lines changed: 89 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ local function change_dirs(path)
177177
return previous_worktree
178178
end
179179

180-
local function create_worktree_job(path, branch, found_branch)
180+
local function create_worktree_job(path, branch, found_branch, base_branch)
181181
local worktree_add_cmd = "git"
182182
local worktree_add_args = { "worktree", "add" }
183183

@@ -186,10 +186,12 @@ local function create_worktree_job(path, branch, found_branch)
186186
table.insert(worktree_add_args, path)
187187
local local_branch_name = branch:gsub("origin/", "")
188188
table.insert(worktree_add_args, local_branch_name)
189+
table.insert(worktree_add_args, base_branch)
189190
else
190191
table.insert(worktree_add_args, "-b")
191192
table.insert(worktree_add_args, branch)
192193
table.insert(worktree_add_args, path)
194+
table.insert(worktree_add_args, base_branch)
193195
end
194196
end
195197

@@ -308,8 +310,42 @@ local function has_branch(branch, cb)
308310
end):start()
309311
end
310312

311-
local function create_worktree(path, branch, upstream, found_branch)
312-
local create = create_worktree_job(path, branch, found_branch)
313+
-- Has branch function to use outside of this file
314+
-- apparently existing one doesn't work?
315+
M.has_branch = function(branch)
316+
local found = false
317+
Job:new({
318+
"git",
319+
"branch",
320+
on_stdout = function(_, data)
321+
-- remove marker on current branch
322+
data = data:gsub("*", "")
323+
data = vim.trim(data)
324+
found = found or data == branch
325+
end,
326+
cwd = git_worktree_root,
327+
}):sync()
328+
329+
return found
330+
end
331+
332+
local function create_worktree(path, branch, upstream, found_branch, base_branch)
333+
has_branch(base_branch, function(found)
334+
if not found then
335+
status:status("Valid base branch was not defined, using current worktree")
336+
base_branch = nil
337+
end
338+
end)
339+
340+
local current_branch_job = Job:new({
341+
"git",
342+
"branch",
343+
"--show-current",
344+
cwd = vim.loop.cwd(),
345+
on_stdout = function(_, data)
346+
base_branch = base_branch or data
347+
end,
348+
})
313349

314350
local worktree_path
315351
if Path:new(path):is_absolute() then
@@ -364,54 +400,65 @@ local function create_worktree(path, branch, upstream, found_branch)
364400
end,
365401
})
366402

367-
if upstream ~= nil then
368-
if M._config.fetch_on_create then
369-
create:and_then_on_success(fetch)
370-
fetch:and_then_on_success(set_branch)
371-
else
372-
create:and_then_on_success(set_branch)
373-
end
403+
current_branch_job:add_on_exit_callback(function()
404+
local create = create_worktree_job(path, branch, found_branch, base_branch)
405+
if upstream ~= nil then
406+
if M._config.fetch_on_create then
407+
create:and_then_on_success(fetch)
408+
fetch:and_then_on_success(set_branch)
409+
else
410+
create:and_then_on_success(set_branch)
411+
end
374412

375-
if M._config.autopush then
376-
-- These are "optional" operations.
377-
-- We have to figure out how we want to handle these...
378-
set_branch:and_then(set_push)
379-
set_push:and_then(rebase)
380-
set_push:after_failure(failure("create_worktree", set_branch.args, worktree_path, true))
381-
else
382-
set_branch:and_then(rebase)
383-
end
413+
if M._config.autopush then
414+
-- These are "optional" operations.
415+
-- We have to figure out how we want to handle these...
416+
set_branch:and_then(set_push)
417+
set_push:and_then(rebase)
418+
set_push:after_failure(failure("create_worktree", set_branch.args, worktree_path, true))
419+
else
420+
set_branch:and_then(rebase)
421+
end
384422

385-
create:after_failure(failure("create_worktree", create.args, git_worktree_root))
386-
if M._config.fetch_on_create then
387-
fetch:after_failure(failure("create_worktree", fetch.args, worktree_path))
388-
end
423+
create:after_failure(failure("create_worktree", create.args, git_worktree_root))
424+
if M._config.fetch_on_create then
425+
fetch:after_failure(failure("create_worktree", fetch.args, worktree_path))
426+
end
389427

390-
set_branch:after_failure(failure("create_worktree", set_branch.args, worktree_path, true))
428+
set_branch:after_failure(failure("create_worktree", set_branch.args, worktree_path, true))
391429

392-
rebase:after(function()
393-
if rebase.code ~= 0 then
394-
status:status("Rebase failed, but that's ok.")
395-
end
430+
rebase:after(function()
431+
if rebase.code ~= 0 then
432+
status:status("Rebase failed, but that's ok.")
433+
end
396434

397-
vim.schedule(function()
398-
emit_on_change(Enum.Operations.Create, { path = worktree_path, branch = branch, upstream = upstream })
399-
M.switch_worktree(worktree_path)
435+
vim.schedule(function()
436+
emit_on_change(
437+
Enum.Operations.Create,
438+
{ path = worktree_path, branch = branch, upstream = upstream }
439+
)
440+
M.switch_worktree(worktree_path)
441+
end)
400442
end)
401-
end)
402-
else
403-
create:after(function()
404-
vim.schedule(function()
405-
emit_on_change(Enum.Operations.Create, { path = worktree_path, branch = branch, upstream = upstream })
406-
M.switch_worktree(worktree_path)
443+
else
444+
create:after(function()
445+
vim.schedule(function()
446+
emit_on_change(
447+
Enum.Operations.Create,
448+
{ path = worktree_path, branch = branch, upstream = upstream }
449+
)
450+
M.switch_worktree(worktree_path)
451+
end)
407452
end)
408-
end)
409-
end
453+
end
454+
455+
create:start()
456+
end)
410457

411-
create:start()
458+
current_branch_job:start()
412459
end
413460

414-
M.create_worktree = function(path, branch, upstream)
461+
M.create_worktree = function(path, branch, upstream, base_branch)
415462
status:reset(8)
416463

417464
if upstream == nil then
@@ -428,7 +475,7 @@ M.create_worktree = function(path, branch, upstream)
428475
end
429476

430477
has_branch(branch, function(found_branch)
431-
create_worktree(path, branch, upstream, found_branch)
478+
create_worktree(path, branch, upstream, found_branch, base_branch)
432479
end)
433480
end)
434481
end

lua/telescope/_extensions/git_worktree.lua

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ wt_actions.delete_worktree = function(prompt_bufnr)
8383
end
8484
end
8585

86-
local create_input_prompt = function(cb)
86+
local create_input_prompt = function()
8787
--[[
8888
local window = Window.centered({
8989
width = 30,
@@ -103,9 +103,32 @@ local create_input_prompt = function(cb)
103103
end)
104104
--]]
105105
--
106+
return vim.fn.input("Path to subtree > ")
107+
end
108+
109+
local use_current_worktree_as_base_prompt = function()
110+
return vim.fn.confirm("Use current worktree as base?", "&Yes\n&No", 1) == 1
111+
end
112+
113+
local get_base_branch = function(opts, name, branch)
114+
local base_branch_selection_opts = opts or {}
115+
base_branch_selection_opts.attach_mappings = function()
116+
actions.select_default:replace(function(prompt_bufnr, _)
117+
local selected_entry = action_state.get_selected_entry()
118+
local current_line = action_state.get_current_line()
119+
120+
actions.close(prompt_bufnr)
121+
122+
local base_branch = selected_entry ~= nil and selected_entry.value or current_line
123+
124+
git_worktree.create_worktree(name, branch, nil, base_branch)
125+
end)
126+
127+
-- do we need to replace other default maps?
106128

107-
local subtree = vim.fn.input("Path to subtree > ")
108-
cb(subtree)
129+
return true
130+
end
131+
require("telescope.builtin").git_branches(base_branch_selection_opts)
109132
end
110133

111134
local pconf = {
@@ -159,8 +182,8 @@ local get_default_opts = function(opts)
159182
end
160183

161184
local create_worktree = function(opts)
162-
opts = get_default_opts(opts)
163-
opts.attach_mappings = function()
185+
local branch_selection_opts = get_default_opts(opts)
186+
branch_selection_opts.attach_mappings = function()
164187
actions.select_default:replace(function(prompt_bufnr, _)
165188
local selected_entry = action_state.get_selected_entry()
166189
local current_line = action_state.get_current_line()
@@ -173,19 +196,29 @@ local create_worktree = function(opts)
173196
return
174197
end
175198

176-
create_input_prompt(function(name)
177-
if name == "" then
178-
name = branch
199+
local name = create_input_prompt()
200+
if name == "" then
201+
name = branch
202+
end
203+
204+
local has_branch = git_worktree.has_branch(branch)
205+
206+
if not has_branch then
207+
if use_current_worktree_as_base_prompt() then
208+
git_worktree.create_worktree(name, branch)
209+
else
210+
get_base_branch(opts, name, branch)
179211
end
212+
else
180213
git_worktree.create_worktree(name, branch)
181-
end)
214+
end
182215
end)
183216

184217
-- do we need to replace other default maps?
185218

186219
return true
187220
end
188-
require("telescope.builtin").git_branches(opts)
221+
require("telescope.builtin").git_branches(branch_selection_opts)
189222
end
190223

191224
local telescope_git_worktree = function(opts)

0 commit comments

Comments
 (0)