t7201-co.sh 15.5 KB
Newer Older
1 2 3 4 5
#!/bin/sh
#
# Copyright (c) 2006 Junio C Hamano
#

6
test_description='git checkout tests.
7 8 9 10 11 12 13

Creates master, forks renamer and side branches from it.
Test switching across them.

  ! [master] Initial A one, A two
   * [renamer] Renamer R one->uno, M two
    ! [side] Side M one, D two, A three
14 15 16 17 18 19
     ! [simple] Simple D one, M two
  ----
     + [simple] Simple D one, M two
    +  [side] Side M one, D two, A three
   *   [renamer] Renamer R one->uno, M two
  +*++ [master] Initial A one, A two
20 21

'
22 23 24

. ./test-lib.sh

Daniel Barkalow's avatar
Daniel Barkalow committed
25 26
test_tick

27 28 29 30 31 32 33
fill () {
	for i
	do
		echo "$i"
	done
}

34

35 36
test_expect_success setup '

Daniel Barkalow's avatar
Daniel Barkalow committed
37
	fill x y z > same &&
38
	fill 1 2 3 4 5 6 7 8 >one &&
39
	fill a b c d e >two &&
Daniel Barkalow's avatar
Daniel Barkalow committed
40
	git add same one two &&
41 42
	git commit -m "Initial A one, A two" &&

43 44 45 46 47 48 49 50 51
	git checkout -b renamer &&
	rm -f one &&
	fill 1 3 4 5 6 7 8 >uno &&
	git add uno &&
	fill a b c d e f >two &&
	git commit -a -m "Renamer R one->uno, M two" &&

	git checkout -b side master &&
	fill 1 2 3 4 5 6 7 >one &&
52 53 54 55 56
	fill A B C D E >three &&
	rm -f two &&
	git update-index --add --remove one two three &&
	git commit -m "Side M one, D two, A three" &&

57 58 59 60 61
	git checkout -b simple master &&
	rm -f one &&
	fill a c e > two &&
	git commit -a -m "Simple D one, M two" &&

62 63 64
	git checkout master
'

65 66 67 68 69 70 71 72 73
test_expect_success "checkout from non-existing branch" '

	git checkout -b delete-me master &&
	rm .git/refs/heads/delete-me &&
	test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
	git checkout master &&
	test refs/heads/master = "$(git symbolic-ref HEAD)"
'

74 75
test_expect_success "checkout with dirty tree without -m" '

76
	fill 0 1 2 3 4 5 6 7 8 >one &&
77 78 79 80 81 82 83 84 85 86
	if git checkout side
	then
		echo Not happy
		false
	else
		echo "happy - failed correctly"
	fi

'

Daniel Barkalow's avatar
Daniel Barkalow committed
87 88 89 90 91 92
test_expect_success "checkout with unrelated dirty tree without -m" '

	git checkout -f master &&
	fill 0 1 2 3 4 5 6 7 8 >same &&
	cp same kept
	git checkout side >messages &&
93
	test_cmp same kept
Daniel Barkalow's avatar
Daniel Barkalow committed
94 95 96 97 98
	(cat > messages.expect <<EOF
M	same
EOF
) &&
	touch messages.expect &&
99
	test_cmp messages.expect messages
Daniel Barkalow's avatar
Daniel Barkalow committed
100 101
'

102 103 104
test_expect_success "checkout -m with dirty tree" '

	git checkout -f master &&
105
	git clean -f &&
106

107
	fill 0 1 2 3 4 5 6 7 8 >one &&
Daniel Barkalow's avatar
Daniel Barkalow committed
108
	git checkout -m side > messages &&
109

110
	test "$(git symbolic-ref HEAD)" = "refs/heads/side" &&
111

Daniel Barkalow's avatar
Daniel Barkalow committed
112 113 114 115
	(cat >expect.messages <<EOF
M	one
EOF
) &&
116
	test_cmp expect.messages messages &&
Daniel Barkalow's avatar
Daniel Barkalow committed
117

118 119
	fill "M	one" "A	three" "D	two" >expect.master &&
	git diff --name-status master >current.master &&
120
	test_cmp expect.master current.master &&
121 122 123

	fill "M	one" >expect.side &&
	git diff --name-status side >current.side &&
124
	test_cmp expect.side current.side &&
125 126 127

	: >expect.index &&
	git diff --cached >current.index &&
128
	test_cmp expect.index current.index
129 130
'

131 132
test_expect_success "checkout -m with dirty tree, renamed" '

133
	git checkout -f master && git clean -f &&
134 135 136 137 138 139 140 141 142 143 144 145

	fill 1 2 3 4 5 7 8 >one &&
	if git checkout renamer
	then
		echo Not happy
		false
	else
		echo "happy - failed correctly"
	fi &&

	git checkout -m renamer &&
	fill 1 3 4 5 7 8 >expect &&
146
	test_cmp expect uno &&
147 148 149 150 151 152 153 154
	! test -f one &&
	git diff --cached >current &&
	! test -s current

'

test_expect_success 'checkout -m with merge conflict' '

155
	git checkout -f master && git clean -f &&
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

	fill 1 T 3 4 5 6 S 8 >one &&
	if git checkout renamer
	then
		echo Not happy
		false
	else
		echo "happy - failed correctly"
	fi &&

	git checkout -m renamer &&

	git diff master:one :3:uno |
	sed -e "1,/^@@/d" -e "/^ /d" -e "s/^-/d/" -e "s/^+/a/" >current &&
	fill d2 aT d7 aS >expect &&
171
	test_cmp current expect &&
172 173
	git diff --cached two >current &&
	! test -s current
174 175
'

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
test_expect_success 'format of merge conflict from checkout -m' '

	git checkout -f master && git clean -f &&

	fill b d > two &&
	git checkout -m simple &&

	git ls-files >current &&
	fill same two two two >expect &&
	test_cmp current expect &&

	cat <<-EOF >expect &&
	<<<<<<< simple
	a
	c
	e
	=======
	b
	d
	>>>>>>> local
	EOF
	test_cmp two expect
'

test_expect_success 'checkout --merge --conflict=diff3 <branch>' '

	git checkout -f master && git reset --hard && git clean -f &&

	fill b d > two &&
	git checkout --merge --conflict=diff3 simple &&

	cat <<-EOF >expect &&
	<<<<<<< simple
	a
	c
	e
212
	||||||| master
213 214 215 216 217 218 219 220 221 222 223 224 225
	a
	b
	c
	d
	e
	=======
	b
	d
	>>>>>>> local
	EOF
	test_cmp two expect
'

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
test_expect_success 'switch to another branch while carrying a deletion' '

	git checkout -f master && git reset --hard && git clean -f &&
	git rm two &&

	test_must_fail git checkout simple 2>errs &&
	test_i18ngrep overwritten errs &&

	git checkout --merge simple 2>errs &&
	test_i18ngrep ! overwritten errs &&
	git ls-files -u &&
	test_must_fail git cat-file -t :0:two &&
	test "$(git cat-file -t :1:two)" = blob &&
	test "$(git cat-file -t :2:two)" = blob &&
	test_must_fail git cat-file -t :3:two
'

243
test_expect_success 'checkout to detach HEAD (with advice declined)' '
244

245
	git config advice.detachedHead false &&
246
	git checkout -f renamer && git clean -f &&
Daniel Barkalow's avatar
Daniel Barkalow committed
247
	git checkout renamer^ 2>messages &&
248
	test_i18ngrep "HEAD is now at 7329388" messages &&
249
	test_line_count = 1 messages &&
250 251 252 253 254 255 256 257 258 259 260 261
	H=$(git rev-parse --verify HEAD) &&
	M=$(git show-ref -s --verify refs/heads/master) &&
	test "z$H" = "z$M" &&
	if git symbolic-ref HEAD >/dev/null 2>&1
	then
		echo "OOPS, HEAD is still symbolic???"
		false
	else
		: happy
	fi
'

262
test_expect_success 'checkout to detach HEAD' '
263 264 265
	git config advice.detachedHead true &&
	git checkout -f renamer && git clean -f &&
	git checkout renamer^ 2>messages &&
266
	test_i18ngrep "HEAD is now at 7329388" messages &&
267
	test_line_count -gt 1 messages &&
268 269 270 271 272 273 274 275 276 277 278 279
	H=$(git rev-parse --verify HEAD) &&
	M=$(git show-ref -s --verify refs/heads/master) &&
	test "z$H" = "z$M" &&
	if git symbolic-ref HEAD >/dev/null 2>&1
	then
		echo "OOPS, HEAD is still symbolic???"
		false
	else
		: happy
	fi
'

280
test_expect_success 'checkout to detach HEAD with branchname^' '
281

282
	git checkout -f master && git clean -f &&
283 284 285 286 287 288 289 290 291 292 293 294 295
	git checkout renamer^ &&
	H=$(git rev-parse --verify HEAD) &&
	M=$(git show-ref -s --verify refs/heads/master) &&
	test "z$H" = "z$M" &&
	if git symbolic-ref HEAD >/dev/null 2>&1
	then
		echo "OOPS, HEAD is still symbolic???"
		false
	else
		: happy
	fi
'

296
test_expect_success 'checkout to detach HEAD with :/message' '
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

	git checkout -f master && git clean -f &&
	git checkout ":/Initial" &&
	H=$(git rev-parse --verify HEAD) &&
	M=$(git show-ref -s --verify refs/heads/master) &&
	test "z$H" = "z$M" &&
	if git symbolic-ref HEAD >/dev/null 2>&1
	then
		echo "OOPS, HEAD is still symbolic???"
		false
	else
		: happy
	fi
'

312
test_expect_success 'checkout to detach HEAD with HEAD^0' '
313

314
	git checkout -f master && git clean -f &&
315 316 317 318 319 320 321 322 323 324 325 326 327
	git checkout HEAD^0 &&
	H=$(git rev-parse --verify HEAD) &&
	M=$(git show-ref -s --verify refs/heads/master) &&
	test "z$H" = "z$M" &&
	if git symbolic-ref HEAD >/dev/null 2>&1
	then
		echo "OOPS, HEAD is still symbolic???"
		false
	else
		: happy
	fi
'

328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
test_expect_success 'checkout with ambiguous tag/branch names' '

	git tag both side &&
	git branch both master &&
	git reset --hard &&
	git checkout master &&

	git checkout both &&
	H=$(git rev-parse --verify HEAD) &&
	M=$(git show-ref -s --verify refs/heads/master) &&
	test "z$H" = "z$M" &&
	name=$(git symbolic-ref HEAD 2>/dev/null) &&
	test "z$name" = zrefs/heads/both

'

test_expect_success 'checkout with ambiguous tag/branch names' '

	git reset --hard &&
	git checkout master &&

	git tag frotz side &&
	git branch frotz master &&
	git reset --hard &&
	git checkout master &&

	git checkout tags/frotz &&
	H=$(git rev-parse --verify HEAD) &&
	S=$(git show-ref -s --verify refs/heads/side) &&
	test "z$H" = "z$S" &&
	if name=$(git symbolic-ref HEAD 2>/dev/null)
	then
		echo "Bad -- should have detached"
		false
	else
		: happy
	fi

'

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
test_expect_success 'switch branches while in subdirectory' '

	git reset --hard &&
	git checkout master &&

	mkdir subs &&
	(
		cd subs &&
		git checkout side
	) &&
	! test -f subs/one &&
	rm -fr subs

'

test_expect_success 'checkout specific path while in subdirectory' '

	git reset --hard &&
	git checkout side &&
	mkdir subs &&
	>subs/bero &&
	git add subs/bero &&
	git commit -m "add subs/bero" &&

	git checkout master &&
	mkdir -p subs &&
	(
		cd subs &&
		git checkout side -- bero
	) &&
	test -f subs/bero

'

402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
test_expect_success \
    'checkout w/--track sets up tracking' '
    git config branch.autosetupmerge false &&
    git checkout master &&
    git checkout --track -b track1 &&
    test "$(git config branch.track1.remote)" &&
    test "$(git config branch.track1.merge)"'

test_expect_success \
    'checkout w/autosetupmerge=always sets up tracking' '
    git config branch.autosetupmerge always &&
    git checkout master &&
    git checkout -b track2 &&
    test "$(git config branch.track2.remote)" &&
    test "$(git config branch.track2.merge)"
    git config branch.autosetupmerge false'

419 420 421 422 423 424 425 426
test_expect_success 'checkout w/--track from non-branch HEAD fails' '
    git checkout master^0 &&
    test_must_fail git symbolic-ref HEAD &&
    test_must_fail git checkout --track -b track &&
    test_must_fail git rev-parse --verify track &&
    test_must_fail git symbolic-ref HEAD &&
    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
'
427

428 429 430 431 432 433 434 435 436
test_expect_success 'checkout w/--track from tag fails' '
    git checkout master^0 &&
    test_must_fail git symbolic-ref HEAD &&
    test_must_fail git checkout --track -b track frotz &&
    test_must_fail git rev-parse --verify track &&
    test_must_fail git symbolic-ref HEAD &&
    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
'

437
test_expect_success 'detach a symbolic link HEAD' '
438 439 440 441 442 443 444 445 446 447
    git checkout master &&
    git config --bool core.prefersymlinkrefs yes &&
    git checkout side &&
    git checkout master &&
    it=$(git symbolic-ref HEAD) &&
    test "z$it" = zrefs/heads/master &&
    here=$(git rev-parse --verify refs/heads/master) &&
    git checkout side^ &&
    test "z$(git rev-parse --verify refs/heads/master)" = "z$here"
'
448

449 450
test_expect_success \
    'checkout with --track fakes a sensible -b <name>' '
451
    git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
452
    git update-ref refs/remotes/origin/koala/bear renamer &&
453

454 455
    git checkout --track origin/koala/bear &&
    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
456 457 458 459 460 461 462 463 464 465 466 467 468 469
    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&

    git checkout master && git branch -D koala/bear &&

    git checkout --track refs/remotes/origin/koala/bear &&
    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&

    git checkout master && git branch -D koala/bear &&

    git checkout --track remotes/origin/koala/bear &&
    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
'
470 471 472 473 474

test_expect_success \
    'checkout with --track, but without -b, fails with too short tracked name' '
    test_must_fail git checkout --track renamer'

475
setup_conflicting_index () {
476 477 478 479 480 481 482 483 484 485
	rm -f .git/index &&
	O=$(echo original | git hash-object -w --stdin) &&
	A=$(echo ourside | git hash-object -w --stdin) &&
	B=$(echo theirside | git hash-object -w --stdin) &&
	(
		echo "100644 $A 0	fild" &&
		echo "100644 $O 1	file" &&
		echo "100644 $A 2	file" &&
		echo "100644 $B 3	file" &&
		echo "100644 $A 0	filf"
486 487 488 489 490
	) | git update-index --index-info
}

test_expect_success 'checkout an unmerged path should fail' '
	setup_conflicting_index &&
491 492 493 494 495 496 497 498 499 500
	echo "none of the above" >sample &&
	cat sample >fild &&
	cat sample >file &&
	cat sample >filf &&
	test_must_fail git checkout fild file filf &&
	test_cmp sample fild &&
	test_cmp sample filf &&
	test_cmp sample file
'

501
test_expect_success 'checkout with an unmerged path can be ignored' '
502
	setup_conflicting_index &&
503 504 505 506 507 508 509 510 511 512 513
	echo "none of the above" >sample &&
	echo ourside >expect &&
	cat sample >fild &&
	cat sample >file &&
	cat sample >filf &&
	git checkout -f fild file filf &&
	test_cmp expect fild &&
	test_cmp expect filf &&
	test_cmp sample file
'

514
test_expect_success 'checkout unmerged stage' '
515
	setup_conflicting_index &&
516 517 518 519 520 521 522 523 524 525 526 527 528
	echo "none of the above" >sample &&
	echo ourside >expect &&
	cat sample >fild &&
	cat sample >file &&
	cat sample >filf &&
	git checkout --ours . &&
	test_cmp expect fild &&
	test_cmp expect filf &&
	test_cmp expect file &&
	git checkout --theirs file &&
	test ztheirside = "z$(cat file)"
'

529
test_expect_success 'checkout with --merge' '
530
	setup_conflicting_index &&
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
	echo "none of the above" >sample &&
	echo ourside >expect &&
	cat sample >fild &&
	cat sample >file &&
	cat sample >filf &&
	git checkout -m -- fild file filf &&
	(
		echo "<<<<<<< ours"
		echo ourside
		echo "======="
		echo theirside
		echo ">>>>>>> theirs"
	) >merged &&
	test_cmp expect fild &&
	test_cmp expect filf &&
	test_cmp merged file
'

test_expect_success 'checkout with --merge, in diff3 -m style' '
	git config merge.conflictstyle diff3 &&
551
	setup_conflicting_index &&
552 553 554 555 556 557 558 559 560
	echo "none of the above" >sample &&
	echo ourside >expect &&
	cat sample >fild &&
	cat sample >file &&
	cat sample >filf &&
	git checkout -m -- fild file filf &&
	(
		echo "<<<<<<< ours"
		echo ourside
561
		echo "||||||| base"
562 563 564 565 566 567 568 569 570 571
		echo original
		echo "======="
		echo theirside
		echo ">>>>>>> theirs"
	) >merged &&
	test_cmp expect fild &&
	test_cmp expect filf &&
	test_cmp merged file
'

572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
test_expect_success 'checkout --conflict=merge, overriding config' '
	git config merge.conflictstyle diff3 &&
	setup_conflicting_index &&
	echo "none of the above" >sample &&
	echo ourside >expect &&
	cat sample >fild &&
	cat sample >file &&
	cat sample >filf &&
	git checkout --conflict=merge -- fild file filf &&
	(
		echo "<<<<<<< ours"
		echo ourside
		echo "======="
		echo theirside
		echo ">>>>>>> theirs"
	) >merged &&
	test_cmp expect fild &&
	test_cmp expect filf &&
	test_cmp merged file
'

test_expect_success 'checkout --conflict=diff3' '
	git config --unset merge.conflictstyle
	setup_conflicting_index &&
	echo "none of the above" >sample &&
	echo ourside >expect &&
	cat sample >fild &&
	cat sample >file &&
	cat sample >filf &&
	git checkout --conflict=diff3 -- fild file filf &&
	(
		echo "<<<<<<< ours"
		echo ourside
605
		echo "||||||| base"
606 607 608 609 610 611 612 613 614 615
		echo original
		echo "======="
		echo theirside
		echo ">>>>>>> theirs"
	) >merged &&
	test_cmp expect fild &&
	test_cmp expect filf &&
	test_cmp merged file
'

616 617 618 619 620 621 622 623 624 625
test_expect_success 'failing checkout -b should not break working tree' '
	git reset --hard master &&
	git symbolic-ref HEAD refs/heads/master &&
	test_must_fail git checkout -b renamer side^ &&
	test $(git symbolic-ref HEAD) = refs/heads/master &&
	git diff --exit-code &&
	git diff --cached --exit-code

'

626 627 628 629 630 631 632 633
test_expect_success 'switch out of non-branch' '
	git reset --hard master &&
	git checkout master^0 &&
	echo modified >one &&
	test_must_fail git checkout renamer 2>error.log &&
	! grep "^Previous HEAD" error.log
'

634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
(
 echo "#!$SHELL_PATH"
 cat <<\EOF
O=$1 A=$2 B=$3
cat "$A" >.tmp
exec >"$A"
echo '<<<<<<< filfre-theirs'
cat "$B"
echo '||||||| filfre-common'
cat "$O"
echo '======='
cat ".tmp"
echo '>>>>>>> filfre-ours'
rm -f .tmp
exit 1
EOF
) >filfre.sh
chmod +x filfre.sh

test_expect_success 'custom merge driver with checkout -m' '
	git reset --hard &&

	git config merge.filfre.driver "./filfre.sh %O %A %B" &&
	git config merge.filfre.name "Feel-free merge driver" &&
	git config merge.filfre.recursive binary &&
	echo "arm merge=filfre" >.gitattributes &&

	git checkout -b left &&
	echo neutral >arm &&
	git add arm .gitattributes &&
	test_tick &&
	git commit -m neutral &&
	git branch right &&

	echo left >arm &&
	test_tick &&
	git commit -a -m left &&
	git checkout right &&

	echo right >arm &&
	test_tick &&
	git commit -a -m right &&

	test_must_fail git merge left &&
	(
		for t in filfre-common left right
		do
			grep $t arm || exit 1
		done
		exit 0
	) &&

	mv arm expect &&
	git checkout -m arm &&
	test_cmp expect arm
'

691
test_done