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