From d7dddb473abf5612615e9aac9e4a029a7eeda1b5 Mon Sep 17 00:00:00 2001 From: carlfriedrich Date: Wed, 1 Jan 2025 14:32:19 +0100 Subject: [PATCH] Feature: add forgit show command Use the new command in git log enter. This fixes the display of diffs for merge commits. Fixes #416. --- README.md | 5 +++ bin/git-forgit | 65 ++++++++++++++++++++++++++++++++++++- completions/_git-forgit | 2 ++ completions/git-forgit.bash | 4 +++ completions/git-forgit.fish | 1 + conf.d/forgit.plugin.fish | 1 + forgit.plugin.zsh | 6 ++++ 7 files changed, 83 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e7729ca..a5805fa2 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,8 @@ Then add the following to your shell's config file: - **Interactive `git diff` viewer** (`gd`) +- **Interactive `git show` viewer** (`gs`) + - **Interactive `git reset HEAD ` selector** (`grh`) - **Interactive `git checkout ` 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=gs 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` | +| `gs` | `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` | +| `gs` | `FORGIT_SHOW_FZF_OPTS` | | `grh` | `FORGIT_RESET_HEAD_FZF_OPTS` | | `gcf` | `FORGIT_CHECKOUT_FILE_FZF_OPTS` | | `gcb` | `FORGIT_CHECKOUT_BRANCH_FZF_OPTS` | diff --git a/bin/git-forgit b/bin/git-forgit index 07cbfd33..fb613dcc 100755 --- a/bin/git-forgit +++ b/bin/git-forgit @@ -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,65 @@ _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" + git show --pretty="" --name-status --diff-merges=first-parent "${_forgit_show_git_opts[@]}" "${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 +1080,7 @@ public_commands=( "rebase" "reset_head" "revert_commit" + "show" "stash_show" "stash_push" ) @@ -1035,10 +1095,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" diff --git a/completions/_git-forgit b/completions/_git-forgit index b26e4dbf..00218f2c 100644 --- a/completions/_git-forgit +++ b/completions/_git-forgit @@ -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 diff --git a/completions/git-forgit.bash b/completions/git-forgit.bash index 80a443f0..380fc4b0 100755 --- a/completions/git-forgit.bash +++ b/completions/git-forgit.bash @@ -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 diff --git a/completions/git-forgit.fish b/completions/git-forgit.fish index 72c896ba..2b9d5037 100644 --- a/completions/git-forgit.fish +++ b/completions/git-forgit.fish @@ -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' diff --git a/conf.d/forgit.plugin.fish b/conf.d/forgit.plugin.fish index 18761d04..6dc94e54 100644 --- a/conf.d/forgit.plugin.fish +++ b/conf.d/forgit.plugin.fish @@ -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 "gs") 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 diff --git a/forgit.plugin.zsh b/forgit.plugin.zsh index b6d4a5ed..8d2b3c77 100755 --- a/forgit.plugin.zsh +++ b/forgit.plugin.zsh @@ -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:-gs}" 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'