diff --git a/conf.d/forgit.plugin.fish b/conf.d/forgit.plugin.fish index 4a98d02..c8b9203 100644 --- a/conf.d/forgit.plugin.fish +++ b/conf.d/forgit.plugin.fish @@ -21,6 +21,15 @@ function forgit::reverse_lines end end +function forgit::previous_commit + # "SHA~" is invalid when the commit is the first commit, but we can use "--root" instead + if test (git rev-parse $argv) = (git rev-list --max-parents=0 HEAD) + echo "--root" + else + echo "$argv~" + end +end + # extract the first git sha occuring in the input and strip trailing newline set -g forgit_extract_sha "grep -Eo '[a-f0-9]+' | head -1 | tr -d '[:space:]'" @@ -399,11 +408,7 @@ function forgit::fixup -d "git fixup" set target_commit (eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") if test -n "$target_commit" && git commit --fixup "$target_commit" - # "$target_commit~" is invalid when the commit is the first commit, but we can use "--root" instead - set prev_commit "$target_commit~" - if test "(git rev-parse '$target_commit')" = "(git rev-list --max-parents=0 HEAD)" - set prev_commit "--root" - end + set prev_commit (forgit::previous_commit $target_commit) GIT_SEQUENCE_EDITOR=: git rebase --autostash -i --autosquash "$prev_commit" end @@ -437,10 +442,12 @@ function forgit::rebase -d "git rebase" --preview=\"$preview\" $FORGIT_REBASE_FZF_OPTS " - set commit (eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") + set target_commit (eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") - if test $commit - git rebase -i "$commit" + if test $target_commit + set prev_commit (forgit::previous_commit $target_commit) + + git rebase -i "$prev_commit" end end diff --git a/forgit.plugin.zsh b/forgit.plugin.zsh index 55556fa..9e0e301 100755 --- a/forgit.plugin.zsh +++ b/forgit.plugin.zsh @@ -6,6 +6,15 @@ forgit::inside_work_tree() { git rev-parse --is-inside-work-tree >/dev/null; } # tac is not available on OSX, tail -r is not available on Linux, so we use either of them forgit::reverse_lines() { tac 2> /dev/null || tail -r; } +forgit::previous_commit() { + # "SHA~" is invalid when the commit is the first commit, but we can use "--root" instead + if [[ "$(git rev-parse "$1")" == "$(git rev-list --max-parents=0 HEAD)" ]]; then + echo "--root" + else + echo "$1~" + fi +} + # optional render emoji characters (https://github.com/wfxr/emoji-cli) hash emojify &>/dev/null && forgit_emojify='|emojify' @@ -177,7 +186,7 @@ forgit::cherry::pick() { forgit::rebase() { forgit::inside_work_tree || return 1 - local cmd preview opts graph files commit + local cmd preview opts graph files target_commit prev_commit graph=--graph [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= cmd="git log $graph --color=always --format='$forgit_log_format' $* $forgit_emojify" @@ -190,8 +199,12 @@ forgit::rebase() { --preview=\"$preview\" $FORGIT_REBASE_FZF_OPTS " - commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") - [[ -n "$commit" ]] && git rebase -i "$commit" + target_commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") + if [[ -n "$target_commit" ]]; then + prev_commit=$(forgit::previous_commit $target_commit) + + git rebase -i "$prev_commit" + fi } forgit::fixup() { @@ -212,12 +225,7 @@ forgit::fixup() { " target_commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") if [[ -n "$target_commit" ]] && git commit --fixup "$target_commit"; then - # "$target_commit~" is invalid when the commit is the first commit, but we can use "--root" instead - if [[ "$(git rev-parse "$target_commit")" == "$(git rev-list --max-parents=0 HEAD)" ]]; then - prev_commit="--root" - else - prev_commit="$target_commit~" - fi + 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"