Add start point to worktree add subcommand

This commit is contained in:
2026-10-20 11:37:54 +01:00
parent 538f90083b
commit e3d3d01998
2 changed files with 43 additions and 6 deletions

View File

@@ -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'

View File

@@ -81,14 +81,17 @@ __worktree_find_in() {
worktree() {
if [[ "$1" == "" ]]; then
echo "usage: worktree {add,cd,list,remove,sync} <branch> [<branch>...]
echo "usage: worktree add <branch> [<start-point>]
worktree {cd,list,remove,sync} <branch> [<branch>...]
worktree find [-i] <glob>"
return 1
elif [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
echo "usage: worktree {add,cd,list,remove,sync} <branch> [<branch>...]
echo "usage: worktree add <branch> [<start-point>]
worktree {cd,list,remove,sync} <branch> [<branch>...]
worktree find [-i] <glob>
Manage git worktrees by branch name."
Manage git worktrees by branch name. A new branch starts from <start-point>,
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 <branch> 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 <remote>/<branch> 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 <start-point> 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