git rebase -i: add static check for commands and SHA-1
authorGalan Rémi <remi.galan-alfonso@ensimag.grenoble-inp.fr>
Mon, 29 Jun 2015 20:20:32 +0000 (22:20 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Jun 2015 19:14:25 +0000 (12:14 -0700)
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-alfonso@ensimag.grenoble-inp.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-rebase--interactive.sh
t/lib-rebase.sh
t/t3404-rebase-interactive.sh
index c26a200a6c0e7edd2b182b71af50df52179d295f..dcc3401b5a8c45fd9c5ba474416eb4a6c3c9a29e 100644 (file)
@@ -846,6 +846,71 @@ 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=0
+       if test -z $1
+       then
+               badsha=1
+       else
+               sha1_verif="$(git rev-parse --verify --quiet $1^{commit})"
+               if test -z $sha1_verif
+               then
+                       badsha=1
+               fi
+       fi
+
+       if test $badsha -ne 0
+       then
+               warn "Warning: the SHA-1 is missing or isn't" \
+                       "a commit in the following line:"
+               warn " - $2"
+               warn
+       fi
+
+       return $badsha
+}
+
+# prints the bad commits and bad commands
+# from the todolist in stdin
+check_bad_cmd_and_sha () {
+       retval=0
+       git stripspace --strip-comments |
+       (
+               while read -r line
+               do
+                       IFS=' '
+                       set -- $line
+                       command=$1
+                       sha1=$2
+
+                       case $command in
+                       ''|noop|x|"exec")
+                               # Doesn't expect a SHA-1
+                               ;;
+                       pick|p|drop|d|reword|r|edit|e|squash|s|fixup|f)
+                               if ! check_commit_sha $sha1 "$line"
+                               then
+                                       retval=1
+                               fi
+                               ;;
+                       *)
+                               warn "Warning: the command isn't recognized" \
+                                       "in the following line:"
+                               warn " - $line"
+                               warn
+                               retval=1
+                               ;;
+                       esac
+               done
+
+               return $retval
+       )
+}
+
 # Print the list of the SHA-1 of the commits
 # from stdin to stdout
 todo_list_to_sha_list () {
@@ -887,6 +952,8 @@ get_missing_commit_check_level () {
 
 # 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
 
@@ -935,6 +1002,11 @@ check_todo_list () {
                ;;
        esac
 
+       if ! check_bad_cmd_and_sha <"$todo"
+       then
+               raise_error=t
+       fi
+
        if test $raise_error = t
        then
                # Checkout before the first commit of the
index fdbc9007d07e8dfe06a7459f40bde69e6bd94bd7..9a96e1566d016e960f79875eb4edba2ffb7c5244 100644 (file)
@@ -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;;
index cfa741018d59678171502945e86a8f368b511d41..ebdab4b95d0bfb4c91295f1461f9bd51bd76cf15 100755 (executable)
@@ -1186,4 +1186,43 @@ 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:
+ - 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' '
+       rebase_setup_and_clean bad-cmd &&
+       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:
+ - 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' '
+       rebase_setup_and_clean bad-sha &&
+       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