diff --git a/git-mergetool.sh b/git-mergetool.sh index 9f77e3a8bb..f67bab55e8 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -126,7 +126,12 @@ resolve_deleted_merge () { case "$ans" in [mMcC]*) git add -- "$MERGED" - cleanup_temp_files --save-backup + if test "$merge_keep_backup" = "true" + then + cleanup_temp_files --save-backup + else + cleanup_temp_files + fi return 0 ;; [dD]*) @@ -135,6 +140,10 @@ resolve_deleted_merge () { return 0 ;; [aA]*) + if test "$merge_keep_temporaries" = "false" + then + cleanup_temp_files + fi return 1 ;; esac @@ -282,8 +291,14 @@ merge_file () { return fi - mv -- "$MERGED" "$BACKUP" - cp -- "$BACKUP" "$MERGED" + if test -f "$MERGED" + then + mv -- "$MERGED" "$BACKUP" + cp -- "$BACKUP" "$MERGED" + fi + # Create a parent directory to handle delete/delete conflicts + # where the base's directory no longer exists. + mkdir -p "$(dirname "$MERGED")" checkout_staged_file 1 "$MERGED" "$BASE" checkout_staged_file 2 "$MERGED" "$LOCAL" @@ -295,7 +310,9 @@ merge_file () { describe_file "$local_mode" "local" "$LOCAL" describe_file "$remote_mode" "remote" "$REMOTE" resolve_deleted_merge - return + status=$? + rmdir -p "$(dirname "$MERGED")" 2>/dev/null + return $status fi if is_symlink "$local_mode" || is_symlink "$remote_mode" diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 6f12b235b3..76306cf268 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -243,6 +243,70 @@ test_expect_success 'mergetool takes partial path' ' git reset --hard ' +test_expect_success 'mergetool delete/delete conflict' ' + git checkout -b delete-base branch1 && + mkdir -p a/a && + (echo one; echo two; echo 3; echo 4) >a/a/file.txt && + git add a/a/file.txt && + git commit -m"base file" && + git checkout -b move-to-b delete-base && + mkdir -p b/b && + git mv a/a/file.txt b/b/file.txt && + (echo one; echo two; echo 4) >b/b/file.txt && + git commit -a -m"move to b" && + git checkout -b move-to-c delete-base && + mkdir -p c/c && + git mv a/a/file.txt c/c/file.txt && + (echo one; echo two; echo 3) >c/c/file.txt && + git commit -a -m"move to c" && + test_must_fail git merge move-to-b && + echo d | git mergetool a/a/file.txt && + ! test -f a/a/file.txt && + git reset --hard HEAD && + test_must_fail git merge move-to-b && + echo m | git mergetool a/a/file.txt && + test -f b/b/file.txt && + git reset --hard HEAD && + test_must_fail git merge move-to-b && + ! echo a | git mergetool a/a/file.txt && + ! test -f a/a/file.txt && + git reset --hard HEAD +' + +test_expect_success 'mergetool produces no errors when keepBackup is used' ' + test_config mergetool.keepBackup true && + test_must_fail git merge move-to-b && + : >expect && + echo d | git mergetool a/a/file.txt 2>actual && + test_cmp expect actual && + ! test -d a && + git reset --hard HEAD +' + +test_expect_success 'mergetool honors tempfile config for deleted files' ' + test_config mergetool.keepTemporaries false && + test_must_fail git merge move-to-b && + echo d | git mergetool a/a/file.txt && + ! test -d a && + git reset --hard HEAD +' + +test_expect_success 'mergetool keeps tempfiles when aborting delete/delete' ' + test_config mergetool.keepTemporaries true && + test_must_fail git merge move-to-b && + ! (echo a; echo n) | git mergetool a/a/file.txt && + test -d a/a && + cat >expect <<-\EOF && + file_BASE_.txt + file_LOCAL_.txt + file_REMOTE_.txt + EOF + ls -1 a/a | sed -e "s/[0-9]*//g" >actual && + test_cmp expect actual && + git clean -fdx && + git reset --hard HEAD +' + test_expect_success 'deleted vs modified submodule' ' git checkout -b test6 branch1 && git submodule update -N &&