Feature: add interactive git switch selector (#472)

This commit is contained in:
Iván Sotillo del Horno 2025-12-10 20:19:26 +01:00 committed by GitHub
parent 779b59690f
commit 3cd63a1bbe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 66 additions and 2 deletions

View file

@ -105,7 +105,7 @@ Forgit offers completions for all supported shells. Completions are automaticall
- Put [`completions/git-forgit.bash`](https://github.com/wfxr/forgit/blob/main/completions/git-forgit.bash) in
`~/.local/share/bash-completion/completions` to have bash tab completion for `git forgit` and configured git aliases.
- Source [`completions/git-forgit.bash`](https://github.com/wfxr/forgit/blob/main/completions/git-forgit.bash) explicitly to have
bash tab completion for forgit shell functions and aliases (e.g., `gcb <tab>` completes branches).
bash tab completion for forgit shell functions and aliases (e.g., `gsw <tab>` completes branches).
## Fish
@ -148,6 +148,8 @@ If you're having issues after updating, and commands such as `forgit::add` or al
- **Interactive `git checkout <branch>` selector** (`gcb`)
- **Interactive `git switch <branch>` selector** (`gsw`)
- **Interactive `git branch -D <branch>` selector** (`gbd`)
- **Interactive `git checkout <tag>` selector** (`gct`)
@ -224,6 +226,7 @@ forgit_ignore=gi
forgit_attributes=gat
forgit_checkout_file=gcf
forgit_checkout_branch=gcb
forgit_switch_branch=gsw
forgit_branch_delete=gbd
forgit_checkout_tag=gct
forgit_checkout_commit=gco
@ -285,6 +288,7 @@ These are passed to the according `git` calls.
| `grh` | `FORGIT_RESET_HEAD_GIT_OPTS` |
| `gcf` | `FORGIT_CHECKOUT_FILE_GIT_OPTS` |
| `gcb` | `FORGIT_CHECKOUT_BRANCH_GIT_OPTS`, `FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS` |
| `gsw` | `FORGIT_SWITCH_BRANCH_GIT_OPTS` |
| `gbd` | `FORGIT_BRANCH_DELETE_GIT_OPTS` |
| `gct` | `FORGIT_CHECKOUT_TAG_GIT_OPTS` |
| `gco` | `FORGIT_CHECKOUT_COMMIT_GIT_OPTS` |
@ -344,6 +348,7 @@ Customizing fzf options for each command individually is also supported:
| `grh` | `FORGIT_RESET_HEAD_FZF_OPTS` |
| `gcf` | `FORGIT_CHECKOUT_FILE_FZF_OPTS` |
| `gcb` | `FORGIT_CHECKOUT_BRANCH_FZF_OPTS` |
| `gsw` | `FORGIT_SWITCH_BRANCH_FZF_OPTS` |
| `gbd` | `FORGIT_BRANCH_DELETE_FZF_OPTS` |
| `gct` | `FORGIT_CHECKOUT_TAG_FZF_OPTS` |
| `gco` | `FORGIT_CHECKOUT_COMMIT_FZF_OPTS` |

View file

@ -903,6 +903,52 @@ _forgit_checkout_branch() {
fi
}
_forgit_git_switch_branch() {
_forgit_switch_branch_git_opts=()
_forgit_parse_array _forgit_switch_branch_git_opts "$FORGIT_SWITCH_BRANCH_GIT_OPTS"
git switch "${_forgit_switch_branch_git_opts[@]}" "$@"
}
_forgit_switch_branch() {
_forgit_inside_work_tree || return 1
# if called with arguments, check if branch exists, else create a new one
if [[ $# -ne 0 ]]; then
if [[ "$*" == "-" ]] || git show-branch "$@" &>/dev/null; then
git switch "$@"
else
git switch -c "$@"
fi
checkout_status=$?
git status --short
return $checkout_status
fi
local opts branch
opts="
$FORGIT_FZF_DEFAULT_OPTS
+s +m --tiebreak=index --header-lines=1
--preview=\"$FORGIT branch_preview {1}\"
$FORGIT_SWITCH_BRANCH_FZF_OPTS
"
_forgit_switch_branch_branch_git_opts=()
_forgit_parse_array _forgit_switch_branch_branch_git_opts "$FORGIT_SWITCH_BRANCH_BRANCH_GIT_OPTS"
branch="$(git branch --color=always "${_forgit_switch_branch_branch_git_opts[@]:---all}" | LC_ALL=C sort -k1.1,1.1 -rs |
FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')"
[[ -z "$branch" ]] && return 1
# track the remote branch if possible
if [[ "$branch" == "remotes/"* ]]; then
if git branch | grep -qw "${branch#remotes/*/}"; then
# hack to force creating a new branch which tracks the remote if a local branch already exists
_forgit_git_switch_branch --create "track/${branch#remotes/*/}" --track "$branch"
elif ! _forgit_git_switch_branch --track "$branch" 2>/dev/null; then
_forgit_git_switch_branch "$branch"
fi
else
_forgit_git_switch_branch "$branch"
fi
}
_forgit_git_checkout_tag() {
_forgit_checkout_tag_git_opts=()
_forgit_parse_array _forgit_checkout_tag_git_opts "$FORGIT_CHECKOUT_TAG_GIT_OPTS"
@ -1233,6 +1279,7 @@ PUBLIC_COMMANDS=(
"blame"
"branch_delete"
"checkout_branch"
"switch_branch"
"checkout_commit"
"checkout_file"
"checkout_tag"

View file

@ -113,6 +113,7 @@ _git-forgit() {
compdef _git-add forgit::add
compdef _git-branches forgit::branch::delete
compdef _git-branches forgit::checkout::branch
compdef _git-branches forgit::switch::branch
compdef __git_recent_commits forgit::checkout::commit
compdef _git-checkout-file forgit::checkout::file
compdef __git_tags forgit::checkout::tag

View file

@ -128,6 +128,7 @@ then
__git_complete forgit::add _git_add
__git_complete forgit::branch::delete _git_branch_delete
__git_complete forgit::checkout::branch _git_checkout_branch
__git_complete forgit::switch::branch _git_switch_branch
__git_complete forgit::checkout::commit _git_checkout
__git_complete forgit::checkout::file _git_checkout_file
__git_complete forgit::checkout::tag _git_checkout_tag
@ -151,6 +152,7 @@ then
__git_complete "${forgit_add}" _git_add
__git_complete "${forgit_branch_delete}" _git_branch_delete
__git_complete "${forgit_checkout_branch}" _git_checkout_branch
__git_complete "${forgit_switch_branch}" _git_switch_branch
__git_complete "${forgit_checkout_commit}" _git_checkout
__git_complete "${forgit_checkout_file}" _git_checkout_file
__git_complete "${forgit_checkout_tag}" _git_checkout_tag

View file

@ -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
revert_commit reword squash stash_show stash_push switch_branch
if contains -- $subcmd (commandline -opc)
return 1
end
@ -45,6 +45,7 @@ complete -c git-forgit -n __fish_forgit_needs_subcommand -a show -d 'git show vi
complete -c git-forgit -n __fish_forgit_needs_subcommand -a squash -d 'git squash'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a stash_show -d 'git stash viewer'
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_seen_subcommand_from add' -a "(complete -C 'git add ')"
complete -c git-forgit -n '__fish_seen_subcommand_from branch_delete' -a "(__fish_git_local_branches)"
@ -66,3 +67,4 @@ complete -c git-forgit -n '__fish_seen_subcommand_from show' -a "(complete -C 'g
complete -c git-forgit -n '__fish_seen_subcommand_from squash' -a "(complete -C 'git log ')"
complete -c git-forgit -n '__fish_seen_subcommand_from stash_show' -a "(__fish_git_complete_stashes)"
complete -c git-forgit -n '__fish_seen_subcommand_from stash_push' -a "(__fish_git_files modified deleted modified-staged-deleted)"
complete -c git-forgit -n '__fish_seen_subcommand_from switch_branch' -a "(complete -C 'git switch ')"

View file

@ -42,6 +42,7 @@ if test -z "$FORGIT_NO_ALIASES"
abbr -a -- (string collect $forgit_attributes; or string collect "gat") git-forgit attributes
abbr -a -- (string collect $forgit_checkout_file; or string collect "gcf") git-forgit checkout_file
abbr -a -- (string collect $forgit_checkout_branch; or string collect "gcb") git-forgit checkout_branch
abbr -a -- (string collect $forgit_switch_branch; or string collect "gsw") git-forgit switch_branch
abbr -a -- (string collect $forgit_branch_delete; or string collect "gbd") git-forgit branch_delete
abbr -a -- (string collect $forgit_clean; or string collect "gclean") git-forgit clean
abbr -a -- (string collect $forgit_stash_show; or string collect "gss") git-forgit stash_show

View file

@ -112,6 +112,10 @@ forgit::checkout::branch() {
"$FORGIT" checkout_branch "$@"
}
forgit::switch::branch() {
"$FORGIT" switch_branch "$@"
}
forgit::checkout::tag() {
"$FORGIT" checkout_tag "$@"
}
@ -170,6 +174,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
builtin export forgit_attributes="${forgit_attributes:-gat}"
builtin export forgit_checkout_file="${forgit_checkout_file:-gcf}"
builtin export forgit_checkout_branch="${forgit_checkout_branch:-gcb}"
builtin export forgit_switch_branch="${forgit_switch_branch:-gsw}"
builtin export forgit_checkout_commit="${forgit_checkout_commit:-gco}"
builtin export forgit_checkout_tag="${forgit_checkout_tag:-gct}"
builtin export forgit_branch_delete="${forgit_branch_delete:-gbd}"
@ -194,6 +199,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
builtin alias "${forgit_attributes}"='forgit::attributes'
builtin alias "${forgit_checkout_file}"='forgit::checkout::file'
builtin alias "${forgit_checkout_branch}"='forgit::checkout::branch'
builtin alias "${forgit_switch_branch}"='forgit::switch::branch'
builtin alias "${forgit_checkout_commit}"='forgit::checkout::commit'
builtin alias "${forgit_checkout_tag}"='forgit::checkout::tag'
builtin alias "${forgit_branch_delete}"='forgit::branch::delete'