t / t3311-notes-merge-fanout.shon commit merge-octopus: abort if index does not match HEAD (3ec62ad)
   1#!/bin/sh
   2#
   3# Copyright (c) 2010 Johan Herland
   4#
   5
   6test_description='Test notes merging at various fanout levels'
   7
   8. ./test-lib.sh
   9
  10verify_notes () {
  11        notes_ref="$1"
  12        commit="$2"
  13        if test -f "expect_notes_$notes_ref"
  14        then
  15                git -c core.notesRef="refs/notes/$notes_ref" notes |
  16                        sort >"output_notes_$notes_ref" &&
  17                test_cmp "expect_notes_$notes_ref" "output_notes_$notes_ref" ||
  18                        return 1
  19        fi &&
  20        git -c core.notesRef="refs/notes/$notes_ref" log --format="%H %s%n%N" \
  21                "$commit" >"output_log_$notes_ref" &&
  22        test_cmp "expect_log_$notes_ref" "output_log_$notes_ref"
  23}
  24
  25verify_fanout () {
  26        notes_ref="$1"
  27        # Expect entire notes tree to have a fanout == 1
  28        git rev-parse --quiet --verify "refs/notes/$notes_ref" >/dev/null &&
  29        git ls-tree -r --name-only "refs/notes/$notes_ref" |
  30        while read path
  31        do
  32                case "$path" in
  33                ??/??????????????????????????????????????)
  34                        : true
  35                        ;;
  36                *)
  37                        echo "Invalid path \"$path\"" &&
  38                        return 1
  39                        ;;
  40                esac
  41        done
  42}
  43
  44verify_no_fanout () {
  45        notes_ref="$1"
  46        # Expect entire notes tree to have a fanout == 0
  47        git rev-parse --quiet --verify "refs/notes/$notes_ref" >/dev/null &&
  48        git ls-tree -r --name-only "refs/notes/$notes_ref" |
  49        while read path
  50        do
  51                case "$path" in
  52                ????????????????????????????????????????)
  53                        : true
  54                        ;;
  55                *)
  56                        echo "Invalid path \"$path\"" &&
  57                        return 1
  58                        ;;
  59                esac
  60        done
  61}
  62
  63# Set up a notes merge scenario with different kinds of conflicts
  64test_expect_success 'setup a few initial commits with notes (notes ref: x)' '
  65        git config core.notesRef refs/notes/x &&
  66        for i in 1 2 3 4 5
  67        do
  68                test_commit "commit$i" >/dev/null &&
  69                git notes add -m "notes for commit$i" || return 1
  70        done
  71'
  72
  73commit_sha1=$(git rev-parse commit1^{commit})
  74commit_sha2=$(git rev-parse commit2^{commit})
  75commit_sha3=$(git rev-parse commit3^{commit})
  76commit_sha4=$(git rev-parse commit4^{commit})
  77commit_sha5=$(git rev-parse commit5^{commit})
  78
  79cat <<EOF | sort >expect_notes_x
  80aed91155c7a72c2188e781fdf40e0f3761b299db $commit_sha5
  8199fab268f9d7ee7b011e091a436c78def8eeee69 $commit_sha4
  82953c20ae26c7aa0b428c20693fe38bc687f9d1a9 $commit_sha3
  836358796131b8916eaa2dde6902642942a1cb37e1 $commit_sha2
  84b02d459c32f0e68f2fe0981033bb34f38776ba47 $commit_sha1
  85EOF
  86
  87cat >expect_log_x <<EOF
  88$commit_sha5 commit5
  89notes for commit5
  90
  91$commit_sha4 commit4
  92notes for commit4
  93
  94$commit_sha3 commit3
  95notes for commit3
  96
  97$commit_sha2 commit2
  98notes for commit2
  99
 100$commit_sha1 commit1
 101notes for commit1
 102
 103EOF
 104
 105test_expect_success 'sanity check (x)' '
 106        verify_notes x commit5 &&
 107        verify_no_fanout x
 108'
 109
 110num=300
 111
 112cp expect_log_x expect_log_y
 113
 114test_expect_success 'Add a few hundred commits w/notes to trigger fanout (x -> y)' '
 115        git update-ref refs/notes/y refs/notes/x &&
 116        git config core.notesRef refs/notes/y &&
 117        i=5 &&
 118        while test $i -lt $num
 119        do
 120                i=$(($i + 1)) &&
 121                test_commit "commit$i" >/dev/null &&
 122                git notes add -m "notes for commit$i" || return 1
 123        done &&
 124        test "$(git rev-parse refs/notes/y)" != "$(git rev-parse refs/notes/x)" &&
 125        # Expected number of commits and notes
 126        test $(git rev-list HEAD | wc -l) = $num &&
 127        test $(git notes list | wc -l) = $num &&
 128        # 5 first notes unchanged
 129        verify_notes y commit5
 130'
 131
 132test_expect_success 'notes tree has fanout (y)' 'verify_fanout y'
 133
 134test_expect_success 'No-op merge (already included) (x => y)' '
 135        git update-ref refs/notes/m refs/notes/y &&
 136        git config core.notesRef refs/notes/m &&
 137        git notes merge x &&
 138        test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/y)"
 139'
 140
 141test_expect_success 'Fast-forward merge (y => x)' '
 142        git update-ref refs/notes/m refs/notes/x &&
 143        git notes merge y &&
 144        test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/y)"
 145'
 146
 147cat <<EOF | sort >expect_notes_z
 1489f506ee70e20379d7f78204c77b334f43d77410d $commit_sha3
 14923a47d6ea7d589895faf800752054818e1e7627b $commit_sha2
 150b02d459c32f0e68f2fe0981033bb34f38776ba47 $commit_sha1
 151EOF
 152
 153cat >expect_log_z <<EOF
 154$commit_sha5 commit5
 155
 156$commit_sha4 commit4
 157
 158$commit_sha3 commit3
 159notes for commit3
 160
 161appended notes for commit3
 162
 163$commit_sha2 commit2
 164new notes for commit2
 165
 166$commit_sha1 commit1
 167notes for commit1
 168
 169EOF
 170
 171test_expect_success 'change some of the initial 5 notes (x -> z)' '
 172        git update-ref refs/notes/z refs/notes/x &&
 173        git config core.notesRef refs/notes/z &&
 174        git notes add -f -m "new notes for commit2" commit2 &&
 175        git notes append -m "appended notes for commit3" commit3 &&
 176        git notes remove commit4 &&
 177        git notes remove commit5 &&
 178        verify_notes z commit5
 179'
 180
 181test_expect_success 'notes tree has no fanout (z)' 'verify_no_fanout z'
 182
 183cp expect_log_z expect_log_m
 184
 185test_expect_success 'successful merge without conflicts (y => z)' '
 186        git update-ref refs/notes/m refs/notes/z &&
 187        git config core.notesRef refs/notes/m &&
 188        git notes merge y &&
 189        verify_notes m commit5 &&
 190        # x/y/z unchanged
 191        verify_notes x commit5 &&
 192        verify_notes y commit5 &&
 193        verify_notes z commit5
 194'
 195
 196test_expect_success 'notes tree still has fanout after merge (m)' 'verify_fanout m'
 197
 198cat >expect_log_w <<EOF
 199$commit_sha5 commit5
 200
 201$commit_sha4 commit4
 202other notes for commit4
 203
 204$commit_sha3 commit3
 205other notes for commit3
 206
 207$commit_sha2 commit2
 208notes for commit2
 209
 210$commit_sha1 commit1
 211other notes for commit1
 212
 213EOF
 214
 215test_expect_success 'introduce conflicting changes (y -> w)' '
 216        git update-ref refs/notes/w refs/notes/y &&
 217        git config core.notesRef refs/notes/w &&
 218        git notes add -f -m "other notes for commit1" commit1 &&
 219        git notes add -f -m "other notes for commit3" commit3 &&
 220        git notes add -f -m "other notes for commit4" commit4 &&
 221        git notes remove commit5 &&
 222        verify_notes w commit5
 223'
 224
 225cat >expect_log_m <<EOF
 226$commit_sha5 commit5
 227
 228$commit_sha4 commit4
 229other notes for commit4
 230
 231$commit_sha3 commit3
 232other notes for commit3
 233
 234$commit_sha2 commit2
 235new notes for commit2
 236
 237$commit_sha1 commit1
 238other notes for commit1
 239
 240EOF
 241
 242test_expect_success 'successful merge using "ours" strategy (z => w)' '
 243        git update-ref refs/notes/m refs/notes/w &&
 244        git config core.notesRef refs/notes/m &&
 245        git notes merge -s ours z &&
 246        verify_notes m commit5 &&
 247        # w/x/y/z unchanged
 248        verify_notes w commit5 &&
 249        verify_notes x commit5 &&
 250        verify_notes y commit5 &&
 251        verify_notes z commit5
 252'
 253
 254test_expect_success 'notes tree still has fanout after merge (m)' 'verify_fanout m'
 255
 256cat >expect_log_m <<EOF
 257$commit_sha5 commit5
 258
 259$commit_sha4 commit4
 260
 261$commit_sha3 commit3
 262notes for commit3
 263
 264appended notes for commit3
 265
 266$commit_sha2 commit2
 267new notes for commit2
 268
 269$commit_sha1 commit1
 270other notes for commit1
 271
 272EOF
 273
 274test_expect_success 'successful merge using "theirs" strategy (z => w)' '
 275        git update-ref refs/notes/m refs/notes/w &&
 276        git notes merge -s theirs z &&
 277        verify_notes m commit5 &&
 278        # w/x/y/z unchanged
 279        verify_notes w commit5 &&
 280        verify_notes x commit5 &&
 281        verify_notes y commit5 &&
 282        verify_notes z commit5
 283'
 284
 285test_expect_success 'notes tree still has fanout after merge (m)' 'verify_fanout m'
 286
 287cat >expect_log_m <<EOF
 288$commit_sha5 commit5
 289
 290$commit_sha4 commit4
 291other notes for commit4
 292
 293$commit_sha3 commit3
 294other notes for commit3
 295
 296notes for commit3
 297
 298appended notes for commit3
 299
 300$commit_sha2 commit2
 301new notes for commit2
 302
 303$commit_sha1 commit1
 304other notes for commit1
 305
 306EOF
 307
 308test_expect_success 'successful merge using "union" strategy (z => w)' '
 309        git update-ref refs/notes/m refs/notes/w &&
 310        git notes merge -s union z &&
 311        verify_notes m commit5 &&
 312        # w/x/y/z unchanged
 313        verify_notes w commit5 &&
 314        verify_notes x commit5 &&
 315        verify_notes y commit5 &&
 316        verify_notes z commit5
 317'
 318
 319test_expect_success 'notes tree still has fanout after merge (m)' 'verify_fanout m'
 320
 321cat >expect_log_m <<EOF
 322$commit_sha5 commit5
 323
 324$commit_sha4 commit4
 325other notes for commit4
 326
 327$commit_sha3 commit3
 328appended notes for commit3
 329notes for commit3
 330other notes for commit3
 331
 332$commit_sha2 commit2
 333new notes for commit2
 334
 335$commit_sha1 commit1
 336other notes for commit1
 337
 338EOF
 339
 340test_expect_success 'successful merge using "cat_sort_uniq" strategy (z => w)' '
 341        git update-ref refs/notes/m refs/notes/w &&
 342        git notes merge -s cat_sort_uniq z &&
 343        verify_notes m commit5 &&
 344        # w/x/y/z unchanged
 345        verify_notes w commit5 &&
 346        verify_notes x commit5 &&
 347        verify_notes y commit5 &&
 348        verify_notes z commit5
 349'
 350
 351test_expect_success 'notes tree still has fanout after merge (m)' 'verify_fanout m'
 352
 353# We're merging z into w. Here are the conflicts we expect:
 354#
 355# commit | x -> w    | x -> z    | conflict?
 356# -------|-----------|-----------|----------
 357# 1      | changed   | unchanged | no, use w
 358# 2      | unchanged | changed   | no, use z
 359# 3      | changed   | changed   | yes (w, then z in conflict markers)
 360# 4      | changed   | deleted   | yes (w)
 361# 5      | deleted   | deleted   | no, deleted
 362
 363test_expect_success 'fails to merge using "manual" strategy (z => w)' '
 364        git update-ref refs/notes/m refs/notes/w &&
 365        test_must_fail git notes merge z
 366'
 367
 368test_expect_success 'notes tree still has fanout after merge (m)' 'verify_fanout m'
 369
 370cat <<EOF | sort >expect_conflicts
 371$commit_sha3
 372$commit_sha4
 373EOF
 374
 375cat >expect_conflict_$commit_sha3 <<EOF
 376<<<<<<< refs/notes/m
 377other notes for commit3
 378=======
 379notes for commit3
 380
 381appended notes for commit3
 382>>>>>>> refs/notes/z
 383EOF
 384
 385cat >expect_conflict_$commit_sha4 <<EOF
 386other notes for commit4
 387EOF
 388
 389test_expect_success 'verify conflict entries (with no fanout)' '
 390        ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
 391        test_cmp expect_conflicts output_conflicts &&
 392        ( for f in $(cat expect_conflicts); do
 393                test_cmp "expect_conflict_$f" ".git/NOTES_MERGE_WORKTREE/$f" ||
 394                exit 1
 395        done ) &&
 396        # Verify that current notes tree (pre-merge) has not changed (m == w)
 397        test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)"
 398'
 399
 400cat >expect_log_m <<EOF
 401$commit_sha5 commit5
 402
 403$commit_sha4 commit4
 404other notes for commit4
 405
 406$commit_sha3 commit3
 407other notes for commit3
 408
 409appended notes for commit3
 410
 411$commit_sha2 commit2
 412new notes for commit2
 413
 414$commit_sha1 commit1
 415other notes for commit1
 416
 417EOF
 418
 419test_expect_success 'resolve and finalize merge (z => w)' '
 420        cat >.git/NOTES_MERGE_WORKTREE/$commit_sha3 <<EOF &&
 421other notes for commit3
 422
 423appended notes for commit3
 424EOF
 425        git notes merge --commit &&
 426        verify_notes m commit5 &&
 427        # w/x/y/z unchanged
 428        verify_notes w commit5 &&
 429        verify_notes x commit5 &&
 430        verify_notes y commit5 &&
 431        verify_notes z commit5
 432'
 433
 434test_expect_success 'notes tree still has fanout after merge (m)' 'verify_fanout m'
 435
 436test_done