merge-recursive: Improve handling of rename target vs. directory addition
authorElijah Newren <newren@gmail.com>
Fri, 12 Aug 2011 05:20:06 +0000 (23:20 -0600)
committerJunio C Hamano <gitster@pobox.com>
Sun, 14 Aug 2011 21:19:37 +0000 (14:19 -0700)
When dealing with file merging and renames and D/F conflicts and possible
criss-cross merges (how's that for a corner case?), we did not do a
thorough job ensuring the index and working directory had the correct
contents. Fix the logic in merge_content() to handle this. Also,
correct some erroneous tests in t6022 that were expecting the wrong number
of unmerged index entries. These changes fix one of the tests in t6042
(and almost fix another one from t6042 as well).

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
merge-recursive.c
t/t6022-merge-rename.sh
t/t6042-merge-rename-corner-cases.sh
index 7f169ade1e805899042120dc3bd146e2a0dfc9cd..c6f177896fa8b0bc5cc302b1874d0710c078a7f9 100644 (file)
@@ -1379,19 +1379,34 @@ static int merge_content(struct merge_options *o,
                        reason = "submodule";
                output(o, 1, "CONFLICT (%s): Merge conflict in %s",
                                reason, path);
-               if (involved_in_rename)
+               if (involved_in_rename && !df_conflict_remains)
                        update_stages(path, &one, &a, &b);
        }
 
        if (df_conflict_remains) {
                char *new_path;
-               update_file_flags(o, mfi.sha, mfi.mode, path,
-                                 o->call_depth || mfi.clean, 0);
+               if (o->call_depth) {
+                       remove_file_from_cache(path);
+               } else {
+                       if (!mfi.clean)
+                               update_stages(path, &one, &a, &b);
+                       else {
+                               int file_from_stage2 = was_tracked(path);
+                               struct diff_filespec merged;
+                               hashcpy(merged.sha1, mfi.sha);
+                               merged.mode = mfi.mode;
+
+                               update_stages(path, NULL,
+                                             file_from_stage2 ? &merged : NULL,
+                                             file_from_stage2 ? NULL : &merged);
+                       }
+
+               }
                new_path = unique_path(o, path, df_rename_conflict_branch);
-               mfi.clean = 0;
                output(o, 1, "Adding as %s instead", new_path);
-               update_file_flags(o, mfi.sha, mfi.mode, new_path, 0, 1);
+               update_file(o, 0, mfi.sha, mfi.mode, new_path);
                free(new_path);
+               mfi.clean = 0;
        } else {
                update_file(o, mfi.clean, mfi.sha, mfi.mode, path);
        }
@@ -1580,6 +1595,8 @@ static int process_df_entry(struct merge_options *o,
                        output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
                               "Adding %s as %s",
                               conf, path, other_branch, path, new_path);
+                       if (o->call_depth)
+                               remove_file_from_cache(path);
                        update_file(o, 0, sha, mode, new_path);
                        if (o->call_depth)
                                remove_file_from_cache(path);
index 6ff4bd26ad72b0f7da29476be23a6f3e88e4a05d..fcc1d4cfff7fe71d0c581ce2177a719671dfb66d 100755 (executable)
@@ -307,7 +307,7 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
        grep "Auto-merging dir" output &&
        grep "Adding as dir~HEAD instead" output &&
 
-       test 2 -eq "$(git ls-files -u | wc -l)" &&
+       test 3 -eq "$(git ls-files -u | wc -l)" &&
        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
 
        test_must_fail git diff --quiet &&
@@ -329,7 +329,7 @@ test_expect_success 'Same as previous, but merged other way' '
        grep "Auto-merging dir" output &&
        grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
 
-       test 2 -eq "$(git ls-files -u | wc -l)" &&
+       test 3 -eq "$(git ls-files -u | wc -l)" &&
        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
 
        test_must_fail git diff --quiet &&
index 668ec6d498723dd49a395311c9706c177003e499..968055d47cfe2cd55110c606d694c76b648934fe 100755 (executable)
@@ -234,7 +234,7 @@ test_expect_success 'setup content merge + rename/directory conflict' '
        git commit -m left
 '
 
-test_expect_failure 'rename/directory conflict + clean content merge' '
+test_expect_success 'rename/directory conflict + clean content merge' '
        git reset --hard &&
        git reset --hard &&
        git clean -fdqx &&