From d343300625927dc5c2ed1ed0d13eeef8388ad681 Mon Sep 17 00:00:00 2001 From: carlfriedrich Date: Fri, 22 Jul 2022 14:41:38 +0200 Subject: [PATCH 1/2] grb: rebase on parent of the selected commit The git rebase command needs to be passed the parent commit of the one you want to edit. When selecting a commit interactively via fzf, it makes sense to automatically pass the parent commit of the selected one. Within fzf it's otherwise quite hard to find the parent commit by hand if you have found your commit via an fzf search string. --- conf.d/forgit.plugin.fish | 12 +++++++++--- forgit.plugin.zsh | 14 +++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/conf.d/forgit.plugin.fish b/conf.d/forgit.plugin.fish index 4a98d02..ab4dda4 100644 --- a/conf.d/forgit.plugin.fish +++ b/conf.d/forgit.plugin.fish @@ -437,10 +437,16 @@ 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 + # "$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 + + git rebase -i "$prev_commit" end end diff --git a/forgit.plugin.zsh b/forgit.plugin.zsh index 55556fa..606c23b 100755 --- a/forgit.plugin.zsh +++ b/forgit.plugin.zsh @@ -177,7 +177,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 +190,16 @@ 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 + # "$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 + git rebase -i "$prev_commit" + fi } forgit::fixup() { From 126772f08c6a44339a878aa0c6336e54dcb864ab Mon Sep 17 00:00:00 2001 From: carlfriedrich Date: Thu, 28 Jul 2022 10:16:22 +0200 Subject: [PATCH 2/2] Add function forgit::previous_commit --- conf.d/forgit.plugin.fish | 21 +++++++++++---------- forgit.plugin.zsh | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/conf.d/forgit.plugin.fish b/conf.d/forgit.plugin.fish index ab4dda4..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 @@ -440,11 +445,7 @@ function forgit::rebase -d "git rebase" set target_commit (eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") if test $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 rebase -i "$prev_commit" end diff --git a/forgit.plugin.zsh b/forgit.plugin.zsh index 606c23b..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' @@ -192,12 +201,8 @@ forgit::rebase() { " target_commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$forgit_extract_sha") if [[ -n "$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) + git rebase -i "$prev_commit" fi } @@ -220,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"