From e3d3d019981aed4b66c923bd5d786b237a9dc735 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Tue, 20 Oct 2026 11:37:54 +0100 Subject: [PATCH] Add start point to worktree add subcommand --- worktree/_worktree | 12 +++++++++++- worktree/worktree.plugin.zsh | 37 +++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/worktree/_worktree b/worktree/_worktree index 7093943..1f19607 100644 --- a/worktree/_worktree +++ b/worktree/_worktree @@ -9,6 +9,14 @@ __worktree_branches() { _describe 'branch' branches } +__worktree_start_points() { + local -a refs + refs=( + ${(fo)"$(git for-each-ref --format='%(refname:short)' refs/heads refs/remotes 2>/dev/null)"} + ) + _describe 'start point' refs +} + __worktree_active_branches() { local -a branches branches=(${(fo)"$(git worktree list --porcelain 2>/dev/null | \ @@ -49,7 +57,9 @@ _worktree() { curcontext="${curcontext%:*:*}:worktree-cmd-$words[1]:" case $line[1] in (add) - _arguments '1:: :__worktree_branches' + _arguments \ + '1:: :__worktree_branches' \ + '2:: :__worktree_start_points' ;; (cd) _arguments '1:: :__worktree_all_branches' diff --git a/worktree/worktree.plugin.zsh b/worktree/worktree.plugin.zsh index 38ca41d..ce98860 100644 --- a/worktree/worktree.plugin.zsh +++ b/worktree/worktree.plugin.zsh @@ -81,14 +81,17 @@ __worktree_find_in() { worktree() { if [[ "$1" == "" ]]; then - echo "usage: worktree {add,cd,list,remove,sync} [...] + echo "usage: worktree add [] + worktree {cd,list,remove,sync} [...] worktree find [-i] " return 1 elif [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then - echo "usage: worktree {add,cd,list,remove,sync} [...] + echo "usage: worktree add [] + worktree {cd,list,remove,sync} [...] worktree find [-i] -Manage git worktrees by branch name." +Manage git worktrees by branch name. A new branch starts from , +e.g. other/main, or origin/main by default." return 0 fi @@ -114,10 +117,34 @@ Manage git worktrees by branch name." print -P "%F{red}error:%f missing argument" return 1 fi + if (( $# > 3 )); then + print -P "%F{red}error:%f unexpected argument: $4" + return 1 + fi + local start=$3 local root=$(git rev-parse --show-toplevel) local wt_dest=${root:h}/${root:t}@${branch} - if ! git show-ref --verify --quiet refs/heads/"$branch" && \ - ! git show-ref --verify --quiet refs/remotes/origin/"$branch"; then + if [[ -n "$start" ]] && \ + ! git rev-parse --verify --quiet "$start^{commit}" >/dev/null; then + # A / start point that hasn't been fetched yet is + # fetched now. Remote names can contain slashes, so the longest + # matching remote wins. + local remote= r + for r in $(git remote); do + [[ "$start" == "$r"/?* ]] && (( ${#r} > ${#remote} )) && remote=$r + done + if [[ -n "$remote" ]]; then + local rbranch=${start#$remote/} + git fetch "$remote" \ + "+refs/heads/${rbranch}:refs/remotes/${remote}/${rbranch}" || return 1 + fi + fi + if [[ -n "$start" ]]; then + # An explicit always makes a new branch, so this fails + # rather than silently ignoring it when the branch already exists. + git branch "$branch" "$start" || return 1 + elif ! git show-ref --verify --quiet refs/heads/"$branch" && \ + ! git show-ref --verify --quiet refs/remotes/origin/"$branch"; then git branch "$branch" origin/main || return 1 fi git worktree add "$wt_dest" "$branch" || return 1