1#!/bin/sh
   2test_description='prepare-commit-msg hook'
   4. ./test-lib.sh
   6test_expect_success 'set up commits for rebasing' '
   8        test_commit root &&
   9        test_commit a a a &&
  10        test_commit b b b &&
  11        git checkout -b rebase-me root &&
  12        test_commit rebase-a a aa &&
  13        test_commit rebase-b b bb &&
  14        for i in $(test_seq 1 13)
  15        do
  16                test_commit rebase-$i c $i
  17        done &&
  18        git checkout master &&
  19        cat >rebase-todo <<-EOF
  21        pick $(git rev-parse rebase-a)
  22        pick $(git rev-parse rebase-b)
  23        fixup $(git rev-parse rebase-1)
  24        fixup $(git rev-parse rebase-2)
  25        pick $(git rev-parse rebase-3)
  26        fixup $(git rev-parse rebase-4)
  27        squash $(git rev-parse rebase-5)
  28        reword $(git rev-parse rebase-6)
  29        squash $(git rev-parse rebase-7)
  30        fixup $(git rev-parse rebase-8)
  31        fixup $(git rev-parse rebase-9)
  32        edit $(git rev-parse rebase-10)
  33        squash $(git rev-parse rebase-11)
  34        squash $(git rev-parse rebase-12)
  35        edit $(git rev-parse rebase-13)
  36        EOF
  37'
  38test_expect_success 'with no hook' '
  40        echo "foo" > file &&
  42        git add file &&
  43        git commit -m "first"
  44'
  46# set up fake editor for interactive editing
  48cat > fake-editor <<'EOF'
  49#!/bin/sh
  50exit 0
  51EOF
  52chmod +x fake-editor
  53## Not using test_set_editor here so we can easily ensure the editor variable
  55## is only set for the editor tests
  56FAKE_EDITOR="$(pwd)/fake-editor"
  57export FAKE_EDITOR
  58# now install hook that always succeeds and adds a message
  60HOOKDIR="$(git rev-parse --git-dir)/hooks"
  61HOOK="$HOOKDIR/prepare-commit-msg"
  62mkdir -p "$HOOKDIR"
  63echo "#!$SHELL_PATH" > "$HOOK"
  64cat >> "$HOOK" <<'EOF'
  65GIT_DIR=$(git rev-parse --git-dir)
  67if test -d "$GIT_DIR/rebase-merge"
  68then
  69        rebasing=1
  70else
  71        rebasing=0
  72fi
  73get_last_cmd () {
  75        tail -n1 "$GIT_DIR/rebase-merge/done" | {
  76                read cmd id _
  77                git log --pretty="[$cmd %s]" -n1 $id
  78        }
  79}
  80if test "$2" = commit
  82then
  83        if test $rebasing = 1
  84        then
  85                source="$3"
  86        else
  87                source=$(git rev-parse "$3")
  88        fi
  89else
  90        source=${2-default}
  91fi
  92test "$GIT_EDITOR" = : && source="$source (no editor)"
  93if test $rebasing = 1
  95then
  96        echo "$source $(get_last_cmd)" >"$1"
  97else
  98        sed -e "1s/.*/$source/" "$1" >msg.tmp
  99        mv msg.tmp "$1"
 100fi
 101exit 0
 102EOF
 103chmod +x "$HOOK"
 104echo dummy template > "$(git rev-parse --git-dir)/template"
 106test_expect_success 'with hook (-m)' '
 108        echo "more" >> file &&
 110        git add file &&
 111        git commit -m "more" &&
 112        test "$(git log -1 --pretty=format:%s)" = "message (no editor)"
 113'
 115test_expect_success 'with hook (-m editor)' '
 117        echo "more" >> file &&
 119        git add file &&
 120        GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -m "more more" &&
 121        test "$(git log -1 --pretty=format:%s)" = message
 122'
 124test_expect_success 'with hook (-t)' '
 126        echo "more" >> file &&
 128        git add file &&
 129        git commit -t "$(git rev-parse --git-dir)/template" &&
 130        test "$(git log -1 --pretty=format:%s)" = template
 131'
 133test_expect_success 'with hook (-F)' '
 135        echo "more" >> file &&
 137        git add file &&
 138        (echo more | git commit -F -) &&
 139        test "$(git log -1 --pretty=format:%s)" = "message (no editor)"
 140'
 142test_expect_success 'with hook (-F editor)' '
 144        echo "more" >> file &&
 146        git add file &&
 147        (echo more more | GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -F -) &&
 148        test "$(git log -1 --pretty=format:%s)" = message
 149'
 151test_expect_success 'with hook (-C)' '
 153        head=$(git rev-parse HEAD) &&
 155        echo "more" >> file &&
 156        git add file &&
 157        git commit -C $head &&
 158        test "$(git log -1 --pretty=format:%s)" = "$head (no editor)"
 159'
 161test_expect_success 'with hook (editor)' '
 163        echo "more more" >> file &&
 165        git add file &&
 166        GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 167        test "$(git log -1 --pretty=format:%s)" = default
 168'
 170test_expect_success 'with hook (--amend)' '
 172        head=$(git rev-parse HEAD) &&
 174        echo "more" >> file &&
 175        git add file &&
 176        GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --amend &&
 177        test "$(git log -1 --pretty=format:%s)" = "$head"
 178'
 180test_expect_success 'with hook (-c)' '
 182        head=$(git rev-parse HEAD) &&
 184        echo "more" >> file &&
 185        git add file &&
 186        GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head &&
 187        test "$(git log -1 --pretty=format:%s)" = "$head"
 188'
 190test_expect_success 'with hook (merge)' '
 192        test_when_finished "git checkout -f master" &&
 194        git checkout -B other HEAD@{1} &&
 195        echo "more" >>file &&
 196        git add file &&
 197        git commit -m other &&
 198        git checkout - &&
 199        git merge --no-ff other &&
 200        test "$(git log -1 --pretty=format:%s)" = "merge (no editor)"
 201'
 202test_expect_success 'with hook and editor (merge)' '
 204        test_when_finished "git checkout -f master" &&
 206        git checkout -B other HEAD@{1} &&
 207        echo "more" >>file &&
 208        git add file &&
 209        git commit -m other &&
 210        git checkout - &&
 211        env GIT_EDITOR="\"\$FAKE_EDITOR\"" git merge --no-ff -e other &&
 212        test "$(git log -1 --pretty=format:%s)" = "merge"
 213'
 214test_rebase () {
 216        expect=$1 &&
 217        mode=$2 &&
 218        test_expect_$expect C_LOCALE_OUTPUT "with hook (rebase $mode)" '
 219                test_when_finished "\
 220                        git rebase --abort
 221                        git checkout -f master
 222                        git branch -D tmp" &&
 223                git checkout -b tmp rebase-me &&
 224                GIT_SEQUENCE_EDITOR="cp rebase-todo" &&
 225                GIT_EDITOR="\"$FAKE_EDITOR\"" &&
 226                (
 227                        export GIT_SEQUENCE_EDITOR GIT_EDITOR &&
 228                        test_must_fail git rebase $mode b &&
 229                        echo x >a &&
 230                        git add a &&
 231                        test_must_fail git rebase --continue &&
 232                        echo x >b &&
 233                        git add b &&
 234                        git commit &&
 235                        git rebase --continue &&
 236                        echo y >a &&
 237                        git add a &&
 238                        git commit &&
 239                        git rebase --continue &&
 240                        echo y >b &&
 241                        git add b &&
 242                        git rebase --continue
 243                ) &&
 244                if test $mode = -p # reword amended after pick
 245                then
 246                        n=18
 247                else
 248                        n=17
 249                fi &&
 250                git log --pretty=%s -g -n$n HEAD@{1} >actual &&
 251                test_cmp "$TEST_DIRECTORY/t7505/expected-rebase$mode" actual
 252        '
 253}
 254test_rebase success -i
 256test_have_prereq !REBASE_P || test_rebase success -p
 257test_expect_success 'with hook (cherry-pick)' '
 259        test_when_finished "git checkout -f master" &&
 260        git checkout -B other b &&
 261        git cherry-pick rebase-1 &&
 262        test "$(git log -1 --pretty=format:%s)" = "message (no editor)"
 263'
 264test_expect_success 'with hook and editor (cherry-pick)' '
 266        test_when_finished "git checkout -f master" &&
 267        git checkout -B other b &&
 268        git cherry-pick -e rebase-1 &&
 269        test "$(git log -1 --pretty=format:%s)" = merge
 270'
 271cat > "$HOOK" <<'EOF'
 273#!/bin/sh
 274exit 1
 275EOF
 276test_expect_success 'with failing hook' '
 278        test_when_finished "git checkout -f master" &&
 280        head=$(git rev-parse HEAD) &&
 281        echo "more" >> file &&
 282        git add file &&
 283        test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head
 284'
 286test_expect_success 'with failing hook (--no-verify)' '
 288        test_when_finished "git checkout -f master" &&
 290        head=$(git rev-parse HEAD) &&
 291        echo "more" >> file &&
 292        git add file &&
 293        test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head
 294'
 296test_expect_success 'with failing hook (merge)' '
 298        test_when_finished "git checkout -f master" &&
 300        git checkout -B other HEAD@{1} &&
 301        echo "more" >> file &&
 302        git add file &&
 303        rm -f "$HOOK" &&
 304        git commit -m other &&
 305        write_script "$HOOK" <<-EOF &&
 306        exit 1
 307        EOF
 308        git checkout - &&
 309        test_must_fail git merge --no-ff other
 310'
 312test_expect_success C_LOCALE_OUTPUT 'with failing hook (cherry-pick)' '
 314        test_when_finished "git checkout -f master" &&
 315        git checkout -B other b &&
 316        test_must_fail git cherry-pick rebase-1 2>actual &&
 317        test $(grep -c prepare-commit-msg actual) = 1
 318'
 319test_done