Refactor: Move git commands from deferred code into functions

We often used deferred code to encapsulate git commands and make them
reusable.
This change removes deferred code for git commands and replaces it with
functions instead.
Some of the deferred code was used with xargs, which executes it on a
subshell. To avoid having to expose the new git functions the same way
we do with the preview functions, the usage of xargs in these cases is
replaced with either a loop or a single command when possible.
This commit is contained in:
sandroid 2024-02-03 00:16:45 +01:00 committed by sandr01d
parent bfffda68d8
commit f927c223f3

View file

@ -236,6 +236,12 @@ _forgit_add_preview() {
fi
}
_forgit_git_add() {
_forgit_add_git_opts=()
_forgit_parse_array _forgit_add_git_opts "$FORGIT_ADD_GIT_OPTS"
git add "${_forgit_add_git_opts[@]}" "$@"
}
_forgit_get_single_file_from_add_line() {
# NOTE: paths listed by 'git status -su' mixed with quoted and unquoted style
# remove indicators | remove original path for rename case | remove surrounding quotes
@ -247,12 +253,9 @@ _forgit_get_single_file_from_add_line() {
# git add selector
_forgit_add() {
_forgit_inside_work_tree || return 1
local git_add changed unmerged untracked files opts extract
_forgit_add_git_opts=()
_forgit_parse_array _forgit_add_git_opts "$FORGIT_ADD_GIT_OPTS"
git_add="git add ${_forgit_add_git_opts[*]}"
local changed unmerged untracked files opts extract
# Add files if passed as arguments
[[ $# -ne 0 ]] && { $git_add "$@" && git status -su; return $?; }
[[ $# -ne 0 ]] && { _forgit_git_add "$@" && git status -su; return $?; }
changed=$(git config --get-color color.status.changed red)
unmerged=$(git config --get-color color.status.unmerged red)
@ -275,7 +278,7 @@ _forgit_add() {
sed -E 's/^(..[^[:space:]]*)[[:space:]]+(.*)$/[\1] \2/' |
FZF_DEFAULT_OPTS="$opts" fzf |
sh -c "$extract")
[[ -n "$files" ]] && echo "$files"| tr '\n' '\0' | $git_add --pathspec-file-nul --pathspec-from-file - && git status -su && return
[[ -n "$files" ]] && echo "$files"| tr '\n' '\0' | _forgit_git_add --pathspec-file-nul --pathspec-from-file - && git status -su && return
echo 'Nothing to add.'
}
@ -284,14 +287,17 @@ _forgit_reset_head_preview() {
git diff --staged --color=always -- "$file" | $_forgit_diff_pager
}
_forgit_git_reset_head() {
_forgit_reset_head_git_opts=()
_forgit_parse_array _forgit_reset_head_git_opts "$FORGIT_RESET_HEAD_GIT_OPTS"
git reset -q "${_forgit_reset_head_git_opts[@]}" HEAD "$@"
}
# git reset HEAD (unstage) selector
_forgit_reset_head() {
_forgit_inside_work_tree || return 1
local git_reset_head files opts rootdir
_forgit_reset_head_git_opts=()
_forgit_parse_array _forgit_reset_head_git_opts "$FORGIT_RESET_HEAD_GIT_OPTS"
git_reset_head="git reset -q ${_forgit_reset_head_git_opts[*]} HEAD"
[[ $# -ne 0 ]] && { $git_reset_head "$@" && git status --short; return $?; }
local files opts rootdir
[[ $# -ne 0 ]] && { _forgit_git_reset_head "$@" && git status --short; return $?; }
rootdir=$(git rev-parse --show-toplevel)
opts="
$FORGIT_FZF_DEFAULT_OPTS
@ -299,10 +305,18 @@ _forgit_reset_head() {
--preview=\"$FORGIT reset_head_preview \"$rootdir\"/{}\"
$FORGIT_RESET_HEAD_FZF_OPTS
"
files="$(git diff --staged --name-only | FZF_DEFAULT_OPTS="$opts" fzf)"
# shellcheck disable=2086
[[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | xargs -0 -I% $git_reset_head "$rootdir"/% && git status --short && return
echo 'Nothing to unstage.'
files=()
while IFS='' read -r file; do
files+=("$file")
done < <(git diff --staged --name-only | FZF_DEFAULT_OPTS="$opts" fzf)
if [[ ${#files} -eq 0 ]]; then
echo 'Nothing to unstage.'
return 1
fi
for file in "${files[@]}"; do
_forgit_git_reset_head "$rootdir/$file"
done
git status --short
}
_forgit_stash_show_preview() {
@ -318,9 +332,8 @@ _forgit_git_stash_show() {
# git stash viewer
_forgit_stash_show() {
_forgit_inside_work_tree || return 1
local git_stash_show git_stash_list opts
git_stash_show="git stash show --color=always --ext-diff"
[[ $# -ne 0 ]] && { $git_stash_show "$@"; return $?; }
local git_stash_list opts
[[ $# -ne 0 ]] && { _forgit_git_stash_show "$@"; return $?; }
_forgit_stash_show_git_opts=()
_forgit_parse_array _forgit_stash_show_git_opts "$FORGIT_STASH_SHOW_GIT_OPTS"
git_stash_list="git stash list ${_forgit_stash_show_git_opts[*]}"
@ -346,13 +359,16 @@ _forgit_stash_push_preview() {
fi
}
_forgit_git_stash_push() {
_forgit_stash_push_git_opts=()
_forgit_parse_array _forgit_stash_push_git_opts "$FORGIT_STASH_PUSH_GIT_OPTS"
git stash push "${_forgit_stash_push_git_opts[@]}" "$@"
}
# git stash push selector
_forgit_stash_push() {
_forgit_inside_work_tree || return 1
local git_stash_push msg args
_forgit_stash_push_git_opts=()
_forgit_parse_array _forgit_stash_push_git_opts "$FORGIT_STASH_PUSH_GIT_OPTS"
git_stash_push="git stash push ${_forgit_stash_push_git_opts[*]}"
local msg args
args=( "$@" )
while (( "$#" )); do
case "$1" in
@ -364,7 +380,7 @@ _forgit_stash_push() {
# ignore -u as it's used implicitly
-u|--include-untracked) shift ;;
# pass to git directly when encountering anything else
*) $git_stash_push "${args[@]}"; return $?
*) _forgit_git_stash_push "${args[@]}"; return $?
esac
done
local opts files
@ -376,7 +392,7 @@ _forgit_stash_push() {
# Show both modified and untracked files
files=$(git ls-files --exclude-standard --modified --others | FZF_DEFAULT_OPTS="$opts" fzf --preview="$FORGIT stash_push_preview {}")
[[ -z "$files" ]] && return 1
echo "${files[@]}" | tr '\n' '\0' | $git_stash_push ${msg:+-m "$msg"} -u --pathspec-file-nul --pathspec-from-file -
echo "${files[@]}" | tr '\n' '\0' | _forgit_git_stash_push ${msg:+-m "$msg"} -u --pathspec-file-nul --pathspec-from-file -
}
# git clean selector
@ -405,6 +421,7 @@ _forgit_cherry_pick_preview() {
_forgit_cherry_pick() {
local git_cherry_pick base target opts fzf_selection fzf_exitval
_forgit_cherry_pick_git_opts=()
_forgit_parse_array _forgit_cherry_pick_git_opts "$FORGIT_CHERRY_PICK_GIT_OPTS"
git_cherry_pick="git cherry-pick ${_forgit_cherry_pick_git_opts[*]}"
@ -549,14 +566,17 @@ _forgit_checkout_file_preview() {
git diff --color=always -- "$1" | $_forgit_diff_pager
}
_forgit_git_checkout_file() {
_forgit_checkout_file_git_opts=()
_forgit_parse_array _forgit_checkout_file_git_opts "$FORGIT_CHECKOUT_FILE_GIT_OPTS"
git checkout "${_forgit_checkout_file_git_opts[@]}" "$@"
}
# git checkout-file selector
_forgit_checkout_file() {
_forgit_inside_work_tree || return 1
local git_checkout files opts
_forgit_checkout_file_git_opts=()
_forgit_parse_array _forgit_checkout_file_git_opts "$FORGIT_CHECKOUT_FILE_GIT_OPTS"
git_checkout="git checkout ${_forgit_checkout_file_git_opts[*]}"
[[ $# -ne 0 ]] && { $git_checkout -- "$@"; return $?; }
local files opts
[[ $# -ne 0 ]] && { _forgit_git_checkout_file -- "$@"; return $?; }
opts="
$FORGIT_FZF_DEFAULT_OPTS
-m -0
@ -564,7 +584,13 @@ _forgit_checkout_file() {
$FORGIT_CHECKOUT_FILE_FZF_OPTS
"
files="$(git ls-files --modified "$(git rev-parse --show-toplevel)"| FZF_DEFAULT_OPTS="$opts" fzf)"
[[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | $git_checkout --pathspec-file-nul --pathspec-from-file -
[[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | _forgit_git_checkout_file --pathspec-file-nul --pathspec-from-file -
}
_forgit_git_checkout_branch() {
_forgit_checkout_branch_git_opts=()
_forgit_parse_array _forgit_checkout_branch_git_opts "$FORGIT_CHECKOUT_BRANCH_GIT_OPTS"
git checkout "${_forgit_checkout_branch_git_opts[@]}" "$@"
}
# git checkout-branch selector
@ -582,7 +608,7 @@ _forgit_checkout_branch() {
return $checkout_status
fi
local git_checkout cmd opts branch
local cmd opts branch
_forgit_checkout_branch_branch_git_opts=()
_forgit_parse_array _forgit_checkout_branch_branch_git_opts "$FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS"
cmd="git branch --color=always ${_forgit_checkout_branch_branch_git_opts[*]:---all} | LC_ALL=C sort -k1.1,1.1 -rs"
@ -595,30 +621,30 @@ _forgit_checkout_branch() {
branch="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')"
[[ -z "$branch" ]] && return 1
_forgit_checkout_branch_git_opts=()
_forgit_parse_array _forgit_checkout_branch_git_opts "$FORGIT_CHECKOUT_BRANCH_GIT_OPTS"
git_checkout="git checkout ${_forgit_checkout_branch_git_opts[*]}"
# track the remote branch if possible
if [[ "$branch" == "remotes/origin/"* ]]; then
if git branch | grep -qw "${branch#remotes/origin/}"; then
# hack to force creating a new branch which tracks the remote if a local branch already exists
$git_checkout -b "track/${branch#remotes/origin/}" --track "$branch"
elif ! $git_checkout --track "$branch" 2>/dev/null; then
$git_checkout "$branch"
_forgit_git_checkout_branch -b "track/${branch#remotes/origin/}" --track "$branch"
elif ! _forgit_git_checkout_branch --track "$branch" 2>/dev/null; then
_forgit_git_checkout_branch "$branch"
fi
else
$git_checkout "$branch"
_forgit_git_checkout_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"
git checkout "${_forgit_checkout_tag_git_opts[@]}" "$@"
}
# git checkout-tag selector
_forgit_checkout_tag() {
_forgit_inside_work_tree || return 1
local git_checkout cmd opts
_forgit_checkout_tag_git_opts=()
_forgit_parse_array _forgit_checkout_tag_git_opts "$FORGIT_CHECKOUT_TAG_GIT_OPTS"
git_checkout="git checkout ${_forgit_checkout_tag_git_opts[*]}"
[[ $# -ne 0 ]] && { $git_checkout "$@"; return $?; }
local cmd opts
[[ $# -ne 0 ]] && { _forgit_git_checkout_tag "$@"; return $?; }
cmd="git tag -l --sort=-v:refname"
opts="
$FORGIT_FZF_DEFAULT_OPTS
@ -628,21 +654,24 @@ _forgit_checkout_tag() {
"
tag="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf)"
[[ -z "$tag" ]] && return 1
$git_checkout "$tag"
_forgit_git_checkout_tag "$tag"
}
_forgit_checkout_commit_preview() {
echo "$1" | _forgit_extract_sha | xargs -I% git show --color=always % | $_forgit_show_pager
}
_forgit_git_checkout_commit() {
_forgit_checkout_commit_git_opts=()
_forgit_parse_array _forgit_checkout_commit_git_opts "$FORGIT_CHECKOUT_COMMIT_GIT_OPTS"
git checkout "${_forgit_checkout_commit_git_opts[@]}" "$@"
}
# git checkout-commit selector
_forgit_checkout_commit() {
_forgit_inside_work_tree || return 1
local git_checkout opts graph
_forgit_checkout_commit_git_opts=()
_forgit_parse_array _forgit_checkout_commit_git_opts "$FORGIT_CHECKOUT_COMMIT_GIT_OPTS"
git_checkout="git checkout ${_forgit_checkout_commit_git_opts[*]}"
[[ $# -ne 0 ]] && { $git_checkout "$@"; return $?; }
local opts graph commit
[[ $# -ne 0 ]] && { _forgit_git_checkout_commit "$@"; return $?; }
opts="
$FORGIT_FZF_DEFAULT_OPTS
+s +m --tiebreak=index
@ -652,22 +681,25 @@ _forgit_checkout_commit() {
"
graph=--graph
[[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph=
# shellcheck disable=2086
eval "git log $graph --color=always --format='$_forgit_log_format' $_forgit_emojify" |
FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha" | xargs -I% $git_checkout % --
commit="$(eval "git log $graph --color=always --format='$_forgit_log_format' $_forgit_emojify" |
FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha")"
_forgit_git_checkout_commit "$commit"
}
_forgit_branch_preview() {
git log "$1" "${_forgit_log_preview_options[@]}"
}
_forgit_branch_delete() {
_forgit_inside_work_tree || return 1
local git_branch opts cmd branches
_forgit_git_branch_delete() {
_forgit_branch_delete_git_opts=()
_forgit_parse_array _forgit_branch_delete_git_opts "$FORGIT_BRANCH_DELETE_GIT_OPTS"
git_branch="git branch ${_forgit_branch_delete_git_opts[*]}"
[[ $# -ne 0 ]] && { $git_branch -D "$@"; return $?; }
git branch "${_forgit_branch_delete_git_opts[@]}" -D "$@"
}
_forgit_branch_delete() {
_forgit_inside_work_tree || return 1
local opts cmd
[[ $# -ne 0 ]] && { _forgit_git_branch_delete "$@"; return $?; }
opts="
$FORGIT_FZF_DEFAULT_OPTS
@ -677,9 +709,9 @@ _forgit_branch_delete() {
"
cmd="git branch --color=always | LC_ALL=C sort -k1.1,1.1 -rs"
branches=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')
# shellcheck disable=2086
echo -n "$branches" | tr '\n' '\0' | xargs -I{} -0 $git_branch -D {}
for branch in $(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}'); do
_forgit_git_branch_delete "$branch"
done
}
_forgit_revert_preview() {
@ -690,14 +722,17 @@ _forgit_revert_preview() {
$_forgit_show_pager
}
_forgit_git_revert() {
_forgit_revert_commit_git_opts=()
_forgit_parse_array _forgit_revert_commit_git_opts "$FORGIT_REVERT_COMMIT_GIT_OPTS"
git revert "${_forgit_revert_commit_git_opts[@]}" "$@"
}
# git revert-commit selector
_forgit_revert_commit() {
_forgit_inside_work_tree || return 1
local git_revert cmd opts files commits IFS
_forgit_revert_commit_git_opts=()
_forgit_parse_array _forgit_revert_commit_git_opts "$FORGIT_REVERT_COMMIT_GIT_OPTS"
git_revert="git revert ${_forgit_revert_commit_git_opts[*]}"
[[ $# -ne 0 ]] && { $git_revert "$@"; return $?; }
local cmd opts files commits IFS
[[ $# -ne 0 ]] && { _forgit_git_revert "$@"; return $?; }
cmd="git log --graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify"
opts="
@ -727,7 +762,7 @@ _forgit_revert_commit() {
[ ${#commits[@]} -eq 0 ] && return 1
$git_revert "${commits[@]}"
_forgit_git_revert "${commits[@]}"
}
_forgit_blame_preview() {
@ -740,14 +775,17 @@ _forgit_blame_preview() {
fi
}
_forgit_git_blame() {
_forgit_blame_git_opts=()
_forgit_parse_array _forgit_blame_git_opts "$FORGIT_BLAME_GIT_OPTS"
git blame "${_forgit_blame_git_opts[@]}" "$@"
}
# git blame viewer
_forgit_blame() {
_forgit_inside_work_tree || return 1
local git_blame opts flags file
_forgit_blame_git_opts=()
_forgit_parse_array _forgit_blame_git_opts "$FORGIT_BLAME_GIT_OPTS"
git_blame="git blame ${_forgit_blame_git_opts[*]}"
_forgit_contains_non_flags "$@" && { $git_blame "$@"; return $?; }
local opts flags file
_forgit_contains_non_flags "$@" && { _forgit_git_blame "$@"; return $?; }
opts="
$FORGIT_FZF_DEFAULT_OPTS
$FORGIT_BLAME_FZF_OPTS
@ -761,8 +799,7 @@ _forgit_blame() {
# with git rev-parse and can only contain flags
file=$(FZF_DEFAULT_OPTS="$opts" fzf --preview="$FORGIT blame_preview {} ${flags[*]}")
[[ -z "$file" ]] && return 1
# shellcheck disable=2086
eval $git_blame "$file" "${flags[*]}"
_forgit_git_blame "$file" "${flags[@]}"
}
# git ignore generator