From 2a2ee36d5624dfe62adbd3ada4cbbdff76849ec4 Mon Sep 17 00:00:00 2001 From: Tim <45259958+carlfriedrich@users.noreply.github.com> Date: Sat, 18 Mar 2023 12:25:20 +0100 Subject: [PATCH] Add git options for each forgit command (#292) The git behavior within forgit can now be customized with a dedicated variable for each forgit command, e.g. `FORGIT_ADD_GIT_OPTS` is passed to the `git add` call within `ga`. Also renaming `FORGIT_STASH_PUSH_OPTS` to `FORGIT_STASH_PUSH_FZF_OPTS` and `FORGIT_REVERT_COMMIT_OPTS` to `FORGIT_REVERT_COMMIT_FZF_OPTS` for consistency. --- README.md | 32 ++++++++++++++++++++++--- bin/git-forgit | 65 +++++++++++++++++++++++++------------------------- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 7c50475..2c66737 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ forgit_blame=gbl forgit_fixup=gfu ``` -#### git +#### git integration You can use forgit as a subcommand of git by making `git-forgit` available in `$PATH`: @@ -193,6 +193,32 @@ And use forgit functions via a git alias: git cf ``` +#### git options + +If you want to customize `git`'s behavior within forgit there is a dedicated variable for each forgit command. +These are passed to the according `git` calls. + +| Command | Option | +|----------|-----------------------------------| +| `ga` | `FORGIT_ADD_GIT_OPTS` | +| `glo` | `FORGIT_LOG_GIT_OPTS` | +| `gd` | `FORGIT_DIFF_GIT_OPTS` | +| `grh` | `FORGIT_RESET_HEAD_GIT_OPTS` | +| `gcf` | `FORGIT_CHECKOUT_FILE_GIT_OPTS` | +| `gcb` | `FORGIT_CHECKOUT_BRANCH_GIT_OPTS` | +| `gbd` | `FORGIT_BRANCH_DELETE_GIT_OPTS` | +| `gct` | `FORGIT_CHECKOUT_TAG_GIT_OPTS` | +| `gco` | `FORGIT_CHECKOUT_COMMIT_GIT_OPTS` | +| `grc` | `FORGIT_REVERT_COMMIT_GIT_OPTS` | +| `gss` | `FORGIT_STASH_SHOW_GIT_OPTS` | +| `gsp` | `FORGIT_STASH_PUSH_GIT_OPTS` | +| `gclean` | `FORGIT_CLEAN_GIT_OPTS` | +| `grb` | `FORGIT_REBASE_GIT_OPTS` | +| `gbl` | `FORGIT_BLAME_GIT_OPTS` | +| `gfu` | `FORGIT_FIXUP_GIT_OPTS` | +| `gcp` | `FORGIT_CHERRY_PICK_GIT_OPTS` | + + #### pagers Forgit will use the default configured pager from git (`core.pager`, @@ -237,9 +263,9 @@ Customizing fzf options for each command individually is also supported: | `gbd` | `FORGIT_BRANCH_DELETE_FZF_OPTS` | | `gct` | `FORGIT_CHECKOUT_TAG_FZF_OPTS` | | `gco` | `FORGIT_CHECKOUT_COMMIT_FZF_OPTS` | -| `grc` | `FORGIT_REVERT_COMMIT_OPTS` | +| `grc` | `FORGIT_REVERT_COMMIT_FZF_OPTS` | | `gss` | `FORGIT_STASH_FZF_OPTS` | -| `gsp` | `FORGIT_STASH_PUSH_OPTS` | +| `gsp` | `FORGIT_STASH_PUSH_FZF_OPTS` | | `gclean` | `FORGIT_CLEAN_FZF_OPTS` | | `grb` | `FORGIT_REBASE_FZF_OPTS` | | `gbl` | `FORGIT_BLAME_FZF_OPTS` | diff --git a/bin/git-forgit b/bin/git-forgit index 11023c9..4c13944 100755 --- a/bin/git-forgit +++ b/bin/git-forgit @@ -90,7 +90,7 @@ _forgit_log() { graph=--graph [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= log_format=${FORGIT_GLO_FORMAT:-$_forgit_log_format} - eval "git log $graph --color=always --format='$log_format' $* $_forgit_emojify" | + eval "git log $graph --color=always --format='$log_format' $FORGIT_LOG_GIT_OPTS $* $_forgit_emojify" | FZF_DEFAULT_OPTS="$opts" fzf fzf_exit_code=$? # exit successfully on 130 (ctrl-c/esc) @@ -131,7 +131,7 @@ _forgit_diff() { # prevent fzf from interpreting this substring by escaping the opening bracket. # The string is evaluated a few subsequent times, so we need multiple escapes. escaped_commits=${commits//\{/\\\\\{} - git_diff="git diff --color=always $escaped_commits" + git_diff="git diff --color=always $FORGIT_DIFF_GIT_OPTS $escaped_commits" preview_cmd="cd '$repo' && $get_files | xargs -0 $git_diff -U$_forgit_preview_context -- | $_forgit_diff_pager" enter_cmd="cd '$repo' && $get_files | xargs -0 $git_diff -U$_forgit_fullscreen_context -- | $_forgit_diff_pager" opts=" @@ -141,7 +141,7 @@ _forgit_diff() { $FORGIT_DIFF_FZF_OPTS --prompt=\"$commits > \" " - eval "git diff --name-status $commits -- ${files[*]} | sed -E 's/^([[:alnum:]]+)[[:space:]]+(.*)$/[\1] \2/'" | + eval "git diff --name-status $FORGIT_DIFF_GIT_OPTS $commits -- ${files[*]} | sed -E 's/^([[:alnum:]]+)[[:space:]]+(.*)$/[\1] \2/'" | sed 's/ / -> /2' | expand -t 8 | FZF_DEFAULT_OPTS="$opts" fzf fzf_exit_code=$? @@ -154,7 +154,7 @@ _forgit_diff() { _forgit_add() { _forgit_inside_work_tree || return 1 # Add files if passed as arguments - [[ $# -ne 0 ]] && git add "$@" && git status -su && return + [[ $# -ne 0 ]] && git add "$FORGIT_ADD_GIT_OPTS" "$@" && git status -su && return local changed unmerged untracked files opts preview extract changed=$(git config --get-color color.status.changed red) @@ -184,7 +184,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' | git add --pathspec-file-nul --pathspec-from-file "$FORGIT_ADD_GIT_OPTS" - && git status -su && return echo 'Nothing to add.' } @@ -201,7 +201,7 @@ _forgit_reset_head() { $FORGIT_RESET_HEAD_FZF_OPTS " files="$(git diff --staged --name-only | FZF_DEFAULT_OPTS="$opts" fzf)" - [[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | xargs -0 -I% git reset -q HEAD "$rootdir"/% && git status --short && return + [[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | xargs -0 -I% git reset -q "$FORGIT_RESET_HEAD_GIT_OPTS" HEAD "$rootdir"/% && git status --short && return echo 'Nothing to unstage.' } @@ -209,7 +209,7 @@ _forgit_reset_head() { _forgit_stash_show() { _forgit_inside_work_tree || return 1 local cmd opts - cmd="echo {} |cut -d: -f1 |xargs -I% git stash show --color=always --ext-diff % |$_forgit_diff_pager" + cmd="echo {} |cut -d: -f1 |xargs -I% git stash show --color=always --ext-diff $FORGIT_STASH_SHOW_GIT_OPTS % |$_forgit_diff_pager" opts=" $FORGIT_FZF_DEFAULT_OPTS +s +m -0 --tiebreak=index --bind=\"enter:execute($cmd | $_forgit_enter_pager)\" @@ -238,14 +238,14 @@ _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 $? + *) git stash push "$FORGIT_STASH_PUSH_GIT_OPTS" "${args[@]}" && return $? esac done local opts preview files opts=" $FORGIT_FZF_DEFAULT_OPTS -m - $FORGIT_STASH_PUSH_OPTS + $FORGIT_STASH_PUSH_FZF_OPTS " preview=" if $_forgit_is_file_tracked; then @@ -257,7 +257,7 @@ _forgit_stash_push() { # Show both modified and untracked files files=$(git ls-files --exclude-standard --modified --others | FZF_DEFAULT_OPTS="$opts" fzf --preview="$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' | git stash push ${msg:+-m "$msg"} -u --pathspec-file-nul --pathspec-from-file "$FORGIT_STASH_PUSH_GIT_OPTS" - } # git clean selector @@ -271,7 +271,7 @@ _forgit_clean() { " # Note: Postfix '/' in directory path should be removed. Otherwise the directory itself will not be removed. files=$(git clean -xdffn "$@"| sed 's/^Would remove //' | FZF_DEFAULT_OPTS="$opts" fzf |sed 's#/$##') - [[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | xargs -0 -I% git clean -xdff '%' && git status --short && return + [[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | xargs -0 -I% git clean -xdff "$FORGIT_CLEAN_GIT_OPTS" '%' && git status --short && return echo 'Nothing to clean.' } @@ -308,7 +308,7 @@ _forgit_cherry_pick() { IFS=$'\n' commits=($(echo "$fzf_selection" | sort --numeric-sort --key=1 | cut -f2 | cut -d' ' -f1 | _forgit_reverse_lines)) [ ${#commits[@]} -eq 0 ] && return 1 - git cherry-pick "${commits[@]}" + git cherry-pick "$FORGIT_CHERRY_PICK_GIT_OPTS" "${commits[@]}" } _forgit_cherry_pick_from_branch() { @@ -369,7 +369,7 @@ _forgit_rebase() { if [[ -n "$target_commit" ]]; then prev_commit=$(_forgit_previous_commit "$target_commit") - git rebase -i "$prev_commit" + git rebase -i "$FORGIT_REBASE_GIT_OPTS" "$prev_commit" fi } @@ -394,7 +394,7 @@ _forgit_fixup() { prev_commit=$(_forgit_previous_commit "$target_commit") # rebase will fail if there are unstaged changes so --autostash is needed to temporarily stash them # GIT_SEQUENCE_EDITOR=: is needed to skip the editor - GIT_SEQUENCE_EDITOR=: git rebase --autostash -i --autosquash "$prev_commit" + GIT_SEQUENCE_EDITOR=: git rebase --autostash -i --autosquash "$FORGIT_FIXUP_GIT_OPTS" "$prev_commit" fi } @@ -402,7 +402,7 @@ _forgit_fixup() { # git checkout-file selector _forgit_checkout_file() { _forgit_inside_work_tree || return 1 - [[ $# -ne 0 ]] && { git checkout -- "$@"; return $?; } + [[ $# -ne 0 ]] && { git checkout "$FORGIT_CHECKOUT_FILE_GIT_OPTS" -- "$@"; return $?; } local cmd files opts cmd="git diff --color=always -- {} | $_forgit_diff_pager" opts=" @@ -412,7 +412,7 @@ _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' | git checkout --pathspec-file-nul --pathspec-from-file "$FORGIT_CHECKOUT_FILE_GIT_OPTS" - } # git checkout-branch selector @@ -442,23 +442,24 @@ _forgit_checkout_branch() { branch="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')" [[ -z "$branch" ]] && return 1 + 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" + $git_checkout -b "track/${branch#remotes/origin/}" --track "$branch" + elif ! $git_checkout --track "$branch" 2>/dev/null; then + $git_checkout "$branch" fi else - git checkout "$branch" + $git_checkout "$branch" fi } # git checkout-tag selector _forgit_checkout_tag() { _forgit_inside_work_tree || return 1 - [[ $# -ne 0 ]] && { git checkout "$@"; return $?; } + [[ $# -ne 0 ]] && { git checkout "$FORGIT_CHECKOUT_TAG_GIT_OPTS" "$@"; return $?; } local cmd opts preview cmd="git tag -l --sort=-v:refname" preview="git log {1} $_forgit_log_preview_options" @@ -470,13 +471,13 @@ _forgit_checkout_tag() { " tag="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf)" [[ -z "$tag" ]] && return 1 - git checkout "$tag" + git checkout "$FORGIT_CHECKOUT_TAG_GIT_OPTS" "$tag" } # git checkout-commit selector _forgit_checkout_commit() { _forgit_inside_work_tree || return 1 - [[ $# -ne 0 ]] && { git checkout "$@"; return $?; } + [[ $# -ne 0 ]] && { git checkout "$FORGIT_CHECKOUT_COMMIT_GIT_OPTS" "$@"; return $?; } local cmd opts graph cmd="echo {} | $_forgit_extract_sha |xargs -I% git show --color=always % | $_forgit_show_pager" opts=" @@ -484,11 +485,11 @@ _forgit_checkout_commit() { +s +m --tiebreak=index --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" --preview=\"$cmd\" - $FORGIT_COMMIT_FZF_OPTS + $FORGIT_CHECKOUT_COMMIT_FZF_OPTS " graph=--graph [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= - eval "git log $graph --color=always --format='$_forgit_log_format' $_forgit_emojify" | + eval "git log $graph --color=always --format='$_forgit_log_format' $FORGIT_CHECKOUT_COMMIT_GIT_OPTS $_forgit_emojify" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha" | xargs -I% git checkout % -- } @@ -506,13 +507,13 @@ _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}') - echo -n "$branches" | tr '\n' '\0' | xargs -I{} -0 git branch -D {} + echo -n "$branches" | tr '\n' '\0' | xargs -I{} -0 git branch "$FORGIT_BRANCH_DELETE_GIT_OPTS" -D {} } # git revert-commit selector _forgit_revert_commit() { _forgit_inside_work_tree || return 1 - [[ $# -ne 0 ]] && { git revert "$@"; return $?; } + [[ $# -ne 0 ]] && { git revert "$FORGIT_REVERT_COMMIT_GIT_OPTS" "$@"; return $?; } local cmd opts files preview commits IFS cmd="git log --graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify" @@ -520,7 +521,7 @@ _forgit_revert_commit() { $FORGIT_FZF_DEFAULT_OPTS +s --tiebreak=index --ansi --with-nth 2.. - $FORGIT_REVERT_COMMIT_OPTS + $FORGIT_REVERT_COMMIT_FZF_OPTS " # in this function, we do something interesting to maintain proper ordering as it's assumed @@ -541,13 +542,13 @@ _forgit_revert_commit() { [ ${#commits[@]} -eq 0 ] && return 1 - git revert "${commits[@]}" + git revert "$FORGIT_REVERT_COMMIT_GIT_OPTS" "${commits[@]}" } # git blame viewer _forgit_blame() { _forgit_inside_work_tree || return 1 - [[ $# -ne 0 ]] && git blame "$@" && return 0 + [[ $# -ne 0 ]] && git blame "$FORGIT_BLAME_GIT_OPTS" "$@" && return 0 local opts flags preview file opts=" $FORGIT_FZF_DEFAULT_OPTS @@ -556,14 +557,14 @@ _forgit_blame() { flags=$(git rev-parse --flags "$@") preview=" if $_forgit_is_file_tracked; then - git blame {} --date=short $flags | $_forgit_blame_pager + git blame {} --date=short $FORGIT_BLAME_GIT_OPTS $flags | $_forgit_blame_pager else echo File not tracked fi " file=$(FZF_DEFAULT_OPTS="$opts" fzf --preview="$preview") [[ -z "$file" ]] && return 1 - eval git blame "$file" "$flags" + eval git blame "$FORGIT_BLAME_GIT_OPTS" "$file" "$flags" } # git ignore generator