Check before the start of the rebasing if the commands exists, and for
the commands expecting a SHA-1, check if the SHA-1 is present and
corresponds to a commit. In case of error, print the error, stop git
rebase and prompt the user to fix with 'git rebase --edit-todo' or to
abort.

This allows to avoid doing half of a rebase before finding an error
and giving back what's left of the todo list to the user and prompt
him to fix when it might be too late for him to do so (he might have
to abort and restart the rebase).

Signed-off-by: Galan Rémi <remi.galan-alfo...@ensimag.grenoble-inp.fr>
---
 I used:
   read -r command sha1 rest <<EOF
   $line
   EOF
 because
   printf '%s' "$line" | read -r command sha1 rest
 doesn't work (the 3 variables have no value as a result).
 There might be a better way to do this, but I don't have it right now.

 git-rebase--interactive.sh    | 70 +++++++++++++++++++++++++++++++++++++++++++
 t/lib-rebase.sh               |  5 ++++
 t/t3404-rebase-interactive.sh | 40 +++++++++++++++++++++++++
 3 files changed, 115 insertions(+)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 66daacf..6381686 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -834,6 +834,52 @@ add_exec_commands () {
        mv "$1.new" "$1"
 }
 
+# Check if the SHA-1 passed as an argument is a
+# correct one, if not then print $2 in "$todo".badsha
+# $1: the SHA-1 to test
+# $2: the line to display if incorrect SHA-1
+check_commit_sha () {
+       badsha=f
+       if test -z $1
+       then
+               badsha=t
+       else
+               sha1_verif="$(git rev-parse --verify --quiet $1^{commit})"
+               if test -z $sha1_verif
+               then
+                       badsha=t
+               fi
+       fi
+
+       if test $badsha = t
+       then
+               printf '%s\n' "$2" >>"$todo".badsha
+       fi
+}
+
+# prints the bad commits and bad commands
+# from the todolist in stdin
+check_bad_cmd_and_sha () {
+       git stripspace --strip-comments |
+       while read -r line
+       do
+               read -r command sha1 rest <<EOF
+$line
+EOF
+               case $command in
+               ''|noop|x|"exec")
+                       # Doesn't expect a SHA-1
+                       ;;
+               pick|p|drop|d|reword|r|edit|e|squash|s|fixup|f)
+                       check_commit_sha $sha1 "$line"
+                       ;;
+               *)
+                       printf '%s\n' "$line" >>"$todo".badcmd
+                       ;;
+               esac
+       done
+}
+
 # Print the list of the SHA-1 of the commits
 # from stdin to stdout
 todo_list_to_sha_list () {
@@ -868,6 +914,8 @@ checkout_onto () {
 
 # Check if the user dropped some commits by mistake
 # Behaviour determined by rebase.missingCommitsCheck.
+# Check if there is an unrecognized command or a
+# bad SHA-1 in a command.
 check_todo_list () {
        raise_error=f
 
@@ -919,6 +967,28 @@ check_todo_list () {
                ;;
        esac
 
+       check_bad_cmd_and_sha <"$todo"
+
+       if test -s "$todo".badsha
+       then
+               raise_error=t
+
+               warn "Warning: the SHA-1 is missing or isn't" \
+                       "a commit in the following line(s):"
+               warn_lines <"$todo".badsha
+               warn
+       fi
+
+       if test -s "$todo".badcmd
+       then
+               raise_error=t
+
+               warn "Warning: the command isn't recognized" \
+                       "in the following line(s):"
+               warn_lines <"$todo".badcmd
+               warn
+       fi
+
        if test $raise_error = t
        then
                # Checkout before the first commit of the
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index fdbc900..9a96e15 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -54,6 +54,11 @@ set_fake_editor () {
                        echo '# comment' >> "$1";;
                ">")
                        echo >> "$1";;
+               bad)
+                       action="badcmd";;
+               fakesha)
+                       echo "$action XXXXXXX False commit" >> "$1"
+                       action=pick;;
                *)
                        sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
                        action=pick;;
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index a92ae19..d691b1c 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1184,4 +1184,44 @@ test_expect_success 'rebase -i respects 
rebase.missingCommitsCheck = error' '
        test B = $(git cat-file commit HEAD^ | sed -ne \$p)
 '
 
+cat >expect <<EOF
+Warning: the command isn't recognized in the following line(s):
+ - badcmd $(git rev-list --oneline -1 master~1)
+
+You can fix this with 'git rebase --edit-todo'.
+Or you can abort the rebase with 'git rebase --abort'.
+EOF
+
+test_expect_success 'static check of bad command' '
+       test_rebase_end tmp2 &&
+       set_fake_editor &&
+       test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \
+               git rebase -i --root 2>actual &&
+       test_cmp expect actual &&
+       FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo &&
+       git rebase --continue &&
+       test E = $(git cat-file commit HEAD | sed -ne \$p) &&
+       test C = $(git cat-file commit HEAD^ | sed -ne \$p)
+'
+
+cat >expect <<EOF
+Warning: the SHA-1 is missing or isn't a commit in the following line(s):
+ - edit XXXXXXX False commit
+
+You can fix this with 'git rebase --edit-todo'.
+Or you can abort the rebase with 'git rebase --abort'.
+EOF
+
+test_expect_success 'static check of bad SHA-1' '
+       test_config rebase.missingCommitsCheck error &&
+       test_rebase_end tmp2 &&
+       set_fake_editor &&
+       test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \
+               git rebase -i --root 2>actual &&
+       test_cmp expect actual &&
+       FAKE_LINES="1 2 4 5 6" git rebase --edit-todo &&
+       git rebase --continue &&
+       test E = $(git cat-file commit HEAD | sed -ne \$p)
+'
+
 test_done
-- 
2.4.3.371.g8992f2a

--
To unsubscribe from this list: send the line "unsubscribe git" in

Reply via email to