t / t1001-read-tree-m-2way.shon commit t4000: make hash size independent (8cc5ff8)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Junio C Hamano
   4#
   5
   6test_description='Two way merge with read-tree -m $H $M
   7
   8This test tries two-way merge (aka fast-forward with carry forward).
   9
  10There is the head (called H) and another commit (called M), which is
  11simply ahead of H.  The index and the work tree contains a state that
  12is derived from H, but may also have local changes.  This test checks
  13all the combinations described in the two-tree merge "carry forward"
  14rules, found in <Documentation/git read-tree.txt>.
  15
  16In the test, these paths are used:
  17        bozbar  - in H, stays in M, modified from bozbar to gnusto
  18        frotz   - not in H added in M
  19        nitfol  - in H, stays in M unmodified
  20        rezrov  - in H, deleted in M
  21        yomin   - not in H or M
  22'
  23. ./test-lib.sh
  24. "$TEST_DIRECTORY"/lib-read-tree.sh
  25
  26read_tree_twoway () {
  27    git read-tree -m "$1" "$2" && git ls-files --stage
  28}
  29
  30compare_change () {
  31        sed -n >current \
  32            -e '/^--- /d; /^+++ /d; /^@@ /d;' \
  33            -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$OID_REGEX"' /\1 X /p' \
  34            "$1"
  35        test_cmp expected current
  36}
  37
  38check_cache_at () {
  39        clean_if_empty=$(git diff-files -- "$1")
  40        case "$clean_if_empty" in
  41        '')  echo "$1: clean" ;;
  42        ?*)  echo "$1: dirty" ;;
  43        esac
  44        case "$2,$clean_if_empty" in
  45        clean,)         :     ;;
  46        clean,?*)       false ;;
  47        dirty,)         false ;;
  48        dirty,?*)       :     ;;
  49        esac
  50}
  51
  52cat >bozbar-old <<\EOF
  53This is a sample file used in two-way fast-forward merge
  54tests.  Its second line ends with a magic word bozbar
  55which will be modified by the merged head to gnusto.
  56It has some extra lines so that external tools can
  57successfully merge independent changes made to later
  58lines (such as this one), avoiding line conflicts.
  59EOF
  60
  61sed -e 's/bozbar/gnusto (earlier bozbar)/' bozbar-old >bozbar-new
  62
  63test_expect_success 'setup' '
  64        echo frotz >frotz &&
  65        echo nitfol >nitfol &&
  66        cat bozbar-old >bozbar &&
  67        echo rezrov >rezrov &&
  68        echo yomin >yomin &&
  69        git update-index --add nitfol bozbar rezrov &&
  70        treeH=$(git write-tree) &&
  71        echo treeH $treeH &&
  72        git ls-tree $treeH &&
  73
  74        cat bozbar-new >bozbar &&
  75        git update-index --add frotz bozbar --force-remove rezrov &&
  76        git ls-files --stage >M.out &&
  77        treeM=$(git write-tree) &&
  78        echo treeM $treeM &&
  79        git ls-tree $treeM &&
  80        git diff-tree $treeH $treeM
  81'
  82
  83test_expect_success '1, 2, 3 - no carry forward' '
  84        rm -f .git/index &&
  85        read_tree_twoway $treeH $treeM &&
  86        git ls-files --stage >1-3.out &&
  87        test_cmp M.out 1-3.out &&
  88        check_cache_at bozbar dirty &&
  89        check_cache_at frotz dirty &&
  90        check_cache_at nitfol dirty
  91'
  92echo '+100644 X 0       yomin' >expected
  93
  94test_expect_success '4 - carry forward local addition.' '
  95        rm -f .git/index &&
  96        read_tree_must_succeed $treeH &&
  97        git checkout-index -u -f -q -a &&
  98        git update-index --add yomin &&
  99        read_tree_twoway $treeH $treeM &&
 100        git ls-files --stage >4.out &&
 101        test_must_fail git diff --no-index M.out 4.out >4diff.out &&
 102        compare_change 4diff.out expected &&
 103        check_cache_at yomin clean
 104'
 105
 106test_expect_success '5 - carry forward local addition.' '
 107        rm -f .git/index &&
 108        read_tree_must_succeed $treeH &&
 109        git checkout-index -u -f -q -a &&
 110        echo yomin >yomin &&
 111        git update-index --add yomin &&
 112        echo yomin yomin >yomin &&
 113        read_tree_twoway $treeH $treeM &&
 114        git ls-files --stage >5.out &&
 115        test_must_fail git diff --no-index M.out 5.out >5diff.out &&
 116        compare_change 5diff.out expected &&
 117        check_cache_at yomin dirty
 118'
 119
 120test_expect_success '6 - local addition already has the same.' '
 121        rm -f .git/index &&
 122        read_tree_must_succeed $treeH &&
 123        git checkout-index -u -f -q -a &&
 124        git update-index --add frotz &&
 125        read_tree_twoway $treeH $treeM &&
 126        git ls-files --stage >6.out &&
 127        test_cmp M.out 6.out &&
 128        check_cache_at frotz clean
 129'
 130
 131test_expect_success '7 - local addition already has the same.' '
 132        rm -f .git/index &&
 133        read_tree_must_succeed $treeH &&
 134        git checkout-index -u -f -q -a &&
 135        echo frotz >frotz &&
 136        git update-index --add frotz &&
 137        echo frotz frotz >frotz &&
 138        read_tree_twoway $treeH $treeM &&
 139        git ls-files --stage >7.out &&
 140        test_cmp M.out 7.out &&
 141        check_cache_at frotz dirty
 142'
 143
 144test_expect_success '8 - conflicting addition.' '
 145        rm -f .git/index &&
 146        read_tree_must_succeed $treeH &&
 147        git checkout-index -u -f -q -a &&
 148        echo frotz frotz >frotz &&
 149        git update-index --add frotz &&
 150        if read_tree_twoway $treeH $treeM; then false; else :; fi
 151'
 152
 153test_expect_success '9 - conflicting addition.' '
 154        rm -f .git/index &&
 155        read_tree_must_succeed $treeH &&
 156        git checkout-index -u -f -q -a &&
 157        echo frotz frotz >frotz &&
 158        git update-index --add frotz &&
 159        echo frotz >frotz &&
 160        if read_tree_twoway $treeH $treeM; then false; else :; fi
 161'
 162
 163test_expect_success '10 - path removed.' '
 164        rm -f .git/index &&
 165        read_tree_must_succeed $treeH &&
 166        git checkout-index -u -f -q -a &&
 167        echo rezrov >rezrov &&
 168        git update-index --add rezrov &&
 169        read_tree_twoway $treeH $treeM &&
 170        git ls-files --stage >10.out &&
 171        test_cmp M.out 10.out
 172'
 173
 174test_expect_success '11 - dirty path removed.' '
 175        rm -f .git/index &&
 176        read_tree_must_succeed $treeH &&
 177        git checkout-index -u -f -q -a &&
 178        echo rezrov >rezrov &&
 179        git update-index --add rezrov &&
 180        echo rezrov rezrov >rezrov &&
 181        if read_tree_twoway $treeH $treeM; then false; else :; fi
 182'
 183
 184test_expect_success '12 - unmatching local changes being removed.' '
 185        rm -f .git/index &&
 186        read_tree_must_succeed $treeH &&
 187        git checkout-index -u -f -q -a &&
 188        echo rezrov rezrov >rezrov &&
 189        git update-index --add rezrov &&
 190        if read_tree_twoway $treeH $treeM; then false; else :; fi
 191'
 192
 193test_expect_success '13 - unmatching local changes being removed.' '
 194        rm -f .git/index &&
 195        read_tree_must_succeed $treeH &&
 196        git checkout-index -u -f -q -a &&
 197        echo rezrov rezrov >rezrov &&
 198        git update-index --add rezrov &&
 199        echo rezrov >rezrov &&
 200        if read_tree_twoway $treeH $treeM; then false; else :; fi
 201'
 202
 203cat >expected <<EOF
 204-100644 X 0     nitfol
 205+100644 X 0     nitfol
 206EOF
 207
 208test_expect_success '14 - unchanged in two heads.' '
 209        rm -f .git/index &&
 210        read_tree_must_succeed $treeH &&
 211        git checkout-index -u -f -q -a &&
 212        echo nitfol nitfol >nitfol &&
 213        git update-index --add nitfol &&
 214        read_tree_twoway $treeH $treeM &&
 215        git ls-files --stage >14.out &&
 216        test_must_fail git diff --no-index M.out 14.out >14diff.out &&
 217        compare_change 14diff.out expected &&
 218        check_cache_at nitfol clean
 219'
 220
 221test_expect_success '15 - unchanged in two heads.' '
 222        rm -f .git/index &&
 223        read_tree_must_succeed $treeH &&
 224        git checkout-index -u -f -q -a &&
 225        echo nitfol nitfol >nitfol &&
 226        git update-index --add nitfol &&
 227        echo nitfol nitfol nitfol >nitfol &&
 228        read_tree_twoway $treeH $treeM &&
 229        git ls-files --stage >15.out &&
 230        test_must_fail git diff --no-index M.out 15.out >15diff.out &&
 231        compare_change 15diff.out expected &&
 232        check_cache_at nitfol dirty
 233'
 234
 235test_expect_success '16 - conflicting local change.' '
 236        rm -f .git/index &&
 237        read_tree_must_succeed $treeH &&
 238        git checkout-index -u -f -q -a &&
 239        echo bozbar bozbar >bozbar &&
 240        git update-index --add bozbar &&
 241        if read_tree_twoway $treeH $treeM; then false; else :; fi
 242'
 243
 244test_expect_success '17 - conflicting local change.' '
 245        rm -f .git/index &&
 246        read_tree_must_succeed $treeH &&
 247        git checkout-index -u -f -q -a &&
 248        echo bozbar bozbar >bozbar &&
 249        git update-index --add bozbar &&
 250        echo bozbar bozbar bozbar >bozbar &&
 251        if read_tree_twoway $treeH $treeM; then false; else :; fi
 252'
 253
 254test_expect_success '18 - local change already having a good result.' '
 255        rm -f .git/index &&
 256        read_tree_must_succeed $treeH &&
 257        git checkout-index -u -f -q -a &&
 258        cat bozbar-new >bozbar &&
 259        git update-index --add bozbar &&
 260        read_tree_twoway $treeH $treeM &&
 261        git ls-files --stage >18.out &&
 262        test_cmp M.out 18.out &&
 263        check_cache_at bozbar clean
 264'
 265
 266test_expect_success '19 - local change already having a good result, further modified.' '
 267        rm -f .git/index &&
 268        read_tree_must_succeed $treeH &&
 269        git checkout-index -u -f -q -a &&
 270        cat bozbar-new >bozbar &&
 271        git update-index --add bozbar &&
 272        echo gnusto gnusto >bozbar &&
 273        read_tree_twoway $treeH $treeM &&
 274        git ls-files --stage >19.out &&
 275        test_cmp M.out 19.out &&
 276        check_cache_at bozbar dirty
 277'
 278
 279test_expect_success '20 - no local change, use new tree.' '
 280        rm -f .git/index &&
 281        read_tree_must_succeed $treeH &&
 282        git checkout-index -u -f -q -a &&
 283        cat bozbar-old >bozbar &&
 284        git update-index --add bozbar &&
 285        read_tree_twoway $treeH $treeM &&
 286        git ls-files --stage >20.out &&
 287        test_cmp M.out 20.out &&
 288        check_cache_at bozbar dirty
 289'
 290
 291test_expect_success '21 - no local change, dirty cache.' '
 292        rm -f .git/index &&
 293        read_tree_must_succeed $treeH &&
 294        git checkout-index -u -f -q -a &&
 295        cat bozbar-old >bozbar &&
 296        git update-index --add bozbar &&
 297        echo gnusto gnusto >bozbar &&
 298        if read_tree_twoway $treeH $treeM; then false; else :; fi
 299'
 300
 301# This fails with straight two-way fast-forward.
 302test_expect_success '22 - local change cache updated.' '
 303        rm -f .git/index &&
 304        read_tree_must_succeed $treeH &&
 305        git checkout-index -u -f -q -a &&
 306        sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
 307        git update-index --add bozbar &&
 308        if read_tree_twoway $treeH $treeM; then false; else :; fi
 309'
 310
 311# Also make sure we did not break DF vs DF/DF case.
 312test_expect_success 'DF vs DF/DF case setup.' '
 313        rm -f .git/index &&
 314        echo DF >DF &&
 315        git update-index --add DF &&
 316        treeDF=$(git write-tree) &&
 317        echo treeDF $treeDF &&
 318        git ls-tree $treeDF &&
 319
 320        rm -f DF &&
 321        mkdir DF &&
 322        echo DF/DF >DF/DF &&
 323        git update-index --add --remove DF DF/DF &&
 324        treeDFDF=$(git write-tree) &&
 325        echo treeDFDF $treeDFDF &&
 326        git ls-tree $treeDFDF &&
 327        git ls-files --stage >DFDF.out
 328'
 329
 330test_expect_success 'DF vs DF/DF case test.' '
 331        rm -f .git/index &&
 332        rm -fr DF &&
 333        echo DF >DF &&
 334        git update-index --add DF &&
 335        read_tree_twoway $treeDF $treeDFDF &&
 336        git ls-files --stage >DFDFcheck.out &&
 337        test_cmp DFDF.out DFDFcheck.out &&
 338        check_cache_at DF/DF dirty &&
 339        :
 340'
 341
 342test_expect_success 'a/b (untracked) vs a case setup.' '
 343        rm -f .git/index &&
 344        : >a &&
 345        git update-index --add a &&
 346        treeM=$(git write-tree) &&
 347        echo treeM $treeM &&
 348        git ls-tree $treeM &&
 349        git ls-files --stage >treeM.out &&
 350
 351        rm -f a &&
 352        git update-index --remove a &&
 353        mkdir a &&
 354        : >a/b &&
 355        treeH=$(git write-tree) &&
 356        echo treeH $treeH &&
 357        git ls-tree $treeH
 358'
 359
 360test_expect_success 'a/b (untracked) vs a, plus c/d case test.' '
 361        read_tree_u_must_fail -u -m "$treeH" "$treeM" &&
 362        git ls-files --stage &&
 363        test -f a/b
 364'
 365
 366test_expect_success 'read-tree supports the super-prefix' '
 367        cat <<-EOF >expect &&
 368                error: Updating '\''fictional/a'\'' would lose untracked files in it
 369        EOF
 370        test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
 371        test_cmp expect actual
 372'
 373
 374test_expect_success 'a/b vs a, plus c/d case setup.' '
 375        rm -f .git/index &&
 376        rm -fr a &&
 377        : >a &&
 378        mkdir c &&
 379        : >c/d &&
 380        git update-index --add a c/d &&
 381        treeM=$(git write-tree) &&
 382        echo treeM $treeM &&
 383        git ls-tree $treeM &&
 384        git ls-files --stage >treeM.out &&
 385
 386        rm -f a &&
 387        mkdir a &&
 388        : >a/b &&
 389        git update-index --add --remove a a/b &&
 390        treeH=$(git write-tree) &&
 391        echo treeH $treeH &&
 392        git ls-tree $treeH
 393'
 394
 395test_expect_success 'a/b vs a, plus c/d case test.' '
 396        read_tree_u_must_succeed -u -m "$treeH" "$treeM" &&
 397        git ls-files --stage | tee >treeMcheck.out &&
 398        test_cmp treeM.out treeMcheck.out
 399'
 400
 401test_expect_success '-m references the correct modified tree' '
 402        echo >file-a &&
 403        echo >file-b &&
 404        git add file-a file-b &&
 405        git commit -a -m "test for correct modified tree" &&
 406        git branch initial-mod &&
 407        echo b >file-b &&
 408        git commit -a -m "B" &&
 409        echo a >file-a &&
 410        git add file-a &&
 411        git ls-tree $(git write-tree) file-a >expect &&
 412        read_tree_must_succeed -m HEAD initial-mod &&
 413        git ls-tree $(git write-tree) file-a >actual &&
 414        test_cmp expect actual
 415'
 416
 417test_done