Merge branch 'gr/rebase-i-drop-warn'
authorJunio C Hamano <gitster@pobox.com>
Mon, 3 Aug 2015 18:01:22 +0000 (11:01 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 3 Aug 2015 18:01:22 +0000 (11:01 -0700)
Add "drop commit-object-name subject" command as another way to
skip replaying of a commit in "rebase -i", and then punish those
who do not use it (and instead just remove the lines) by throwing
a warning.

* gr/rebase-i-drop-warn:
  git rebase -i: add static check for commands and SHA-1
  git rebase -i: warn about removed commits
  git-rebase -i: add command "drop" to remove a commit

1  2 
Documentation/config.txt
Documentation/git-rebase.txt
git-rebase--interactive.sh
t/t3404-rebase-interactive.sh

@@@ -2180,11 -2160,17 +2180,22 @@@ rebase.autoStash:
        successful rebase might result in non-trivial conflicts.
        Defaults to false.
  
+ rebase.missingCommitsCheck::
+       If set to "warn", git rebase -i will print a warning if some
+       commits are removed (e.g. a line was deleted), however the
+       rebase will still proceed. If set to "error", it will print
+       the previous warning and stop the rebase, 'git rebase
+       --edit-todo' can then be used to correct the error. If set to
+       "ignore", no checking is done.
+       To drop a commit without warning or error, use the `drop`
+       command in the todo-list.
+       Defaults to "ignore".
 +rebase.instructionFormat
 +      A format string, as specified in linkgit:git-log[1], to be used for
 +      the instruction list during an interactive rebase.  The format will automatically
 +      have the long commit hash prepended to the format.
 +
  receive.advertiseAtomic::
        By default, git-receive-pack will advertise the atomic push
        capability to its clients. If you don't want to this capability
@@@ -213,9 -213,12 +213,15 @@@ rebase.autoSquash:
  rebase.autoStash::
        If set to true enable '--autostash' option by default.
  
+ rebase.missingCommitsCheck::
+       If set to "warn", print warnings about removed commits in
+       interactive mode. If set to "error", print the warnings and
+       stop the rebase. If set to "ignore", no checking is
+       done. "ignore" by default.
 +rebase.instructionFormat::
 +      Custom commit list format to use during an '--interactive' rebase.
 +
  OPTIONS
  -------
  --onto <newbase>::
@@@ -502,10 -512,10 +512,10 @@@ do_pick () 
  }
  
  do_next () {
 -      rm -f "$msg" "$author_script" "$amend" || exit
 +      rm -f "$msg" "$author_script" "$amend" "$state_dir"/stopped-sha || exit
        read -r command sha1 rest < "$todo"
        case "$command" in
-       "$comment_char"*|''|noop)
+       "$comment_char"*|''|noop|drop|d)
                mark_action_done
                ;;
        pick|p)
@@@ -1102,25 -1102,127 +1102,148 @@@ test_expect_success 'rebase -i commits 
        test $(git cat-file commit HEAD | sed -ne \$p) = I
  '
  
 +test_expect_success 'rebase --continue removes CHERRY_PICK_HEAD' '
 +      git checkout -b commit-to-skip &&
 +      for double in X 3 1
 +      do
 +              test_seq 5 | sed "s/$double/&&/" >seq &&
 +              git add seq &&
 +              test_tick &&
 +              git commit -m seq-$double
 +      done &&
 +      git tag seq-onto &&
 +      git reset --hard HEAD~2 &&
 +      git cherry-pick seq-onto &&
 +      set_fake_editor &&
 +      test_must_fail env FAKE_LINES= git rebase -i seq-onto &&
 +      test -d .git/rebase-merge &&
 +      git rebase --continue &&
 +      git diff --exit-code seq-onto &&
 +      test ! -d .git/rebase-merge &&
 +      test ! -f .git/CHERRY_PICK_HEAD
 +'
 +
+ rebase_setup_and_clean () {
+       test_when_finished "
+               git checkout master &&
+               test_might_fail git branch -D $1 &&
+               test_might_fail git rebase --abort
+       " &&
+       git checkout -b $1 master
+ }
+ test_expect_success 'drop' '
+       rebase_setup_and_clean drop-test &&
+       set_fake_editor &&
+       FAKE_LINES="1 drop 2 3 drop 4 5" git rebase -i --root &&
+       test E = $(git cat-file commit HEAD | sed -ne \$p) &&
+       test C = $(git cat-file commit HEAD^ | sed -ne \$p) &&
+       test A = $(git cat-file commit HEAD^^ | sed -ne \$p)
+ '
+ cat >expect <<EOF
+ Successfully rebased and updated refs/heads/missing-commit.
+ EOF
+ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' '
+       test_config rebase.missingCommitsCheck ignore &&
+       rebase_setup_and_clean missing-commit &&
+       set_fake_editor &&
+       FAKE_LINES="1 2 3 4" \
+               git rebase -i --root 2>actual &&
+       test D = $(git cat-file commit HEAD | sed -ne \$p) &&
+       test_cmp expect actual
+ '
+ cat >expect <<EOF
+ Warning: some commits may have been dropped accidentally.
+ Dropped commits (newer to older):
+  - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
+ To avoid this message, use "drop" to explicitly remove a commit.
+ Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
+ The possible behaviours are: ignore, warn, error.
+ Successfully rebased and updated refs/heads/missing-commit.
+ EOF
+ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' '
+       test_config rebase.missingCommitsCheck warn &&
+       rebase_setup_and_clean missing-commit &&
+       set_fake_editor &&
+       FAKE_LINES="1 2 3 4" \
+               git rebase -i --root 2>actual &&
+       test_cmp expect actual &&
+       test D = $(git cat-file commit HEAD | sed -ne \$p)
+ '
+ cat >expect <<EOF
+ Warning: some commits may have been dropped accidentally.
+ Dropped commits (newer to older):
+  - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
+  - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2)
+ To avoid this message, use "drop" to explicitly remove a commit.
+ Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
+ The possible behaviours are: ignore, warn, error.
+ You can fix this with 'git rebase --edit-todo'.
+ Or you can abort the rebase with 'git rebase --abort'.
+ EOF
+ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' '
+       test_config rebase.missingCommitsCheck error &&
+       rebase_setup_and_clean missing-commit &&
+       set_fake_editor &&
+       test_must_fail env FAKE_LINES="1 2 4" \
+               git rebase -i --root 2>actual &&
+       test_cmp expect actual &&
+       cp .git/rebase-merge/git-rebase-todo.backup \
+               .git/rebase-merge/git-rebase-todo &&
+       FAKE_LINES="1 2 drop 3 4 drop 5" \
+               git rebase --edit-todo &&
+       git rebase --continue &&
+       test D = $(git cat-file commit HEAD | sed -ne \$p) &&
+       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