git/t/t6436-merge-overwrite.sh

#!/bin/sh

test_description='git-merge

Do not overwrite changes.'

GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

test_expect_success 'setup' '
	test_commit c0 c0.c &&
	test_commit c1 c1.c &&
	test_commit c1a c1.c "c1 a" &&
	git reset --hard c0 &&
	test_commit c2 c2.c &&
	git reset --hard c0 &&
	mkdir sub &&
	echo "sub/f" > sub/f &&
	mkdir sub2 &&
	echo "sub2/f" > sub2/f &&
	git add sub/f sub2/f &&
	git commit -m sub &&
	git tag sub &&
	echo "VERY IMPORTANT CHANGES" > important
'

test_expect_success 'will not overwrite untracked file' '
	git reset --hard c1 &&
	cp important c2.c &&
	test_must_fail git merge c2 &&
	test_path_is_missing .git/MERGE_HEAD &&
	test_cmp important c2.c
'

test_expect_success 'will overwrite tracked file' '
	git reset --hard c1 &&
	cp important c2.c &&
	git add c2.c &&
	git commit -m important &&
	git checkout c2
'

test_expect_success 'will not overwrite new file' '
	git reset --hard c1 &&
	cp important c2.c &&
	git add c2.c &&
	test_must_fail git merge c2 &&
	test_path_is_missing .git/MERGE_HEAD &&
	test_cmp important c2.c
'

test_expect_success 'will not overwrite staged changes' '
	git reset --hard c1 &&
	cp important c2.c &&
	git add c2.c &&
	rm c2.c &&
	test_must_fail git merge c2 &&
	test_path_is_missing .git/MERGE_HEAD &&
	git checkout c2.c &&
	test_cmp important c2.c
'

test_expect_success 'will not overwrite removed file' '
	git reset --hard c1 &&
	git rm c1.c &&
	git commit -m "rm c1.c" &&
	cp important c1.c &&
	test_must_fail git merge c1a &&
	test_cmp important c1.c &&
	rm c1.c  # Do not leave untracked file in way of future tests
'

test_expect_success 'will not overwrite re-added file' '
	git reset --hard c1 &&
	git rm c1.c &&
	git commit -m "rm c1.c" &&
	cp important c1.c &&
	git add c1.c &&
	test_must_fail git merge c1a &&
	test_path_is_missing .git/MERGE_HEAD &&
	test_cmp important c1.c
'

test_expect_success 'will not overwrite removed file with staged changes' '
	git reset --hard c1 &&
	git rm c1.c &&
	git commit -m "rm c1.c" &&
	cp important c1.c &&
	git add c1.c &&
	rm c1.c &&
	test_must_fail git merge c1a &&
	test_path_is_missing .git/MERGE_HEAD &&
	git checkout c1.c &&
	test_cmp important c1.c
'

test_expect_success 'will not overwrite unstaged changes in renamed file' '
	git reset --hard c1 &&
	git mv c1.c other.c &&
	git commit -m rename &&
	cp important other.c &&
	if test "$GIT_TEST_MERGE_ALGORITHM" = ort
	then
		test_must_fail git merge c1a >out 2>err &&
		test_grep "would be overwritten by merge" err &&
		test_cmp important other.c &&
		test_path_is_missing .git/MERGE_HEAD
	else
		test_must_fail git merge c1a >out &&
		test_grep "Refusing to lose dirty file at other.c" out &&
		test_path_is_file other.c~HEAD &&
		test $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&
		test_cmp important other.c
	fi
'

test_expect_success 'will not overwrite untracked subtree' '
	git reset --hard c0 &&
	rm -rf sub &&
	mkdir -p sub/f &&
	cp important sub/f/important &&
	test_must_fail git merge sub &&
	test_path_is_missing .git/MERGE_HEAD &&
	test_cmp important sub/f/important
'

cat >expect <<\EOF
error: The following untracked working tree files would be overwritten by merge:
	sub
	sub2
Please move or remove them before you merge.
Aborting
EOF

test_expect_success 'will not overwrite untracked file in leading path' '
	git reset --hard c0 &&
	rm -rf sub &&
	cp important sub &&
	cp important sub2 &&
	test_must_fail git merge sub 2>out &&
	test_cmp out expect &&
	test_path_is_missing .git/MERGE_HEAD &&
	test_cmp important sub &&
	test_cmp important sub2 &&
	rm -f sub sub2
'

test_expect_success SYMLINKS 'will not overwrite untracked symlink in leading path' '
	git reset --hard c0 &&
	rm -rf sub &&
	mkdir sub2 &&
	ln -s sub2 sub &&
	test_must_fail git merge sub &&
	test_path_is_missing .git/MERGE_HEAD
'

test_expect_success 'will not be confused by symlink in leading path' '
	git reset --hard c0 &&
	rm -rf sub &&
	test_ln_s_add sub2 sub &&
	git commit -m ln &&
	git checkout sub
'

cat >expect <<\EOF
error: Untracked working tree file 'c0.c' would be overwritten by merge.
fatal: read-tree failed
EOF

test_expect_success 'will not overwrite untracked file on unborn branch' '
	git reset --hard c0 &&
	git rm -fr . &&
	git checkout --orphan new &&
	cp important c0.c &&
	test_must_fail git merge c0 2>out &&
	test_cmp out expect
'

test_expect_success 'will not overwrite untracked file on unborn branch .git/MERGE_HEAD sanity etc.' '
	test_when_finished "rm c0.c" &&
	test_path_is_missing .git/MERGE_HEAD &&
	test_cmp important c0.c
'

test_expect_success 'failed merge leaves unborn branch in the womb' '
	test_must_fail git rev-parse --verify HEAD
'

test_expect_success 'set up unborn branch and content' '
	git symbolic-ref HEAD refs/heads/unborn &&
	rm -f .git/index &&
	echo foo > tracked-file &&
	git add tracked-file &&
	echo bar > untracked-file
'

test_expect_success 'will not clobber WT/index when merging into unborn' '
	git merge main &&
	grep foo tracked-file &&
	git show :tracked-file >expect &&
	grep foo expect &&
	grep bar untracked-file
'

test_done