merge-recursive: Improve handling of rename target vs. directory addition

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>

Elijah Newren committed Aug 11, 2011 at 23:20 UTC 51931bf08e7de1f597d36bc2fd38b5310b6da7dd
3 files changed +25 -8
merge-recursive.c
+22 -5
@@ -1379,19 +1379,34 @@ static int merge_content(struct merge_options *o,
1379 reason = "submodule";
1380 output(o, 1, "CONFLICT (%s): Merge conflict in %s",
1381 reason, path);
1382 - if (involved_in_rename)
1382 + if (involved_in_rename && !df_conflict_remains)
1383 update_stages(path, &one, &a, &b);
1384 }
1385
1386 if (df_conflict_remains) {
1387 char *new_path;
1388 - update_file_flags(o, mfi.sha, mfi.mode, path,
1389 - o->call_depth || mfi.clean, 0);
1388 + if (o->call_depth) {
1389 + remove_file_from_cache(path);
1390 + } else {
1391 + if (!mfi.clean)
1392 + update_stages(path, &one, &a, &b);
1393 + else {
1394 + int file_from_stage2 = was_tracked(path);
1395 + struct diff_filespec merged;
1396 + hashcpy(merged.sha1, mfi.sha);
1397 + merged.mode = mfi.mode;
1398 +
1399 + update_stages(path, NULL,
1400 + file_from_stage2 ? &merged : NULL,
1401 + file_from_stage2 ? NULL : &merged);
1402 + }
1403 +
1404 + }
1405 new_path = unique_path(o, path, df_rename_conflict_branch);
1391 - mfi.clean = 0;
1406 output(o, 1, "Adding as %s instead", new_path);
1393 - update_file_flags(o, mfi.sha, mfi.mode, new_path, 0, 1);
1407 + update_file(o, 0, mfi.sha, mfi.mode, new_path);
1408 free(new_path);
1409 + mfi.clean = 0;
1410 } else {
1411 update_file(o, mfi.clean, mfi.sha, mfi.mode, path);
1412 }
@@ -1580,6 +1595,8 @@ static int process_df_entry(struct merge_options *o,
1595 output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
1596 "Adding %s as %s",
1597 conf, path, other_branch, path, new_path);
1598 + if (o->call_depth)
1599 + remove_file_from_cache(path);
1600 update_file(o, 0, sha, mode, new_path);
1601 if (o->call_depth)
1602 remove_file_from_cache(path);
t/t6022-merge-rename.sh
+2 -2
@@ -307,7 +307,7 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
307 grep "Auto-merging dir" output &&
308 grep "Adding as dir~HEAD instead" output &&
309
310 - test 2 -eq "$(git ls-files -u | wc -l)" &&
310 + test 3 -eq "$(git ls-files -u | wc -l)" &&
311 test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
312
313 test_must_fail git diff --quiet &&
@@ -329,7 +329,7 @@ test_expect_success 'Same as previous, but merged other way' '
329 grep "Auto-merging dir" output &&
330 grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
331
332 - test 2 -eq "$(git ls-files -u | wc -l)" &&
332 + test 3 -eq "$(git ls-files -u | wc -l)" &&
333 test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
334
335 test_must_fail git diff --quiet &&
t/t6042-merge-rename-corner-cases.sh
+1 -1
@@ -234,7 +234,7 @@ test_expect_success 'setup content merge + rename/directory conflict' '
234 git commit -m left
235 '
236
237 -test_expect_failure 'rename/directory conflict + clean content merge' '
237 +test_expect_success 'rename/directory conflict + clean content merge' '
238 git reset --hard &&
239 git reset --hard &&
240 git clean -fdqx &&