From 5a117b63cdadcb069c4624771aef6325e98eb7d6 Mon Sep 17 00:00:00 2001 From: Chris Apple <14171107+cjappl@users.noreply.github.com> Date: Fri, 16 Dec 2022 07:50:28 -0700 Subject: [PATCH] Ensure that `grc` and `gcp` always have the correct ordering, regardless of how they were input (#261) (#253) Closes #253. Essentially the idea is this: When cherry picking a group of commits, most of the time you want to cherry pick oldest to newest. This means you have the lowest chance of having a conflict or error when reverting a commit. You most often want to revert from newest to oldest. Similarly prevents errors This commit does that, based on the wonderful suggestion on how to do that from @carlfriedrich in the linked ticket (#253). --- bin/git-forgit | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/bin/git-forgit b/bin/git-forgit index 48e0a35..760747f 100755 --- a/bin/git-forgit +++ b/bin/git-forgit @@ -262,20 +262,30 @@ _forgit_clean() { _forgit_cherry_pick() { local base target preview opts fzf_selection fzf_exitval + base=$(git branch --show-current) + [[ -z "$base" ]] && echo "Current commit is not on a branch." && return 1 + [[ -z $1 ]] && echo "Please specify target branch" && return 1 target="$1" - preview="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always % | $_forgit_show_pager" + + # in this function, we do something interesting to maintain proper ordering as it's assumed + # you generally want to cherry pick oldest->newest when you multiselect + # The instances of "cut", "nl" and "sort" all serve this purpose + # Please see https://github.com/wfxr/forgit/issues/253 for more details + + preview="echo {} | cut -f2- | $_forgit_extract_sha | xargs -I% git show --color=always % | $_forgit_show_pager" opts=" $FORGIT_FZF_DEFAULT_OPTS --preview=\"$preview\" - -m -0 --tiebreak=index + --multi --ansi --with-nth 2.. -0 --tiebreak=index $FORGIT_CHERRY_PICK_FZF_OPTS " - fzf_selection=$(git cherry "$base" "$target" --abbrev -v | _forgit_reverse_lines | - FZF_DEFAULT_OPTS="$opts" fzf) + fzf_selection=$(git cherry "$base" "$target" --abbrev -v | nl | _forgit_reverse_lines | + FZF_DEFAULT_OPTS="$opts" fzf | sort --numeric-sort --key=1 --reverse | cut -f2-) fzf_exitval=$? [[ $fzf_exitval != 0 ]] && return $fzf_exitval + [[ -z "$fzf_selection" ]] && return $fzf_exitval commits=() while IFS="" read -r line @@ -283,6 +293,8 @@ _forgit_cherry_pick() { commits+=("$line") done < <(echo "$fzf_selection" | _forgit_reverse_lines | cut -d' ' -f2) + [ ${#commits[@]} -eq 0 ] && return 1 + git cherry-pick "${commits[@]}" } @@ -484,23 +496,35 @@ _forgit_branch_delete() { _forgit_revert_commit() { _forgit_inside_work_tree || return 1 [[ $# -ne 0 ]] && { git revert "$@"; 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 " + + # in this function, we do something interesting to maintain proper ordering as it's assumed + # you generally want to revert newest->oldest when you multiselect + # The instances of "cut", "nl" and "sort" all serve this purpose + # Please see https://github.com/wfxr/forgit/issues/253 for more details + files=$(sed -nE 's/.* -- (.*)/\1/p' <<< "$*") # extract files parameters for `git show` command - preview="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" + preview="echo {} | cut -f2- | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" + # shellcheck disable=2207 - IFS=$'\n' commits=($(eval "$cmd" | - FZF_DEFAULT_OPTS="$opts" fzf --preview="$preview" -m | + IFS=$'\n' commits=($(eval "$cmd" | + nl | + FZF_DEFAULT_OPTS="$opts" fzf --preview="$preview" -m | + sort --numeric-sort --key=1 | + cut -f2- | sed 's/^[^a-f^0-9]*\([a-f0-9]*\).*/\1/')) + [ ${#commits[@]} -eq 0 ] && return 1 - for commit in "${commits[@]}"; do - git revert "$commit" - done + + git revert "${commits[@]}" } # git blame viewer