git/t/t6402-merge-rename.sh
Junio C Hamano 7d0daf3f12 Merge branch 'en/pull-conflicting-options'
"git pull" had various corner cases that were not well thought out
around its --rebase backend, e.g. "git pull --ff-only" did not stop
but went ahead and rebased when the history on other side is not a
descendant of our history.  The series tries to fix them up.

* en/pull-conflicting-options:
  pull: fix handling of multiple heads
  pull: update docs & code for option compatibility with rebasing
  pull: abort by default when fast-forwarding is not possible
  pull: make --rebase and --no-rebase override pull.ff=only
  pull: since --ff-only overrides, handle it first
  pull: abort if --ff-only is given and fast-forwarding is impossible
  t7601: add tests of interactions with multiple merge heads and config
  t7601: test interaction of merge/rebase/fast-forward flags and options
2021-08-30 16:06:01 -07:00

973 lines
25 KiB
Bash
Executable file

#!/bin/sh
test_description='Merge-recursive merging renames'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
modify () {
sed -e "$1" <"$2" >"$2.x" &&
mv "$2.x" "$2"
}
test_expect_success 'setup' '
cat >A <<-\EOF &&
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
c cccccccccccccccccccccccccccccccccccccccccccccccc
d dddddddddddddddddddddddddddddddddddddddddddddddd
e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
f ffffffffffffffffffffffffffffffffffffffffffffffff
g gggggggggggggggggggggggggggggggggggggggggggggggg
h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
l llllllllllllllllllllllllllllllllllllllllllllllll
m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
o oooooooooooooooooooooooooooooooooooooooooooooooo
EOF
cat >M <<-\EOF &&
A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
EOF
git add A M &&
git commit -m "initial has A and M" &&
git branch white &&
git branch red &&
git branch blue &&
git branch yellow &&
git branch change &&
git branch change+rename &&
sed -e "/^g /s/.*/g : main changes a line/" <A >A+ &&
mv A+ A &&
git commit -a -m "main updates A" &&
git checkout yellow &&
rm -f M &&
git commit -a -m "yellow removes M" &&
git checkout white &&
sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "white renames A->B, M->N" &&
git checkout red &&
sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "red renames A->B, M->N" &&
git checkout blue &&
sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A C M N &&
git commit -m "blue renames A->C, M->N" &&
git checkout change &&
sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
mv A+ A &&
git commit -q -a -m "changed" &&
git checkout change+rename &&
sed -e "/^g /s/.*/g : changed line/" <A >B &&
rm A &&
git update-index --add B &&
git commit -q -a -m "changed and renamed" &&
git checkout main
'
test_expect_success 'pull renaming branch into unrenaming one' \
'
git show-branch &&
test_expect_code 1 git pull --no-rebase . white &&
git ls-files -s &&
test_stdout_line_count = 3 git ls-files -u B &&
test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
}" B | grep main &&
git diff --exit-code white N
'
test_expect_success 'pull renaming branch into another renaming one' \
'
rm -f B &&
git reset --hard &&
git checkout red &&
test_expect_code 1 git pull --no-rebase . white &&
test_stdout_line_count = 3 git ls-files -u B &&
test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
}" B | grep red &&
git diff --exit-code white N
'
test_expect_success 'pull unrenaming branch into renaming one' \
'
git reset --hard &&
git show-branch &&
test_expect_code 1 git pull --no-rebase . main &&
test_stdout_line_count = 3 git ls-files -u B &&
test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
}" B | grep red &&
git diff --exit-code white N
'
test_expect_success 'pull conflicting renames' \
'
git reset --hard &&
git show-branch &&
test_expect_code 1 git pull --no-rebase . blue &&
test_stdout_line_count = 1 git ls-files -u A &&
test_stdout_line_count = 1 git ls-files -u B &&
test_stdout_line_count = 1 git ls-files -u C &&
test_stdout_line_count = 1 git ls-files -s N &&
sed -ne "/^g/{
p
q
}" B | grep red &&
git diff --exit-code white N
'
test_expect_success 'interference with untracked working tree file' '
git reset --hard &&
git show-branch &&
echo >A this file should not matter &&
test_expect_code 1 git pull --no-rebase . white &&
test_path_is_file A
'
test_expect_success 'interference with untracked working tree file' '
git reset --hard &&
git checkout white &&
git show-branch &&
rm -f A &&
echo >A this file should not matter &&
test_expect_code 1 git pull --no-rebase . red &&
test_path_is_file A
'
test_expect_success 'interference with untracked working tree file' '
git reset --hard &&
rm -f A M &&
git checkout -f main &&
git tag -f anchor &&
git show-branch &&
git pull --no-rebase . yellow &&
test_path_is_missing M &&
git reset --hard anchor
'
test_expect_success 'updated working tree file should prevent the merge' '
git reset --hard &&
rm -f A M &&
git checkout -f main &&
git tag -f anchor &&
git show-branch &&
echo >>M one line addition &&
cat M >M.saved &&
test_expect_code 128 git pull . yellow &&
test_cmp M M.saved &&
rm -f M.saved
'
test_expect_success 'updated working tree file should prevent the merge' '
git reset --hard &&
rm -f A M &&
git checkout -f main &&
git tag -f anchor &&
git show-branch &&
echo >>M one line addition &&
cat M >M.saved &&
git update-index M &&
test_expect_code 128 git pull --no-rebase . yellow &&
test_cmp M M.saved &&
rm -f M.saved
'
test_expect_success 'interference with untracked working tree file' '
git reset --hard &&
rm -f A M &&
git checkout -f yellow &&
git tag -f anchor &&
git show-branch &&
echo >M this file should not matter &&
git pull --no-rebase . main &&
test_path_is_file M &&
! {
git ls-files -s |
grep M
} &&
git reset --hard anchor
'
test_expect_success 'merge of identical changes in a renamed file' '
rm -f A M N &&
git reset --hard &&
git checkout change+rename &&
test-tool chmtime --get -3600 B >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge change >out &&
test-tool chmtime --get B >new-mtime &&
test_cmp old-mtime new-mtime &&
git reset --hard HEAD^ &&
git checkout change &&
# A will be renamed to B; we check mtimes and file presence
test_path_is_missing B &&
test-tool chmtime --get -3600 A >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
test_path_is_missing A &&
test-tool chmtime --get B >new-mtime &&
test $(cat old-mtime) -lt $(cat new-mtime)
'
test_expect_success 'setup for rename + d/f conflicts' '
git reset --hard &&
git checkout --orphan dir-in-way &&
git rm -rf . &&
git clean -fdqx &&
mkdir sub &&
mkdir dir &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
echo foo >dir/file-in-the-way &&
git add -A &&
git commit -m "Common commit" &&
echo 11 >>sub/file &&
echo more >>dir/file-in-the-way &&
git add -u &&
git commit -m "Commit to merge, with dir in the way" &&
git checkout -b dir-not-in-way &&
git reset --soft HEAD^ &&
git rm -rf dir &&
git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
git rm -rf dir &&
git rm sub/file &&
printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
git add dir &&
git commit -m "Independent change" &&
git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
git rm -rf dir &&
git mv sub/file dir &&
echo 12 >>dir &&
git add dir &&
git commit -m "Conflicting change"
'
test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
git reset --hard &&
git checkout -q renamed-file-has-no-conflicts^0 &&
git merge --strategy=recursive dir-not-in-way &&
git diff --quiet &&
test_path_is_file dir &&
test_write_lines 1 2 3 4 5555 6 7 8 9 10 11 >expected &&
test_cmp expected dir
'
test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
git reset --hard &&
rm -rf dir~* &&
git checkout -q renamed-file-has-no-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-in-way >output &&
test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
test_i18ngrep "Auto-merging dir" output &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_i18ngrep "moving it to dir~HEAD instead" output
else
test_i18ngrep "Adding as dir~HEAD instead" output
fi &&
test_stdout_line_count = 3 git ls-files -u &&
test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
test_path_is_file dir/file-in-the-way &&
test_path_is_file dir~HEAD &&
test_cmp expected dir~HEAD
'
test_expect_success 'Same as previous, but merged other way' '
git reset --hard &&
rm -rf dir~* &&
git checkout -q dir-in-way^0 &&
test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
! grep "error: refusing to lose untracked file at" errors &&
test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
test_i18ngrep "Auto-merging dir" output &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_i18ngrep "moving it to dir~renamed-file-has-no-conflicts instead" output
else
test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output
fi &&
test_stdout_line_count = 3 git ls-files -u &&
test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
test_path_is_file dir/file-in-the-way &&
test_path_is_file dir~renamed-file-has-no-conflicts &&
test_cmp expected dir~renamed-file-has-no-conflicts
'
test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
git reset --hard &&
rm -rf dir~* &&
git checkout -q renamed-file-has-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-not-in-way &&
test_stdout_line_count = 3 git ls-files -u &&
test_stdout_line_count = 3 git ls-files -u dir &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
test_path_is_file dir &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
9
10
<<<<<<< HEAD:dir
12
=======
11
>>>>>>> dir-not-in-way:sub/file
EOF
test_cmp expected dir
'
test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
modify s/dir-not-in-way/dir-in-way/ expected &&
git reset --hard &&
rm -rf dir~* &&
git checkout -q renamed-file-has-conflicts^0 &&
test_must_fail git merge --strategy=recursive dir-in-way &&
test_stdout_line_count = 5 git ls-files -u &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_stdout_line_count = 3 git ls-files -u dir~HEAD
else
git ls-files -u dir >out &&
test 3 -eq $(grep -v file-in-the-way out | wc -l) &&
rm -f out
fi &&
test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
test_path_is_file dir/file-in-the-way &&
test_path_is_file dir~HEAD &&
test_cmp expected dir~HEAD
'
test_expect_success 'Same as previous, but merged other way' '
git reset --hard &&
rm -rf dir~* &&
git checkout -q dir-in-way^0 &&
test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
test_stdout_line_count = 5 git ls-files -u &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_stdout_line_count = 3 git ls-files -u dir~renamed-file-has-conflicts
else
git ls-files -u dir >out &&
test 3 -eq $(grep -v file-in-the-way out | wc -l) &&
rm -f out
fi &&
test_stdout_line_count = 2 git ls-files -u dir/file-in-the-way &&
test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet &&
test_path_is_file dir/file-in-the-way &&
test_path_is_file dir~renamed-file-has-conflicts &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
9
10
<<<<<<< HEAD:sub/file
11
=======
12
>>>>>>> renamed-file-has-conflicts:dir
EOF
test_cmp expected dir~renamed-file-has-conflicts
'
test_expect_success 'setup both rename source and destination involved in D/F conflict' '
git reset --hard &&
git checkout --orphan rename-dest &&
git rm -rf . &&
git clean -fdqx &&
mkdir one &&
echo stuff >one/file &&
git add -A &&
git commit -m "Common commit" &&
git mv one/file destdir &&
git commit -m "Renamed to destdir" &&
git checkout -b source-conflict HEAD~1 &&
git rm -rf one &&
mkdir destdir &&
touch one destdir/foo &&
git add -A &&
git commit -m "Conflicts in the way"
'
test_expect_success 'both rename source and destination involved in D/F conflict' '
git reset --hard &&
rm -rf dir~* &&
git checkout -q rename-dest^0 &&
test_must_fail git merge --strategy=recursive source-conflict &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_stdout_line_count = 2 git ls-files -u
else
test_stdout_line_count = 1 git ls-files -u
fi &&
test_must_fail git diff --quiet &&
test_path_is_file destdir/foo &&
test_path_is_file one &&
test_path_is_file destdir~HEAD &&
test "stuff" = "$(cat destdir~HEAD)"
'
test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
git reset --hard &&
git checkout --orphan rename-two &&
git rm -rf . &&
git clean -fdqx &&
mkdir one &&
mkdir two &&
echo stuff >one/file &&
echo other >two/file &&
git add -A &&
git commit -m "Common commit" &&
git rm -rf one &&
git mv two/file one &&
git commit -m "Rename two/file -> one" &&
git checkout -b rename-one HEAD~1 &&
git rm -rf two &&
git mv one/file two &&
rm -r one &&
git commit -m "Rename one/file -> two"
'
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
git checkout -q rename-one^0 &&
mkdir one &&
test_must_fail git merge --strategy=recursive rename-two &&
test_stdout_line_count = 4 git ls-files -u &&
test_stdout_line_count = 2 git ls-files -u one &&
test_stdout_line_count = 2 git ls-files -u two &&
test_must_fail git diff --quiet &&
test 3 -eq $(find . | grep -v .git | wc -l) &&
test_path_is_file one &&
test_path_is_file two &&
test "other" = $(cat one) &&
test "stuff" = $(cat two)
'
else
test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
git checkout -q rename-one^0 &&
mkdir one &&
test_must_fail git merge --strategy=recursive rename-two &&
test_stdout_line_count = 2 git ls-files -u &&
test_stdout_line_count = 1 git ls-files -u one &&
test_stdout_line_count = 1 git ls-files -u two &&
test_must_fail git diff --quiet &&
test 4 -eq $(find . | grep -v .git | wc -l) &&
test_path_is_dir one &&
test_path_is_file one~rename-two &&
test_path_is_file two &&
test "other" = $(cat one~rename-two) &&
test "stuff" = $(cat two)
'
fi
test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '
git reset --hard &&
git clean -fdqx &&
test_must_fail git merge --strategy=recursive rename-two &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_stdout_line_count = 4 git ls-files -u &&
test_stdout_line_count = 2 git ls-files -u one &&
test_stdout_line_count = 2 git ls-files -u two
else
test_stdout_line_count = 2 git ls-files -u &&
test_stdout_line_count = 1 git ls-files -u one &&
test_stdout_line_count = 1 git ls-files -u two
fi &&
test_must_fail git diff --quiet &&
test 3 -eq $(find . | grep -v .git | wc -l) &&
test_path_is_file one &&
test_path_is_file two &&
test "other" = $(cat one) &&
test "stuff" = $(cat two)
'
test_expect_success 'setup rename of one file to two, with directories in the way' '
git reset --hard &&
git checkout --orphan first-rename &&
git rm -rf . &&
git clean -fdqx &&
echo stuff >original &&
git add -A &&
git commit -m "Common commit" &&
mkdir two &&
>two/file &&
git add two/file &&
git mv original one &&
git commit -m "Put two/file in the way, rename to one" &&
git checkout -b second-rename HEAD~1 &&
mkdir one &&
>one/file &&
git add one/file &&
git mv original two &&
git commit -m "Put one/file in the way, rename to two"
'
test_expect_success 'check handling of differently renamed file with D/F conflicts' '
git checkout -q first-rename^0 &&
test_must_fail git merge --strategy=recursive second-rename &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_stdout_line_count = 5 git ls-files -s &&
test_stdout_line_count = 3 git ls-files -u &&
test_stdout_line_count = 1 git ls-files -u one~HEAD &&
test_stdout_line_count = 1 git ls-files -u two~second-rename &&
test_stdout_line_count = 1 git ls-files -u original &&
test_stdout_line_count = 0 git ls-files -o
else
test_stdout_line_count = 5 git ls-files -s &&
test_stdout_line_count = 3 git ls-files -u &&
test_stdout_line_count = 1 git ls-files -u one &&
test_stdout_line_count = 1 git ls-files -u two &&
test_stdout_line_count = 1 git ls-files -u original &&
test_stdout_line_count = 2 git ls-files -o
fi &&
test_path_is_file one/file &&
test_path_is_file two/file &&
test_path_is_file one~HEAD &&
test_path_is_file two~second-rename &&
test_path_is_missing original
'
test_expect_success 'setup rename one file to two; directories moving out of the way' '
git reset --hard &&
git checkout --orphan first-rename-redo &&
git rm -rf . &&
git clean -fdqx &&
echo stuff >original &&
mkdir one two &&
touch one/file two/file &&
git add -A &&
git commit -m "Common commit" &&
git rm -rf one &&
git mv original one &&
git commit -m "Rename to one" &&
git checkout -b second-rename-redo HEAD~1 &&
git rm -rf two &&
git mv original two &&
git commit -m "Rename to two"
'
test_expect_success 'check handling of differently renamed file with D/F conflicts' '
git checkout -q first-rename-redo^0 &&
test_must_fail git merge --strategy=recursive second-rename-redo &&
test_stdout_line_count = 3 git ls-files -u &&
test_stdout_line_count = 1 git ls-files -u one &&
test_stdout_line_count = 1 git ls-files -u two &&
test_stdout_line_count = 1 git ls-files -u original &&
test_stdout_line_count = 0 git ls-files -o &&
test_path_is_file one &&
test_path_is_file two &&
test_path_is_missing original
'
test_expect_success 'setup avoid unnecessary update, normal rename' '
git reset --hard &&
git checkout --orphan avoid-unnecessary-update-1 &&
git rm -rf . &&
git clean -fdqx &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
git add -A &&
git commit -m "Common commit" &&
git mv original rename &&
echo 11 >>rename &&
git add -u &&
git commit -m "Renamed and modified" &&
git checkout -b merge-branch-1 HEAD~1 &&
echo "random content" >random-file &&
git add -A &&
git commit -m "Random, unrelated changes"
'
test_expect_success 'avoid unnecessary update, normal rename' '
git checkout -q avoid-unnecessary-update-1^0 &&
test-tool chmtime --get -3600 rename >expect &&
git merge merge-branch-1 &&
test-tool chmtime --get rename >actual &&
test_cmp expect actual # "rename" should have stayed intact
'
test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
git reset --hard &&
git checkout --orphan avoid-unnecessary-update-2 &&
git rm -rf . &&
git clean -fdqx &&
mkdir df &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
git add -A &&
git commit -m "Common commit" &&
git mv df/file temp &&
rm -rf df &&
git mv temp df &&
echo 11 >>df &&
git add -u &&
git commit -m "Renamed and modified" &&
git checkout -b merge-branch-2 HEAD~1 &&
>unrelated-change &&
git add unrelated-change &&
git commit -m "Only unrelated changes"
'
test_expect_success 'avoid unnecessary update, with D/F conflict' '
git checkout -q avoid-unnecessary-update-2^0 &&
test-tool chmtime --get -3600 df >expect &&
git merge merge-branch-2 &&
test-tool chmtime --get df >actual &&
test_cmp expect actual # "df" should have stayed intact
'
test_expect_success 'setup avoid unnecessary update, dir->(file,nothing)' '
git rm -rf . &&
git clean -fdqx &&
rm -rf .git &&
git init &&
>irrelevant &&
mkdir df &&
>df/file &&
git add -A &&
git commit -mA &&
git checkout -b side &&
git rm -rf df &&
git commit -mB &&
git checkout main &&
git rm -rf df &&
echo bla >df &&
git add -A &&
git commit -m "Add a newfile"
'
test_expect_success 'avoid unnecessary update, dir->(file,nothing)' '
git checkout -q main^0 &&
test-tool chmtime --get -3600 df >expect &&
git merge side &&
test-tool chmtime --get df >actual &&
test_cmp expect actual # "df" should have stayed intact
'
test_expect_success 'setup avoid unnecessary update, modify/delete' '
git rm -rf . &&
git clean -fdqx &&
rm -rf .git &&
git init &&
>irrelevant &&
>file &&
git add -A &&
git commit -mA &&
git checkout -b side &&
git rm -f file &&
git commit -m "Delete file" &&
git checkout main &&
echo bla >file &&
git add -A &&
git commit -m "Modify file"
'
test_expect_success 'avoid unnecessary update, modify/delete' '
git checkout -q main^0 &&
test-tool chmtime --get -3600 file >expect &&
test_must_fail git merge side &&
test-tool chmtime --get file >actual &&
test_cmp expect actual # "file" should have stayed intact
'
test_expect_success 'setup avoid unnecessary update, rename/add-dest' '
git rm -rf . &&
git clean -fdqx &&
rm -rf .git &&
git init &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n" >file &&
git add -A &&
git commit -mA &&
git checkout -b side &&
cp file newfile &&
git add -A &&
git commit -m "Add file copy" &&
git checkout main &&
git mv file newfile &&
git commit -m "Rename file"
'
test_expect_success 'avoid unnecessary update, rename/add-dest' '
git checkout -q main^0 &&
test-tool chmtime --get -3600 newfile >expect &&
git merge side &&
test-tool chmtime --get newfile >actual &&
test_cmp expect actual # "file" should have stayed intact
'
test_expect_success 'setup merge of rename + small change' '
git reset --hard &&
git checkout --orphan rename-plus-small-change &&
git rm -rf . &&
git clean -fdqx &&
echo ORIGINAL >file &&
git add file &&
test_tick &&
git commit -m Initial &&
git checkout -b rename_branch &&
git mv file renamed_file &&
git commit -m Rename &&
git checkout rename-plus-small-change &&
echo NEW-VERSION >file &&
git commit -a -m Reformat
'
test_expect_success 'merge rename + small change' '
git merge rename_branch &&
test_stdout_line_count = 1 git ls-files -s &&
test_stdout_line_count = 0 git ls-files -o &&
newhash=$(git rev-parse HEAD:renamed_file) &&
oldhash=$(git rev-parse HEAD~1:file) &&
test $newhash = $oldhash
'
test_expect_success 'setup for use of extended merge markers' '
git rm -rf . &&
git clean -fdqx &&
rm -rf .git &&
git init &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
git add original_file &&
git commit -mA &&
git checkout -b rename &&
echo 9 >>original_file &&
git add original_file &&
git mv original_file renamed_file &&
git commit -mB &&
git checkout main &&
echo 8.5 >>original_file &&
git add original_file &&
git commit -mC
'
test_expect_success 'merge main into rename has correct extended markers' '
git checkout rename^0 &&
test_must_fail git merge -s recursive main^0 &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
<<<<<<< HEAD:renamed_file
9
=======
8.5
>>>>>>> main^0:original_file
EOF
test_cmp expected renamed_file
'
test_expect_success 'merge rename into main has correct extended markers' '
git reset --hard &&
git checkout main^0 &&
test_must_fail git merge -s recursive rename^0 &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
<<<<<<< HEAD:original_file
8.5
=======
9
>>>>>>> rename^0:renamed_file
EOF
test_cmp expected renamed_file
'
test_expect_success 'setup spurious "refusing to lose untracked" message' '
git rm -rf . &&
git clean -fdqx &&
rm -rf .git &&
git init &&
> irrelevant_file &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
git add irrelevant_file original_file &&
git commit -mA &&
git checkout -b rename &&
git mv original_file renamed_file &&
git commit -mB &&
git checkout main &&
git rm original_file &&
git commit -mC
'
test_expect_success 'no spurious "refusing to lose untracked" message' '
git checkout main^0 &&
test_must_fail git merge rename^0 2>errors.txt &&
! grep "refusing to lose untracked file" errors.txt
'
test_expect_success 'do not follow renames for empty files' '
git checkout -f -b empty-base &&
>empty1 &&
git add empty1 &&
git commit -m base &&
echo content >empty1 &&
git add empty1 &&
git commit -m fill &&
git checkout -b empty-topic HEAD^ &&
git mv empty1 empty2 &&
git commit -m rename &&
test_must_fail git merge empty-base &&
test_must_be_empty empty2
'
test_done