git rebase -i: add static check for commands and SHA-1

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>

Galan Rémi committed Jun 29, 2015 at 22:20 UTC 804098bb30a5339cccb0be981a3e876245aa0ae5
3 files changed +116
git-rebase--interactive.sh
+72
@@ -846,6 +846,71 @@ add_exec_commands () {
846 mv "$1.new" "$1"
847 }
848
849 +# Check if the SHA-1 passed as an argument is a
850 +# correct one, if not then print $2 in "$todo".badsha
851 +# $1: the SHA-1 to test
852 +# $2: the line to display if incorrect SHA-1
853 +check_commit_sha () {
854 + badsha=0
855 + if test -z $1
856 + then
857 + badsha=1
858 + else
859 + sha1_verif="$(git rev-parse --verify --quiet $1^{commit})"
860 + if test -z $sha1_verif
861 + then
862 + badsha=1
863 + fi
864 + fi
865 +
866 + if test $badsha -ne 0
867 + then
868 + warn "Warning: the SHA-1 is missing or isn't" \
869 + "a commit in the following line:"
870 + warn " - $2"
871 + warn
872 + fi
873 +
874 + return $badsha
875 +}
876 +
877 +# prints the bad commits and bad commands
878 +# from the todolist in stdin
879 +check_bad_cmd_and_sha () {
880 + retval=0
881 + git stripspace --strip-comments |
882 + (
883 + while read -r line
884 + do
885 + IFS=' '
886 + set -- $line
887 + command=$1
888 + sha1=$2
889 +
890 + case $command in
891 + ''|noop|x|"exec")
892 + # Doesn't expect a SHA-1
893 + ;;
894 + pick|p|drop|d|reword|r|edit|e|squash|s|fixup|f)
895 + if ! check_commit_sha $sha1 "$line"
896 + then
897 + retval=1
898 + fi
899 + ;;
900 + *)
901 + warn "Warning: the command isn't recognized" \
902 + "in the following line:"
903 + warn " - $line"
904 + warn
905 + retval=1
906 + ;;
907 + esac
908 + done
909 +
910 + return $retval
911 + )
912 +}
913 +
914 # Print the list of the SHA-1 of the commits
915 # from stdin to stdout
916 todo_list_to_sha_list () {
@@ -887,6 +952,8 @@ get_missing_commit_check_level () {
952
953 # Check if the user dropped some commits by mistake
954 # Behaviour determined by rebase.missingCommitsCheck.
955 +# Check if there is an unrecognized command or a
956 +# bad SHA-1 in a command.
957 check_todo_list () {
958 raise_error=f
959
@@ -935,6 +1002,11 @@ check_todo_list () {
1002 ;;
1003 esac
1004
1005 + if ! check_bad_cmd_and_sha <"$todo"
1006 + then
1007 + raise_error=t
1008 + fi
1009 +
1010 if test $raise_error = t
1011 then
1012 # Checkout before the first commit of the
t/lib-rebase.sh
+5
@@ -54,6 +54,11 @@ set_fake_editor () {
54 echo '# comment' >> "$1";;
55 ">")
56 echo >> "$1";;
57 + bad)
58 + action="badcmd";;
59 + fakesha)
60 + echo "$action XXXXXXX False commit" >> "$1"
61 + action=pick;;
62 *)
63 sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
64 action=pick;;
t/t3404-rebase-interactive.sh
+39
@@ -1186,4 +1186,43 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' '
1186 test B = $(git cat-file commit HEAD^ | sed -ne \$p)
1187 '
1188
1189 +cat >expect <<EOF
1190 +Warning: the command isn't recognized in the following line:
1191 + - badcmd $(git rev-list --oneline -1 master~1)
1192 +
1193 +You can fix this with 'git rebase --edit-todo'.
1194 +Or you can abort the rebase with 'git rebase --abort'.
1195 +EOF
1196 +
1197 +test_expect_success 'static check of bad command' '
1198 + rebase_setup_and_clean bad-cmd &&
1199 + set_fake_editor &&
1200 + test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \
1201 + git rebase -i --root 2>actual &&
1202 + test_cmp expect actual &&
1203 + FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo &&
1204 + git rebase --continue &&
1205 + test E = $(git cat-file commit HEAD | sed -ne \$p) &&
1206 + test C = $(git cat-file commit HEAD^ | sed -ne \$p)
1207 +'
1208 +
1209 +cat >expect <<EOF
1210 +Warning: the SHA-1 is missing or isn't a commit in the following line:
1211 + - edit XXXXXXX False commit
1212 +
1213 +You can fix this with 'git rebase --edit-todo'.
1214 +Or you can abort the rebase with 'git rebase --abort'.
1215 +EOF
1216 +
1217 +test_expect_success 'static check of bad SHA-1' '
1218 + rebase_setup_and_clean bad-sha &&
1219 + set_fake_editor &&
1220 + test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \
1221 + git rebase -i --root 2>actual &&
1222 + test_cmp expect actual &&
1223 + FAKE_LINES="1 2 4 5 6" git rebase --edit-todo &&
1224 + git rebase --continue &&
1225 + test E = $(git cat-file commit HEAD | sed -ne \$p)
1226 +'
1227 +
1228 test_done