Skip to content

Commit

Permalink
Add git options for each forgit command (#292)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
carlfriedrich committed Mar 18, 2023
1 parent f32fd30 commit 2a2ee36
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 35 deletions.
32 changes: 29 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:

Expand Down Expand Up @@ -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`,
Expand Down Expand Up @@ -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` |
Expand Down
65 changes: 33 additions & 32 deletions bin/git-forgit
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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="
Expand All @@ -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=$?
Expand All @@ -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)
Expand Down Expand Up @@ -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.'
}

Expand All @@ -201,15 +201,15 @@ _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.'
}

# git stash viewer
_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)\"
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.'
}

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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
}

Expand All @@ -394,15 +394,15 @@ _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

}

# 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="
Expand All @@ -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
Expand Down Expand Up @@ -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"
Expand All @@ -470,25 +471,25 @@ _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="
$FORGIT_FZF_DEFAULT_OPTS
+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 % --
}

Expand All @@ -506,21 +507,21 @@ _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"
opts="
$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
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 2a2ee36

Please sign in to comment.