diff --git a/README.md b/README.md index 743e3be..f888f0b 100644 --- a/README.md +++ b/README.md @@ -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 ` completes branches). + bash tab completion for forgit shell functions and aliases (e.g., `gsw ` 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 ` selector** (`gcb`) +- **Interactive `git switch ` selector** (`gsw`) + - **Interactive `git branch -D ` selector** (`gbd`) - **Interactive `git checkout ` 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` | diff --git a/bin/git-forgit b/bin/git-forgit index 7bddde0..41375ea 100755 --- a/bin/git-forgit +++ b/bin/git-forgit @@ -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" diff --git a/completions/_git-forgit b/completions/_git-forgit index c85bcd5..ee80c88 100644 --- a/completions/_git-forgit +++ b/completions/_git-forgit @@ -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 diff --git a/completions/git-forgit.bash b/completions/git-forgit.bash index 47b81d1..7a508ce 100755 --- a/completions/git-forgit.bash +++ b/completions/git-forgit.bash @@ -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 diff --git a/completions/git-forgit.fish b/completions/git-forgit.fish index 31fb3ad..48f995c 100644 --- a/completions/git-forgit.fish +++ b/completions/git-forgit.fish @@ -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 ')" diff --git a/conf.d/forgit.plugin.fish b/conf.d/forgit.plugin.fish index 58bb18a..2ffd429 100644 --- a/conf.d/forgit.plugin.fish +++ b/conf.d/forgit.plugin.fish @@ -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 diff --git a/forgit.plugin.zsh b/forgit.plugin.zsh index 54a8f8b..012c354 100755 --- a/forgit.plugin.zsh +++ b/forgit.plugin.zsh @@ -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'