Feature: add forgit show command

Use the new command in git log enter. This fixes the display of diffs
for merge commits.

Fixes #416.
This commit is contained in:
carlfriedrich 2025-01-04 13:33:57 +01:00
parent df5191157f
commit 580c5cbab0
7 changed files with 86 additions and 1 deletions

View file

@ -101,6 +101,8 @@ Then add the following to your shell's config file:
- **Interactive `git diff` viewer** (`gd`)
- **Interactive `git show` viewer** (`gso`)
- **Interactive `git reset HEAD <file>` selector** (`grh`)
- **Interactive `git checkout <file>` selector** (`gcf`)
@ -172,6 +174,7 @@ You can change the default aliases by defining these variables below.
forgit_log=glo
forgit_reflog=grl
forgit_diff=gd
forgit_show=gso
forgit_add=ga
forgit_reset_head=grh
forgit_ignore=gi
@ -232,6 +235,7 @@ These are passed to the according `git` calls.
| `glo` | `FORGIT_LOG_GIT_OPTS` |
| `grl` | `FORGIT_REFLOG_GIT_OPTS` |
| `gd` | `FORGIT_DIFF_GIT_OPTS` |
| `gso` | `FORGIT_SHOW_GIT_OPTS` |
| `grh` | `FORGIT_RESET_HEAD_GIT_OPTS` |
| `gcf` | `FORGIT_CHECKOUT_FILE_GIT_OPTS` |
| `gcb` | `FORGIT_CHECKOUT_BRANCH_GIT_OPTS`, `FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS` |
@ -286,6 +290,7 @@ Customizing fzf options for each command individually is also supported:
| `grl` | `FORGIT_REFLOG_FZF_OPTS` |
| `gi` | `FORGIT_IGNORE_FZF_OPTS` |
| `gd` | `FORGIT_DIFF_FZF_OPTS` |
| `gso` | `FORGIT_SHOW_FZF_OPTS` |
| `grh` | `FORGIT_RESET_HEAD_FZF_OPTS` |
| `gcf` | `FORGIT_CHECKOUT_FILE_FZF_OPTS` |
| `gcb` | `FORGIT_CHECKOUT_BRANCH_FZF_OPTS` |

View file

@ -185,7 +185,7 @@ _forgit_log_enter() {
local sha
sha=$(echo "$1" | _forgit_extract_sha)
shift
echo "$sha" | xargs -I% "${FORGIT}" diff %^! "$@"
echo "$sha" | xargs -I% "${FORGIT}" show % "$@"
}
# git commit viewer
@ -339,6 +339,68 @@ _forgit_diff() {
return $fzf_exit_code
}
_forgit_exec_show() {
_forgit_show_git_opts=()
_forgit_parse_array _forgit_show_git_opts "$FORGIT_SHOW_GIT_OPTS"
git show --pretty="" --diff-merges=first-parent --color=always "${_forgit_show_git_opts[@]}" "$@"
}
_forgit_show_view() {
local input_line=$1
local diff_context=$2
local commit=$3
local repo
repo=$(git rev-parse --show-toplevel)
cd "$repo" || return 1
echo "$input_line" | _forgit_get_files_from_diff_line | xargs -0 \
"$FORGIT" exec_show "${commit}" -U"$diff_context" -- | _forgit_pager diff
}
_forgit_show_enter() {
file=$1
commit=$2
_forgit_show_view "$file" "$_forgit_fullscreen_context" "${commit}"
}
# git show viewer
_forgit_show() {
_forgit_inside_work_tree || return 1
local files opts commit escaped_commit
files=()
if [[ $# -ne 0 ]]; then
if git rev-parse "$1" -- &>/dev/null ; then
commit="$1" && files=("${@:2}")
else
commit="HEAD" && files=("$@")
fi
else
commit="HEAD"
fi
# Escape opening brackets to support stashes (see comment in _forgit_diff)
escaped_commit=${commit//\{/\\\\\{}
opts="
$FORGIT_FZF_DEFAULT_OPTS
+m -0 --bind=\"enter:execute($FORGIT show_enter {} $escaped_commit | $FORGIT pager enter)\"
--preview=\"$FORGIT show_view {} '$_forgit_preview_context' $escaped_commit\"
--bind=\"alt-e:execute($FORGIT edit_diffed_file {})+refresh-preview\"
$FORGIT_DIFF_FZF_OPTS
--prompt=\"${commit} > \"
"
_forgit_show_git_opts=()
_forgit_parse_array _forgit_show_git_opts "$FORGIT_SHOW_GIT_OPTS"
# Add "^{commit}" suffix after the actual commit. This suppresses the tag information in case it is a tag.
# See: https://git-scm.com/docs/git-show#Documentation/git-show.txt-codegitshow-s--formatsv100commitcode
git show --pretty="" --name-status --diff-merges=first-parent "${_forgit_show_git_opts[@]}" "${commit}^{commit}" \
-- "${files[@]}" |
sed -E 's/^([[:alnum:]]+)[[:space:]]+(.*)$/[\1] \2/' |
sed 's/ / -> /2' | expand -t 8 |
FZF_DEFAULT_OPTS="$opts" fzf
fzf_exit_code=$?
# exit successfully on 130 (ctrl-c/esc)
[[ $fzf_exit_code == 130 ]] && return 0
return $fzf_exit_code
}
_forgit_add_preview() {
file=$(echo "$1" | _forgit_get_single_file_from_add_line)
if (git status -s -- "$file" | grep '^??') &>/dev/null; then # diff with /dev/null for untracked files
@ -1021,6 +1083,7 @@ public_commands=(
"rebase"
"reset_head"
"revert_commit"
"show"
"stash_show"
"stash_push"
)
@ -1035,10 +1098,13 @@ private_commands=(
"cherry_pick_preview"
"clean_preview"
"diff_enter"
"exec_show"
"file_preview"
"ignore_preview"
"revert_preview"
"reset_head_preview"
"show_enter"
"show_view"
"stash_push_preview"
"stash_show_preview"
"yank_sha"

View file

@ -97,6 +97,7 @@ _git-forgit() {
reset_head) _git-staged ;;
revert_commit) __git_recent_commits ;;
stash_show) _git-stash-show ;;
show) _git-show ;;
esac
}
@ -122,6 +123,7 @@ compdef _git-rebase forgit::rebase
compdef _git-staged forgit::reset::head
compdef __git_recent_commits forgit::revert::commit
compdef _git-stash-show forgit::stash::show
compdef _git-show forgit::show
# this is the case of calling the command and pressing tab
# the very first time of a shell session, we have to manually

View file

@ -75,6 +75,7 @@ _git_forgit()
rebase
reset_head
revert_commit
show
stash_show
stash_push
"
@ -101,6 +102,7 @@ _git_forgit()
rebase) _git_rebase ;;
reset_head) _git_reset ;;
revert_commit) _git_revert ;;
show) _git_show ;;
stash_show) _git_stash_show ;;
esac
;;
@ -135,6 +137,7 @@ then
__git_complete forgit::rebase _git_rebase
__git_complete forgit::reset::head _git_reset
__git_complete forgit::revert::commit _git_revert
__git_complete forgit::show _git_show
__git_complete forgit::stash::show _git_stash_show
# Completion for forgit plugin shell aliases
@ -154,6 +157,7 @@ then
__git_complete "${forgit_rebase}" _git_rebase
__git_complete "${forgit_reset_head}" _git_reset
__git_complete "${forgit_revert_commit}" _git_revert
__git_complete "${forgit_show}" _git_show
__git_complete "${forgit_stash_show}" _git_stash_show
fi
fi

View file

@ -40,6 +40,7 @@ complete -c git-forgit -n __fish_forgit_needs_subcommand -a reflog -d 'git reflo
complete -c git-forgit -n __fish_forgit_needs_subcommand -a rebase -d 'git rebase'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a reset_head -d 'git reset HEAD (unstage) selector'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a revert_commit -d 'git revert commit selector'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a show -d 'git show viewer'
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'

View file

@ -37,6 +37,7 @@ if test -z "$FORGIT_NO_ALIASES"
abbr -a -- (string collect $forgit_log; or string collect "glo") git-forgit log
abbr -a -- (string collect $forgit_reflog; or string collect "grl") git-forgit reflog
abbr -a -- (string collect $forgit_diff; or string collect "gd") git-forgit diff
abbr -a -- (string collect $forgit_show; or string collect "gso") git-forgit show
abbr -a -- (string collect $forgit_ignore; or string collect "gi") git-forgit ignore
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

View file

@ -53,6 +53,10 @@ forgit::diff() {
"$FORGIT" diff "$@"
}
forgit::show() {
"$FORGIT" show "$@"
}
forgit::add() {
"$FORGIT" add "$@"
}
@ -146,6 +150,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
export forgit_log="${forgit_log:-glo}"
export forgit_reflog="${forgit_reflog:-grl}"
export forgit_diff="${forgit_diff:-gd}"
export forgit_show="${forgit_show:-gso}"
export forgit_ignore="${forgit_ignore:-gi}"
export forgit_checkout_file="${forgit_checkout_file:-gcf}"
export forgit_checkout_branch="${forgit_checkout_branch:-gcb}"
@ -166,6 +171,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
alias "${forgit_log}"='forgit::log'
alias "${forgit_reflog}"='forgit::reflog'
alias "${forgit_diff}"='forgit::diff'
alias "${forgit_show}"='forgit::show'
alias "${forgit_ignore}"='forgit::ignore'
alias "${forgit_checkout_file}"='forgit::checkout::file'
alias "${forgit_checkout_branch}"='forgit::checkout::branch'