mirror of
https://github.com/wfxr/forgit.git
synced 2026-09-10 07:16:23 -04:00
feat: add interactive worktree add command (gwa)
Add `gwa` command for interactively creating git worktrees with fzf-powered branch selection. Usage: - `gwa`: select a branch to create a worktree for - `gwa <new-branch>`: create a new branch from a selected base branch - 2+ args: fall back to `git worktree add` directly New worktrees are created under `$FORGIT_WORKTREE_ADD_DIR` (defaults to `<repo-root>/.wt/`) and the shell automatically cd's into the result.
This commit is contained in:
parent
e20071e29b
commit
7f9ea3a4b1
|
|
@ -71,6 +71,7 @@ It's **lightweight** and **easy to use**.
|
|||
| `grw` | Interactive `git commit --fixup=reword && git rebase -i --autosquash` selector |
|
||||
| `gclean` | Interactive `git clean` selector |
|
||||
| `gwt` | Interactive `git worktree` selector |
|
||||
| `gwa` | Interactive `git worktree add` selector |
|
||||
| `gwd` | Interactive `git worktree remove` selector |
|
||||
|
||||
📥 Installation
|
||||
|
|
@ -203,6 +204,7 @@ forgit_fixup=gfu
|
|||
forgit_squash=gsq
|
||||
forgit_reword=grw
|
||||
forgit_worktree=gwt
|
||||
forgit_worktree_add=gwa
|
||||
forgit_worktree_delete=gwd
|
||||
```
|
||||
|
||||
|
|
@ -280,6 +282,7 @@ Each forgit command can be customized with dedicated environment variables for g
|
|||
| `gsq` | `FORGIT_SQUASH_GIT_OPTS` | `FORGIT_SQUASH_FZF_OPTS` |
|
||||
| `grw` | `FORGIT_REWORD_GIT_OPTS` | `FORGIT_REWORD_FZF_OPTS` |
|
||||
| `gwt` | | `FORGIT_WORKTREE_FZF_OPTS` |
|
||||
| `gwa` | `FORGIT_WORKTREE_ADD_BRANCH_GIT_OPTS` | `FORGIT_WORKTREE_ADD_FZF_OPTS` |
|
||||
| `gwd` | `FORGIT_WORKTREE_DELETE_GIT_OPTS` | `FORGIT_WORKTREE_DELETE_FZF_OPTS` |
|
||||
|
||||
### Pagers
|
||||
|
|
@ -350,6 +353,7 @@ export FORGIT_LOG_FZF_OPTS='
|
|||
| `FORGIT_FULLSCREEN_CONTEXT` | lines of diff context in full-screen mode | 10 |
|
||||
| `FORGIT_DIR_VIEW` | command used to preview directories | `tree` if available, otherwise `find` |
|
||||
| `FORGIT_CLEAN_LIST_FILES_OPTS` | arguments passed to `git ls-files` together with `--others` to determine which files are shown when invoking `forgit clean` | |
|
||||
| `FORGIT_WORKTREE_ADD_DIR` | directory where new worktrees are created | `<repo-root>/.wt` |
|
||||
|
||||
⌨ Keybindings
|
||||
---------------
|
||||
|
|
|
|||
|
|
@ -1262,6 +1262,11 @@ _forgit_paths_list() {
|
|||
find "$path" -name "*$ext" -print |sed -e "s#$ext\$##" -e 's#.*/##' -e '/^$/d' | sort -fu
|
||||
}
|
||||
|
||||
# Get the root path of the main worktree (not the current worktree)
|
||||
_forgit_main_worktree_root() {
|
||||
git worktree list --porcelain | sed -n 's/^worktree //p;q'
|
||||
}
|
||||
|
||||
# Parse git worktree list --porcelain output and format it for display
|
||||
# Output format: [XY] /path/to/worktree (branch) 3 hours ago
|
||||
# X: '*' = current worktree, ' ' = other
|
||||
|
|
@ -1410,6 +1415,51 @@ _forgit_worktree_delete() {
|
|||
done
|
||||
}
|
||||
|
||||
_forgit_worktree_add() {
|
||||
_forgit_inside_git_repo || return 1
|
||||
|
||||
# Default to main worktree root, not current worktree's root
|
||||
local wt_dir="${FORGIT_WORKTREE_ADD_DIR:-$(_forgit_main_worktree_root)/.wt}"
|
||||
|
||||
# Two or more arguments: pass through to git directly
|
||||
if [[ $# -ge 2 ]]; then
|
||||
git worktree add "$@"
|
||||
return $?
|
||||
fi
|
||||
|
||||
local new_branch="${1:-}"
|
||||
local opts branch
|
||||
|
||||
_forgit_worktree_add_branch_git_opts=()
|
||||
_forgit_parse_array _forgit_worktree_add_branch_git_opts "$FORGIT_WORKTREE_ADD_BRANCH_GIT_OPTS"
|
||||
|
||||
local header_opt=""
|
||||
[[ -z "$new_branch" ]] && header_opt="--header-lines=1"
|
||||
|
||||
opts="
|
||||
$FORGIT_FZF_DEFAULT_OPTS
|
||||
+s +m --tiebreak=index $header_opt
|
||||
--preview=\"$FORGIT branch_preview {}\"
|
||||
$FORGIT_WORKTREE_ADD_FZF_OPTS
|
||||
"
|
||||
branch=$(_forgit_branch_list "${_forgit_worktree_add_branch_git_opts[@]:---all}" |
|
||||
FZF_DEFAULT_OPTS="$opts" fzf | _forgit_extract_branch_name)
|
||||
[[ -z "$branch" ]] && return 1
|
||||
|
||||
# Strip remotes/<remote>/ prefix for remote branches
|
||||
local local_branch="${branch#remotes/*/}"
|
||||
|
||||
if [[ -n "$new_branch" ]]; then
|
||||
# gwa <new-branch>: create new branch from selected base
|
||||
local target="$wt_dir/$new_branch"
|
||||
git worktree add -b "$new_branch" "$target" "$branch" >&2 && echo "$target"
|
||||
else
|
||||
# gwa: create worktree for selected branch
|
||||
local target="$wt_dir/$local_branch"
|
||||
git worktree add "$target" "$branch" >&2 && echo "$target"
|
||||
fi
|
||||
}
|
||||
|
||||
check_prequisites() {
|
||||
local installed_fzf_version
|
||||
local higher_fzf_version
|
||||
|
|
@ -1484,6 +1534,7 @@ PUBLIC_COMMANDS=(
|
|||
"stash_show"
|
||||
"stash_push"
|
||||
"worktree"
|
||||
"worktree_add"
|
||||
"worktree_delete"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ _git-forgit() {
|
|||
'stash_push:git stash push selector'
|
||||
'switch_branch:git switch branch selector'
|
||||
'worktree:git worktree browser'
|
||||
'worktree_add:git worktree add selector'
|
||||
'worktree_delete:git worktree remove selector'
|
||||
)
|
||||
_describe -t commands 'git forgit' subcommands
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ _git_forgit()
|
|||
stash_push
|
||||
switch_branch
|
||||
worktree
|
||||
worktree_add
|
||||
worktree_delete
|
||||
"
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
function __fish_forgit_needs_subcommand
|
||||
for subcmd in add blame branch_delete checkout_branch checkout_commit checkout_file checkout_tag \
|
||||
cherry_pick cherry_pick_from_branch clean diff fixup ignore log reflog rebase reset_head \
|
||||
revert_commit reword squash stash_show stash_push switch_branch worktree worktree_delete
|
||||
revert_commit reword squash stash_show stash_push switch_branch worktree worktree_add worktree_delete
|
||||
if contains -- $subcmd (commandline -opc)
|
||||
return 1
|
||||
end
|
||||
|
|
@ -51,6 +51,7 @@ complete -c git-forgit -n __fish_forgit_needs_subcommand -a stash_show -d 'git s
|
|||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a stash_push -d 'git stash push selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a switch_branch -d 'git switch branch selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a worktree -d 'git worktree browser'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a worktree_add -d 'git worktree add selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a worktree_delete -d 'git worktree remove selector'
|
||||
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from add' -a "(complete -C 'git add ')"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,14 @@ function forgit::worktree
|
|||
return $status
|
||||
end
|
||||
set -l tree (git-forgit worktree)
|
||||
test -n "$tree"; and cd "$tree"
|
||||
test -d "$tree"; and cd "$tree"
|
||||
end
|
||||
|
||||
function forgit::worktree::add
|
||||
set -l tree (git-forgit worktree_add $argv)
|
||||
or return $status
|
||||
test -d "$tree"; or return 0
|
||||
cd "$tree"; or return 1
|
||||
end
|
||||
|
||||
# register abbreviations
|
||||
|
|
@ -66,5 +73,6 @@ if test -z "$FORGIT_NO_ALIASES"
|
|||
abbr -a -- (string collect $forgit_blame; or string collect "gbl") git-forgit blame
|
||||
abbr -a -- (string collect $forgit_checkout_tag; or string collect "gct") git-forgit checkout_tag
|
||||
abbr -a -- (string collect $forgit_worktree; or string collect "gwt") forgit::worktree
|
||||
abbr -a -- (string collect $forgit_worktree_add; or string collect "gwa") forgit::worktree::add
|
||||
abbr -a -- (string collect $forgit_worktree_delete; or string collect "gwd") git-forgit worktree_delete
|
||||
end
|
||||
|
|
|
|||
|
|
@ -164,7 +164,14 @@ forgit::worktree() {
|
|||
if [[ $# -ne 0 ]]; then "$FORGIT" worktree "$@"; return $?; fi
|
||||
local tree
|
||||
tree=$("$FORGIT" worktree) || return $?
|
||||
[[ -n "$tree" ]] && builtin cd "$tree" || return 1
|
||||
[[ -d "$tree" ]] && builtin cd "$tree" || return 1
|
||||
}
|
||||
|
||||
forgit::worktree::add() {
|
||||
local tree
|
||||
tree=$("$FORGIT" worktree_add "$@") || return $?
|
||||
[[ -d "$tree" ]] || return 0
|
||||
builtin cd "$tree" || return 1
|
||||
}
|
||||
|
||||
forgit::worktree::delete() {
|
||||
|
|
@ -200,6 +207,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
|
|||
builtin export forgit_reword="${forgit_reword:-grw}"
|
||||
builtin export forgit_blame="${forgit_blame:-gbl}"
|
||||
builtin export forgit_worktree="${forgit_worktree:-gwt}"
|
||||
builtin export forgit_worktree_add="${forgit_worktree_add:-gwa}"
|
||||
builtin export forgit_worktree_delete="${forgit_worktree_delete:-gwd}"
|
||||
|
||||
builtin alias "${forgit_add}"='forgit::add'
|
||||
|
|
@ -227,6 +235,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
|
|||
builtin alias "${forgit_reword}"='forgit::reword'
|
||||
builtin alias "${forgit_blame}"='forgit::blame'
|
||||
builtin alias "${forgit_worktree}"='forgit::worktree'
|
||||
builtin alias "${forgit_worktree_add}"='forgit::worktree::add'
|
||||
builtin alias "${forgit_worktree_delete}"='forgit::worktree::delete'
|
||||
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in a new issue