merge-recursive: switch directory rename detection default

When all of x/a, x/b, and x/c have moved to z/a, z/b, and z/c on one branch, there is a question about whether x/d added on a different branch should remain at x/d or appear at z/d when the two branches are merged. There are different possible viewpoints here: A) The file was placed at x/d; it's unrelated to the other files in x/ so it doesn't matter that all the files from x/ moved to z/ on one branch; x/d should still remain at x/d. B) x/d is related to the other files in x/, and x/ was renamed to z/; therefore x/d should be moved to z/d. Since there was no ability to detect directory renames prior to git-2.18, users experienced (A) regardless of context. Choice (B) was implemented in git-2.18, with no option to go back to (A), and has been in use since. However, one user reported that the merge results did not match their expectations, making the change of default problematic, especially since there was no notice printed when directory rename detection moved files. Note that there is also a third possibility here: C) There are different answers depending on the context and content that cannot be determined by git, so this is a conflict. Use a higher stage in the index to record the conflict and notify the user of the potential issue instead of silently selecting a resolution for them. Add an option for users to specify their preference for whether to use directory rename detection, and default to (C). Even when directory rename detection is on, add notice messages about files moved into new directories. As a sidenote, x/d did not have to be a new file here; it could have already existed at some other path and been renamed to x/d, with directory rename detection just renaming it again to z/d. Thus, it's not just new files, but also a modification to all rename types (normal renames, rename/add, rename/delete, rename/rename(1to1), rename/rename(1to2), and rename/rename(2to1)). Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Apr 5, 2019 at 08:00 UTC 8c8e5bd6eb331d055aa7fa6345f6dcdadd658979
5 files changed +552 -87
Documentation/config/merge.txt
+16 -3
@@ -39,9 +39,22 @@ merge.renameLimit::
39 is turned off.
40
41 merge.renames::
42 - Whether and how Git detects renames. If set to "false",
43 - rename detection is disabled. If set to "true", basic rename
44 - detection is enabled. Defaults to the value of diff.renames.
42 + Whether Git detects renames. If set to "false", rename detection
43 + is disabled. If set to "true", basic rename detection is enabled.
44 + Defaults to the value of diff.renames.
45 +
46 +merge.directoryRenames::
47 + Whether Git detects directory renames, affecting what happens at
48 + merge time to new files added to a directory on one side of
49 + history when that directory was renamed on the other side of
50 + history. If merge.directoryRenames is set to "false", directory
51 + rename detection is disabled, meaning that such new files will be
52 + left behind in the old directory. If set to "true", directory
53 + rename detection is enabled, meaning that such new files will be
54 + moved into the new directory. If set to "conflict", a conflict
55 + will be reported for such paths. If merge.renames is false,
56 + merge.directoryRenames is ignored and treated as false. Defaults
57 + to "conflict".
58
59 merge.renormalize::
60 Tell Git that canonical representation of files in the
merge-recursive.c
+123 -23
@@ -1370,30 +1370,39 @@ static int handle_rename_via_dir(struct merge_options *opt,
1370 */
1371 const struct rename *ren = ci->ren1;
1372 const struct diff_filespec *dest = ren->pair->two;
1373 + char *file_path = dest->path;
1374 + int mark_conflicted = (opt->detect_directory_renames == 1);
1375 + assert(ren->dir_rename_original_dest);
1376
1377 if (!opt->call_depth && would_lose_untracked(opt, dest->path)) {
1375 - char *alt_path = unique_path(opt, dest->path, ren->branch);
1376 -
1378 + mark_conflicted = 1;
1379 + file_path = unique_path(opt, dest->path, ren->branch);
1380 output(opt, 1, _("Error: Refusing to lose untracked file at %s; "
1378 - "writing to %s instead."),
1379 - dest->path, alt_path);
1381 + "writing to %s instead."),
1382 + dest->path, file_path);
1383 + }
1384 +
1385 + if (mark_conflicted) {
1386 /*
1381 - * Write the file in worktree at alt_path, but not in the
1382 - * index. Instead, write to dest->path for the index but
1383 - * only at the higher appropriate stage.
1387 + * Write the file in worktree at file_path. In the index,
1388 + * only record the file at dest->path in the appropriate
1389 + * higher stage.
1390 */
1385 - if (update_file(opt, 0, dest, alt_path))
1391 + if (update_file(opt, 0, dest, file_path))
1392 return -1;
1387 - free(alt_path);
1388 - return update_stages(opt, dest->path, NULL,
1389 - ren->branch == opt->branch1 ? dest : NULL,
1390 - ren->branch == opt->branch1 ? NULL : dest);
1393 + if (file_path != dest->path)
1394 + free(file_path);
1395 + if (update_stages(opt, dest->path, NULL,
1396 + ren->branch == opt->branch1 ? dest : NULL,
1397 + ren->branch == opt->branch1 ? NULL : dest))
1398 + return -1;
1399 + return 0; /* not clean, but conflicted */
1400 + } else {
1401 + /* Update dest->path both in index and in worktree */
1402 + if (update_file(opt, 1, dest, dest->path))
1403 + return -1;
1404 + return 1; /* clean */
1405 }
1392 -
1393 - /* Update dest->path both in index and in worktree */
1394 - if (update_file(opt, 1, dest, dest->path))
1395 - return -1;
1396 - return 0;
1406 }
1407
1408 static int handle_change_delete(struct merge_options *opt,
@@ -3090,10 +3099,88 @@ static int handle_rename_normal(struct merge_options *opt,
3099 const struct diff_filespec *b,
3100 struct rename_conflict_info *ci)
3101 {
3093 - /* Merge the content and write it out */
3102 + struct rename *ren = ci->ren1;
3103 struct merge_file_info mfi;
3095 - return handle_content_merge(&mfi, opt, path, was_dirty(opt, path),
3096 - o, a, b, ci);
3104 + int clean;
3105 + int side = (ren->branch == opt->branch1 ? 2 : 3);
3106 +
3107 + /* Merge the content and write it out */
3108 + clean = handle_content_merge(&mfi, opt, path, was_dirty(opt, path),
3109 + o, a, b, ci);
3110 +
3111 + if (clean && opt->detect_directory_renames == 1 &&
3112 + ren->dir_rename_original_dest) {
3113 + if (update_stages(opt, path,
3114 + NULL,
3115 + side == 2 ? &mfi.blob : NULL,
3116 + side == 2 ? NULL : &mfi.blob))
3117 + return -1;
3118 + clean = 0; /* not clean, but conflicted */
3119 + }
3120 + return clean;
3121 +}
3122 +
3123 +static void dir_rename_warning(const char *msg,
3124 + int is_add,
3125 + int clean,
3126 + struct merge_options *opt,
3127 + struct rename *ren)
3128 +{
3129 + const char *other_branch;
3130 + other_branch = (ren->branch == opt->branch1 ?
3131 + opt->branch2 : opt->branch1);
3132 + if (is_add) {
3133 + output(opt, clean ? 2 : 1, msg,
3134 + ren->pair->one->path, ren->branch,
3135 + other_branch, ren->pair->two->path);
3136 + return;
3137 + }
3138 + output(opt, clean ? 2 : 1, msg,
3139 + ren->pair->one->path, ren->dir_rename_original_dest, ren->branch,
3140 + other_branch, ren->pair->two->path);
3141 +}
3142 +static int warn_about_dir_renamed_entries(struct merge_options *opt,
3143 + struct rename *ren)
3144 +{
3145 + const char *msg;
3146 + int clean = 1, is_add;
3147 +
3148 + if (!ren)
3149 + return clean;
3150 +
3151 + /* Return early if ren was not affected/created by a directory rename */
3152 + if (!ren->dir_rename_original_dest)
3153 + return clean;
3154 +
3155 + /* Sanity checks */
3156 + assert(opt->detect_directory_renames > 0);
3157 + assert(ren->dir_rename_original_type == 'A' ||
3158 + ren->dir_rename_original_type == 'R');
3159 +
3160 + /* Check whether to treat directory renames as a conflict */
3161 + clean = (opt->detect_directory_renames == 2);
3162 +
3163 + is_add = (ren->dir_rename_original_type == 'A');
3164 + if (ren->dir_rename_original_type == 'A' && clean) {
3165 + msg = _("Path updated: %s added in %s inside a "
3166 + "directory that was renamed in %s; moving it to %s.");
3167 + } else if (ren->dir_rename_original_type == 'A' && !clean) {
3168 + msg = _("CONFLICT (file location): %s added in %s "
3169 + "inside a directory that was renamed in %s, "
3170 + "suggesting it should perhaps be moved to %s.");
3171 + } else if (ren->dir_rename_original_type == 'R' && clean) {
3172 + msg = _("Path updated: %s renamed to %s in %s, inside a "
3173 + "directory that was renamed in %s; moving it to %s.");
3174 + } else if (ren->dir_rename_original_type == 'R' && !clean) {
3175 + msg = _("CONFLICT (file location): %s renamed to %s in %s, "
3176 + "inside a directory that was renamed in %s, "
3177 + "suggesting it should perhaps be moved to %s.");
3178 + } else {
3179 + BUG("Impossible dir_rename_original_type/clean combination");
3180 + }
3181 + dir_rename_warning(msg, is_add, clean, opt, ren);
3182 +
3183 + return clean;
3184 }
3185
3186 /* Per entry merge function */
@@ -3115,6 +3202,10 @@ static int process_entry(struct merge_options *opt,
3202 if (entry->rename_conflict_info) {
3203 struct rename_conflict_info *ci = entry->rename_conflict_info;
3204 struct diff_filespec *temp;
3205 + int path_clean;
3206 +
3207 + path_clean = warn_about_dir_renamed_entries(opt, ci->ren1);
3208 + path_clean &= warn_about_dir_renamed_entries(opt, ci->ren2);
3209
3210 /*
3211 * For cases with a single rename, {o,a,b}->path have all been
@@ -3135,9 +3226,7 @@ static int process_entry(struct merge_options *opt,
3226 ci);
3227 break;
3228 case RENAME_VIA_DIR:
3138 - clean_merge = 1;
3139 - if (handle_rename_via_dir(opt, ci))
3140 - clean_merge = -1;
3229 + clean_merge = handle_rename_via_dir(opt, ci);
3230 break;
3231 case RENAME_ADD:
3232 /*
@@ -3187,6 +3276,8 @@ static int process_entry(struct merge_options *opt,
3276 entry->processed = 0;
3277 break;
3278 }
3279 + if (path_clean < clean_merge)
3280 + clean_merge = path_clean;
3281 } else if (o_valid && (!a_valid || !b_valid)) {
3282 /* Case A: Deleted in one */
3283 if ((!a_valid && !b_valid) ||
@@ -3558,6 +3649,15 @@ static void merge_recursive_config(struct merge_options *opt)
3649 opt->merge_detect_rename = git_config_rename("merge.renames", value);
3650 free(value);
3651 }
3652 + if (!git_config_get_string("merge.directoryrenames", &value)) {
3653 + int boolval = git_parse_maybe_bool(value);
3654 + if (0 <= boolval) {
3655 + opt->detect_directory_renames = boolval ? 2 : 0;
3656 + } else if (!strcasecmp(value, "conflict")) {
3657 + opt->detect_directory_renames = 1;
3658 + } /* avoid erroring on values from future versions of git */
3659 + free(value);
3660 + }
3661 git_config(git_xmerge_config, NULL);
3662 }
3663
t/t3401-rebase-and-am-rename.sh
+4 -4
@@ -42,7 +42,7 @@ test_expect_success 'rebase --interactive: directory rename detected' '
42 git checkout B^0 &&
43
44 set_fake_editor &&
45 - FAKE_LINES="1" git rebase --interactive A &&
45 + FAKE_LINES="1" git -c merge.directoryRenames=true rebase --interactive A &&
46
47 git ls-files -s >out &&
48 test_line_count = 5 out &&
@@ -58,7 +58,7 @@ test_expect_failure 'rebase (am): directory rename detected' '
58
59 git checkout B^0 &&
60
61 - git rebase A &&
61 + git -c merge.directoryRenames=true rebase A &&
62
63 git ls-files -s >out &&
64 test_line_count = 5 out &&
@@ -74,7 +74,7 @@ test_expect_success 'rebase --merge: directory rename detected' '
74
75 git checkout B^0 &&
76
77 - git rebase --merge A &&
77 + git -c merge.directoryRenames=true rebase --merge A &&
78
79 git ls-files -s >out &&
80 test_line_count = 5 out &&
@@ -92,7 +92,7 @@ test_expect_failure 'am: directory rename detected' '
92
93 git format-patch -1 B &&
94
95 - git am --3way 0001*.patch &&
95 + git -c merge.directoryRenames=true am --3way 0001*.patch &&
96
97 git ls-files -s >out &&
98 test_line_count = 5 out &&
t/t6043-merge-rename-directories.sh
+405 -53
@@ -75,7 +75,7 @@ test_expect_success '1a-check: Simple directory rename detection' '
75
76 git checkout A^0 &&
77
78 - git merge -s recursive B^0 &&
78 + git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
79
80 git ls-files -s >out &&
81 test_line_count = 4 out &&
@@ -142,7 +142,7 @@ test_expect_success '1b-check: Merge a directory with another' '
142
143 git checkout A^0 &&
144
145 - git merge -s recursive B^0 &&
145 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
146
147 git ls-files -s >out &&
148 test_line_count = 4 out &&
@@ -201,7 +201,7 @@ test_expect_success '1c-check: Transitive renaming' '
201
202 git checkout A^0 &&
203
204 - git merge -s recursive B^0 &&
204 + git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
205
206 git ls-files -s >out &&
207 test_line_count = 3 out &&
@@ -270,7 +270,7 @@ test_expect_success '1d-check: Directory renames cause a rename/rename(2to1) con
270
271 git checkout A^0 &&
272
273 - test_must_fail git merge -s recursive B^0 >out &&
273 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
274 test_i18ngrep "CONFLICT (rename/rename)" out &&
275
276 git ls-files -s >out &&
@@ -350,7 +350,7 @@ test_expect_success '1e-check: Renamed directory, with all files being renamed t
350
351 git checkout A^0 &&
352
353 - git merge -s recursive B^0 &&
353 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
354
355 git ls-files -s >out &&
356 test_line_count = 3 out &&
@@ -416,7 +416,7 @@ test_expect_success '1f-check: Split a directory into two other directories' '
416
417 git checkout A^0 &&
418
419 - git merge -s recursive B^0 &&
419 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
420
421 git ls-files -s >out &&
422 test_line_count = 6 out &&
@@ -497,7 +497,7 @@ test_expect_success '2a-check: Directory split into two on one side, with equal
497
498 git checkout A^0 &&
499
500 - test_must_fail git merge -s recursive B^0 >out &&
500 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
501 test_i18ngrep "CONFLICT.*directory rename split" out &&
502
503 git ls-files -s >out &&
@@ -559,7 +559,7 @@ test_expect_success '2b-check: Directory split into two on one side, with equal
559
560 git checkout A^0 &&
561
562 - git merge -s recursive B^0 >out &&
562 + git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
563
564 git ls-files -s >out &&
565 test_line_count = 3 out &&
@@ -640,7 +640,7 @@ test_expect_success '3a-check: Avoid implicit rename if involved as source on ot
640
641 git checkout A^0 &&
642
643 - git merge -s recursive B^0 &&
643 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
644
645 git ls-files -s >out &&
646 test_line_count = 3 out &&
@@ -705,7 +705,7 @@ test_expect_success '3b-check: Avoid implicit rename if involved as source on cu
705
706 git checkout A^0 &&
707
708 - test_must_fail git merge -s recursive B^0 >out &&
708 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
709 test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out &&
710 test_i18ngrep ! CONFLICT.*rename/rename.*y/d out &&
711
@@ -826,7 +826,7 @@ test_expect_success '4a-check: Directory split, with original directory still pr
826
827 git checkout A^0 &&
828
829 - git merge -s recursive B^0 &&
829 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
830
831 git ls-files -s >out &&
832 test_line_count = 5 out &&
@@ -915,7 +915,7 @@ test_expect_success '5a-check: Merge directories, other side adds files to origi
915
916 git checkout A^0 &&
917
918 - test_must_fail git merge -s recursive B^0 >out &&
918 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
919 test_i18ngrep "CONFLICT.*implicit dir rename" out &&
920
921 git ls-files -s >out &&
@@ -989,7 +989,7 @@ test_expect_success '5b-check: Rename/delete in order to get add/add/add conflic
989
990 git checkout A^0 &&
991
992 - test_must_fail git merge -s recursive B^0 >out &&
992 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
993 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
994
995 git ls-files -s >out &&
@@ -1069,7 +1069,7 @@ test_expect_success '5c-check: Transitive rename would cause rename/rename/renam
1069
1070 git checkout A^0 &&
1071
1072 - test_must_fail git merge -s recursive B^0 >out &&
1072 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1073 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&
1074 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
1075
@@ -1153,7 +1153,7 @@ test_expect_success '5d-check: Directory/file/file conflict due to directory ren
1153
1154 git checkout A^0 &&
1155
1156 - test_must_fail git merge -s recursive B^0 >out &&
1156 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1157 test_i18ngrep "CONFLICT (file/directory).*y/d" out &&
1158
1159 git ls-files -s >out &&
@@ -1243,7 +1243,7 @@ test_expect_success '6a-check: Tricky rename/delete' '
1243
1244 git checkout A^0 &&
1245
1246 - test_must_fail git merge -s recursive B^0 >out &&
1246 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1247 test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&
1248
1249 git ls-files -s >out &&
@@ -1308,7 +1308,7 @@ test_expect_success '6b-check: Same rename done on both sides' '
1308
1309 git checkout A^0 &&
1310
1311 - git merge -s recursive B^0 &&
1311 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
1312
1313 git ls-files -s >out &&
1314 test_line_count = 3 out &&
@@ -1370,7 +1370,7 @@ test_expect_success '6c-check: Rename only done on same side' '
1370
1371 git checkout A^0 &&
1372
1373 - git merge -s recursive B^0 &&
1373 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
1374
1375 git ls-files -s >out &&
1376 test_line_count = 3 out &&
@@ -1432,7 +1432,7 @@ test_expect_success '6d-check: We do not always want transitive renaming' '
1432
1433 git checkout A^0 &&
1434
1435 - git merge -s recursive B^0 &&
1435 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
1436
1437 git ls-files -s >out &&
1438 test_line_count = 3 out &&
@@ -1495,7 +1495,7 @@ test_expect_success '6e-check: Add/add from one side' '
1495
1496 git checkout A^0 &&
1497
1498 - git merge -s recursive B^0 &&
1498 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
1499
1500 git ls-files -s >out &&
1501 test_line_count = 4 out &&
@@ -1591,7 +1591,7 @@ test_expect_success '7a-check: rename-dir vs. rename-dir (NOT split evenly) PLUS
1591
1592 git checkout A^0 &&
1593
1594 - test_must_fail git merge -s recursive B^0 >out &&
1594 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1595 test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
1596 test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
1597
@@ -1663,7 +1663,7 @@ test_expect_success '7b-check: rename/rename(2to1), but only due to transitive r
1663
1664 git checkout A^0 &&
1665
1666 - test_must_fail git merge -s recursive B^0 >out &&
1666 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1667 test_i18ngrep "CONFLICT (rename/rename)" out &&
1668
1669 git ls-files -s >out &&
@@ -1740,7 +1740,7 @@ test_expect_success '7c-check: rename/rename(1to...2or3); transitive rename may
1740
1741 git checkout A^0 &&
1742
1743 - test_must_fail git merge -s recursive B^0 >out &&
1743 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1744 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
1745
1746 git ls-files -s >out &&
@@ -1804,7 +1804,7 @@ test_expect_success '7d-check: transitive rename involved in rename/delete; how
1804
1805 git checkout A^0 &&
1806
1807 - test_must_fail git merge -s recursive B^0 >out &&
1807 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1808 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1809
1810 git ls-files -s >out &&
@@ -1894,7 +1894,7 @@ test_expect_success '7e-check: transitive rename in rename/delete AND dirs in th
1894
1895 git checkout A^0 &&
1896
1897 - test_must_fail git merge -s recursive B^0 >out &&
1897 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1898 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1899
1900 git ls-files -s >out &&
@@ -1985,7 +1985,7 @@ test_expect_success '8a-check: Dual-directory rename, one into the others way' '
1985
1986 git checkout A^0 &&
1987
1988 - git merge -s recursive B^0 &&
1988 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
1989
1990 git ls-files -s >out &&
1991 test_line_count = 6 out &&
@@ -2063,7 +2063,7 @@ test_expect_success '8b-check: Dual-directory rename, one into the others way, w
2063
2064 git checkout A^0 &&
2065
2066 - git merge -s recursive B^0 &&
2066 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
2067
2068 git ls-files -s >out &&
2069 test_line_count = 6 out &&
@@ -2135,7 +2135,7 @@ test_expect_success '8c-check: modify/delete or rename+modify/delete' '
2135
2136 git checkout A^0 &&
2137
2138 - test_must_fail git merge -s recursive B^0 >out &&
2138 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2139 test_i18ngrep "CONFLICT (modify/delete).* z/d" out &&
2140
2141 git ls-files -s >out &&
@@ -2212,7 +2212,7 @@ test_expect_success '8d-check: rename/delete...or not?' '
2212
2213 git checkout A^0 &&
2214
2215 - git merge -s recursive B^0 &&
2215 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
2216
2217 git ls-files -s >out &&
2218 test_line_count = 3 out &&
@@ -2287,7 +2287,7 @@ test_expect_success '8e-check: Both sides rename, one side adds to original dire
2287
2288 git checkout A^0 &&
2289
2290 - test_must_fail git merge -s recursive B^0 >out 2>err &&
2290 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
2291 test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
2292 test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
2293
@@ -2374,7 +2374,7 @@ test_expect_success '9a-check: Inner renamed directory within outer renamed dire
2374
2375 git checkout A^0 &&
2376
2377 - git merge -s recursive B^0 &&
2377 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
2378
2379 git ls-files -s >out &&
2380 test_line_count = 7 out &&
@@ -2444,7 +2444,7 @@ test_expect_success '9b-check: Transitive rename with content merge' '
2444
2445 git checkout A^0 &&
2446
2447 - git merge -s recursive B^0 &&
2447 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
2448
2449 git ls-files -s >out &&
2450 test_line_count = 3 out &&
@@ -2534,7 +2534,7 @@ test_expect_success '9c-check: Doubly transitive rename?' '
2534
2535 git checkout A^0 &&
2536
2537 - git merge -s recursive B^0 >out &&
2537 + git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2538 test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
2539
2540 git ls-files -s >out &&
@@ -2622,7 +2622,7 @@ test_expect_success '9d-check: N-way transitive rename?' '
2622
2623 git checkout A^0 &&
2624
2625 - git merge -s recursive B^0 >out &&
2625 + git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2626 test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
2627 test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
2628 test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
@@ -2704,7 +2704,7 @@ test_expect_success C_LOCALE_OUTPUT '9e-check: N-to-1 whammo' '
2704
2705 git checkout A^0 &&
2706
2707 - test_must_fail git merge -s recursive B^0 >out &&
2707 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2708 grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&
2709 grep -q dir1/yo error_line &&
2710 grep -q dir2/yo error_line &&
@@ -2782,7 +2782,7 @@ test_expect_success '9f-check: Renamed directory that only contained immediate s
2782
2783 git checkout A^0 &&
2784
2785 - git merge -s recursive B^0 &&
2785 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
2786
2787 git ls-files -s >out &&
2788 test_line_count = 4 out &&
@@ -2849,7 +2849,7 @@ test_expect_failure '9g-check: Renamed directory that only contained immediate s
2849
2850 git checkout A^0 &&
2851
2852 - git merge -s recursive B^0 &&
2852 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
2853
2854 git ls-files -s >out &&
2855 test_line_count = 4 out &&
@@ -2918,7 +2918,7 @@ test_expect_success '9h-check: Avoid dir rename on merely modified path' '
2918
2919 git checkout A^0 &&
2920
2921 - git merge -s recursive B^0 &&
2921 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
2922
2923 git ls-files -s >out &&
2924 test_line_count = 3 out &&
@@ -2993,7 +2993,7 @@ test_expect_success '10a-check: Overwrite untracked with normal rename/delete' '
2993 echo very >z/c &&
2994 echo important >z/d &&
2995
2996 - test_must_fail git merge -s recursive B^0 >out 2>err &&
2996 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
2997 test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&
2998
2999 git ls-files -s >out &&
@@ -3061,7 +3061,7 @@ test_expect_success '10b-check: Overwrite untracked with dir rename + delete' '
3061 echo important >y/d &&
3062 echo contents >y/e &&
3063
3064 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3064 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3065 test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
3066 test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
3067
@@ -3137,7 +3137,7 @@ test_expect_success '10c-check: Overwrite untracked with dir rename/rename(1to2)
3137 git checkout A^0 &&
3138 echo important >y/c &&
3139
3140 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3140 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3141 test_i18ngrep "CONFLICT (rename/rename)" out &&
3142 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
3143
@@ -3174,7 +3174,7 @@ test_expect_success '10c-check: Overwrite untracked with dir rename/rename(1to2)
3174 mkdir y &&
3175 echo important >y/c &&
3176
3177 - test_must_fail git merge -s recursive A^0 >out 2>err &&
3177 + test_must_fail git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
3178 test_i18ngrep "CONFLICT (rename/rename)" out &&
3179 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~HEAD instead" out &&
3180
@@ -3249,7 +3249,7 @@ test_expect_success '10d-check: Delete untracked with dir rename/rename(2to1)' '
3249 git checkout A^0 &&
3250 echo important >y/wham &&
3251
3252 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3252 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3253 test_i18ngrep "CONFLICT (rename/rename)" out &&
3254 test_i18ngrep "Refusing to lose untracked file at y/wham" out &&
3255
@@ -3327,7 +3327,7 @@ test_expect_failure '10e-check: Does git complain about untracked file that is n
3327 mkdir z &&
3328 echo random >z/c &&
3329
3330 - git merge -s recursive B^0 >out 2>err &&
3330 + git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3331 test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&
3332
3333 git ls-files -s >out &&
@@ -3407,7 +3407,7 @@ test_expect_success '11a-check: Avoid losing dirty contents with simple rename'
3407 git checkout A^0 &&
3408 echo stuff >>z/c &&
3409
3410 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3410 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3411 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3412
3413 test_seq 1 10 >expected &&
@@ -3479,7 +3479,7 @@ test_expect_success '11b-check: Avoid losing dirty file involved in directory re
3479 git checkout A^0 &&
3480 echo stuff >>z/c &&
3481
3482 - git merge -s recursive B^0 >out 2>err &&
3482 + git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3483 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3484
3485 grep -q stuff z/c &&
@@ -3554,7 +3554,7 @@ test_expect_success '11c-check: Avoid losing not-uptodate with rename + D/F conf
3554 git checkout A^0 &&
3555 echo stuff >>y/c &&
3556
3557 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3557 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3558 test_i18ngrep "following files would be overwritten by merge" err &&
3559
3560 grep -q stuff y/c &&
@@ -3621,7 +3621,7 @@ test_expect_success '11d-check: Avoid losing not-uptodate with rename + D/F conf
3621 git checkout A^0 &&
3622 echo stuff >>z/c &&
3623
3624 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3624 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3625 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3626
3627 grep -q stuff z/c &&
@@ -3700,7 +3700,7 @@ test_expect_success '11e-check: Avoid deleting not-uptodate with dir rename/rena
3700 git checkout A^0 &&
3701 echo mods >>y/c &&
3702
3703 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3703 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3704 test_i18ngrep "CONFLICT (rename/rename)" out &&
3705 test_i18ngrep "Refusing to lose dirty file at y/c" out &&
3706
@@ -3782,7 +3782,7 @@ test_expect_success '11f-check: Avoid deleting not-uptodate with dir rename/rena
3782 git checkout A^0 &&
3783 echo important >>y/wham &&
3784
3785 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3785 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3786 test_i18ngrep "CONFLICT (rename/rename)" out &&
3787 test_i18ngrep "Refusing to lose dirty file at y/wham" out &&
3788
@@ -3870,7 +3870,7 @@ test_expect_success '12a-check: Moving one directory hierarchy into another' '
3870
3871 git checkout A^0 &&
3872
3873 - git merge -s recursive B^0 &&
3873 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
3874
3875 git ls-files -s >out &&
3876 test_line_count = 6 out &&
@@ -3946,7 +3946,7 @@ test_expect_success '12b-check: Moving two directory hierarchies into each other
3946
3947 git checkout A^0 &&
3948
3949 - git merge -s recursive B^0 &&
3949 + git -c merge.directoryRenames=true merge -s recursive B^0 &&
3950
3951 git ls-files -s >out &&
3952 test_line_count = 4 out &&
@@ -4016,7 +4016,7 @@ test_expect_success '12c-check: Moving one directory hierarchy into another w/ c
4016
4017 git checkout A^0 &&
4018
4019 - test_must_fail git merge -s recursive B^0 &&
4019 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 &&
4020
4021 git ls-files -u >out &&
4022 test_line_count = 12 out &&
@@ -4051,4 +4051,356 @@ test_expect_success '12c-check: Moving one directory hierarchy into another w/ c
4051 )
4052 '
4053
4054 +###########################################################################
4055 +# SECTION 13: Checking informational and conflict messages
4056 +#
4057 +# A year after directory rename detection became the default, it was
4058 +# instead decided to report conflicts on the pathname on the basis that
4059 +# some users may expect the new files added or moved into a directory to
4060 +# be unrelated to all the other files in that directory, and thus that
4061 +# directory rename detection is unexpected. Test that the messages printed
4062 +# match our expectation.
4063 +###########################################################################
4064 +
4065 +# Testcase 13a, Basic directory rename with newly added files
4066 +# Commit O: z/{b,c}
4067 +# Commit A: y/{b,c}
4068 +# Commit B: z/{b,c,d,e/f}
4069 +# Expected: y/{b,c,d,e/f}, with notices/conflicts for both y/d and y/e/f
4070 +
4071 +test_expect_success '13a-setup: messages for newly added files' '
4072 + test_create_repo 13a &&
4073 + (
4074 + cd 13a &&
4075 +
4076 + mkdir z &&
4077 + echo b >z/b &&
4078 + echo c >z/c &&
4079 + git add z &&
4080 + test_tick &&
4081 + git commit -m "O" &&
4082 +
4083 + git branch O &&
4084 + git branch A &&
4085 + git branch B &&
4086 +
4087 + git checkout A &&
4088 + git mv z y &&
4089 + test_tick &&
4090 + git commit -m "A" &&
4091 +
4092 + git checkout B &&
4093 + echo d >z/d &&
4094 + mkdir z/e &&
4095 + echo f >z/e/f &&
4096 + git add z/d z/e/f &&
4097 + test_tick &&
4098 + git commit -m "B"
4099 + )
4100 +'
4101 +
4102 +test_expect_success '13a-check(conflict): messages for newly added files' '
4103 + (
4104 + cd 13a &&
4105 +
4106 + git checkout A^0 &&
4107 +
4108 + test_must_fail git merge -s recursive B^0 >out 2>err &&
4109 +
4110 + test_i18ngrep CONFLICT..file.location.*z/e/f.added.in.B^0.*y/e/f out &&
4111 + test_i18ngrep CONFLICT..file.location.*z/d.added.in.B^0.*y/d out &&
4112 +
4113 + git ls-files >paths &&
4114 + ! grep z/ paths &&
4115 + grep "y/[de]" paths &&
4116 +
4117 + test_path_is_missing z/d &&
4118 + test_path_is_file y/d &&
4119 + test_path_is_missing z/e/f &&
4120 + test_path_is_file y/e/f
4121 + )
4122 +'
4123 +
4124 +test_expect_success '13a-check(info): messages for newly added files' '
4125 + (
4126 + cd 13a &&
4127 +
4128 + git reset --hard &&
4129 + git checkout A^0 &&
4130 +
4131 + git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4132 +
4133 + test_i18ngrep Path.updated:.*z/e/f.added.in.B^0.*y/e/f out &&
4134 + test_i18ngrep Path.updated:.*z/d.added.in.B^0.*y/d out &&
4135 +
4136 + git ls-files >paths &&
4137 + ! grep z/ paths &&
4138 + grep "y/[de]" paths &&
4139 +
4140 + test_path_is_missing z/d &&
4141 + test_path_is_file y/d &&
4142 + test_path_is_missing z/e/f &&
4143 + test_path_is_file y/e/f
4144 + )
4145 +'
4146 +
4147 +# Testcase 13b, Transitive rename with conflicted content merge and default
4148 +# "conflict" setting
4149 +# (Related to testcase 1c, 9b)
4150 +# Commit O: z/{b,c}, x/d_1
4151 +# Commit A: y/{b,c}, x/d_2
4152 +# Commit B: z/{b,c,d_3}
4153 +# Expected: y/{b,c,d_merged}, with two conflict messages for y/d,
4154 +# one about content, and one about file location
4155 +
4156 +test_expect_success '13b-setup: messages for transitive rename with conflicted content' '
4157 + test_create_repo 13b &&
4158 + (
4159 + cd 13b &&
4160 +
4161 + mkdir x &&
4162 + mkdir z &&
4163 + test_seq 1 10 >x/d &&
4164 + echo b >z/b &&
4165 + echo c >z/c &&
4166 + git add x z &&
4167 + test_tick &&
4168 + git commit -m "O" &&
4169 +
4170 + git branch O &&
4171 + git branch A &&
4172 + git branch B &&
4173 +
4174 + git checkout A &&
4175 + git mv z y &&
4176 + echo 11 >>x/d &&
4177 + git add x/d &&
4178 + test_tick &&
4179 + git commit -m "A" &&
4180 +
4181 + git checkout B &&
4182 + echo eleven >>x/d &&
4183 + git mv x/d z/d &&
4184 + git add z/d &&
4185 + test_tick &&
4186 + git commit -m "B"
4187 + )
4188 +'
4189 +
4190 +test_expect_success '13b-check(conflict): messages for transitive rename with conflicted content' '
4191 + (
4192 + cd 13b &&
4193 +
4194 + git checkout A^0 &&
4195 +
4196 + test_must_fail git merge -s recursive B^0 >out 2>err &&
4197 +
4198 + test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
4199 + test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
4200 +
4201 + git ls-files >paths &&
4202 + ! grep z/ paths &&
4203 + grep "y/d" paths &&
4204 +
4205 + test_path_is_missing z/d &&
4206 + test_path_is_file y/d
4207 + )
4208 +'
4209 +
4210 +test_expect_success '13b-check(info): messages for transitive rename with conflicted content' '
4211 + (
4212 + cd 13b &&
4213 +
4214 + git reset --hard &&
4215 + git checkout A^0 &&
4216 +
4217 + test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4218 +
4219 + test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
4220 + test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
4221 +
4222 + git ls-files >paths &&
4223 + ! grep z/ paths &&
4224 + grep "y/d" paths &&
4225 +
4226 + test_path_is_missing z/d &&
4227 + test_path_is_file y/d
4228 + )
4229 +'
4230 +
4231 +# Testcase 13c, Rename/rename(1to1) due to directory rename
4232 +# Commit O: z/{b,c}, x/{d,e}
4233 +# Commit A: y/{b,c,d}, x/e
4234 +# Commit B: z/{b,c,d}, x/e
4235 +# Expected: y/{b,c,d}, with info or conflict messages for d (
4236 +# A: renamed x/d -> z/d; B: renamed z/ -> y/ AND renamed x/d to y/d
4237 +# One could argue A had partial knowledge of what was done with
4238 +# d and B had full knowledge, but that's a slippery slope as
4239 +# shown in testcase 13d.
4240 +
4241 +test_expect_success '13c-setup: messages for rename/rename(1to1) via transitive rename' '
4242 + test_create_repo 13c &&
4243 + (
4244 + cd 13c &&
4245 +
4246 + mkdir x &&
4247 + mkdir z &&
4248 + test_seq 1 10 >x/d &&
4249 + echo e >x/e &&
4250 + echo b >z/b &&
4251 + echo c >z/c &&
4252 + git add x z &&
4253 + test_tick &&
4254 + git commit -m "O" &&
4255 +
4256 + git branch O &&
4257 + git branch A &&
4258 + git branch B &&
4259 +
4260 + git checkout A &&
4261 + git mv z y &&
4262 + git mv x/d y/ &&
4263 + test_tick &&
4264 + git commit -m "A" &&
4265 +
4266 + git checkout B &&
4267 + git mv x/d z/d &&
4268 + git add z/d &&
4269 + test_tick &&
4270 + git commit -m "B"
4271 + )
4272 +'
4273 +
4274 +test_expect_success '13c-check(conflict): messages for rename/rename(1to1) via transitive rename' '
4275 + (
4276 + cd 13c &&
4277 +
4278 + git checkout A^0 &&
4279 +
4280 + test_must_fail git merge -s recursive B^0 >out 2>err &&
4281 +
4282 + test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
4283 +
4284 + git ls-files >paths &&
4285 + ! grep z/ paths &&
4286 + grep "y/d" paths &&
4287 +
4288 + test_path_is_missing z/d &&
4289 + test_path_is_file y/d
4290 + )
4291 +'
4292 +
4293 +test_expect_success '13c-check(info): messages for rename/rename(1to1) via transitive rename' '
4294 + (
4295 + cd 13c &&
4296 +
4297 + git reset --hard &&
4298 + git checkout A^0 &&
4299 +
4300 + git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4301 +
4302 + test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
4303 +
4304 + git ls-files >paths &&
4305 + ! grep z/ paths &&
4306 + grep "y/d" paths &&
4307 +
4308 + test_path_is_missing z/d &&
4309 + test_path_is_file y/d
4310 + )
4311 +'
4312 +
4313 +# Testcase 13d, Rename/rename(1to1) due to directory rename on both sides
4314 +# Commit O: a/{z,y}, b/x, c/w
4315 +# Commit A: a/z, b/{y,x}, d/w
4316 +# Commit B: a/z, d/x, c/{y,w}
4317 +# Expected: a/z, d/{y,x,w} with no file location conflict for x
4318 +# Easy cases:
4319 +# * z is always in a; so it stays in a.
4320 +# * x starts in b, only modified on one side to move into d/
4321 +# * w starts in c, only modified on one side to move into d/
4322 +# Hard case:
4323 +# * A renames a/y to b/y, and B renames b/->d/ => a/y -> d/y
4324 +# * B renames a/y to c/y, and A renames c/->d/ => a/y -> d/y
4325 +# No conflict in where a/y ends up, so put it in d/y.
4326 +
4327 +test_expect_success '13d-setup: messages for rename/rename(1to1) via dual transitive rename' '
4328 + test_create_repo 13d &&
4329 + (
4330 + cd 13d &&
4331 +
4332 + mkdir a &&
4333 + mkdir b &&
4334 + mkdir c &&
4335 + echo z >a/z &&
4336 + echo y >a/y &&
4337 + echo x >b/x &&
4338 + echo w >c/w &&
4339 + git add a b c &&
4340 + test_tick &&
4341 + git commit -m "O" &&
4342 +
4343 + git branch O &&
4344 + git branch A &&
4345 + git branch B &&
4346 +
4347 + git checkout A &&
4348 + git mv a/y b/ &&
4349 + git mv c/ d/ &&
4350 + test_tick &&
4351 + git commit -m "A" &&
4352 +
4353 + git checkout B &&
4354 + git mv a/y c/ &&
4355 + git mv b/ d/ &&
4356 + test_tick &&
4357 + git commit -m "B"
4358 + )
4359 +'
4360 +
4361 +test_expect_success '13d-check(conflict): messages for rename/rename(1to1) via dual transitive rename' '
4362 + (
4363 + cd 13d &&
4364 +
4365 + git checkout A^0 &&
4366 +
4367 + test_must_fail git merge -s recursive B^0 >out 2>err &&
4368 +
4369 + test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.b/y.*moved.to.d/y out &&
4370 + test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.c/y.*moved.to.d/y out &&
4371 +
4372 + git ls-files >paths &&
4373 + ! grep b/ paths &&
4374 + ! grep c/ paths &&
4375 + grep "d/y" paths &&
4376 +
4377 + test_path_is_missing b/y &&
4378 + test_path_is_missing c/y &&
4379 + test_path_is_file d/y
4380 + )
4381 +'
4382 +
4383 +test_expect_success '13d-check(info): messages for rename/rename(1to1) via dual transitive rename' '
4384 + (
4385 + cd 13d &&
4386 +
4387 + git reset --hard &&
4388 + git checkout A^0 &&
4389 +
4390 + git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4391 +
4392 + test_i18ngrep Path.updated.*a/y.renamed.to.b/y.*moving.it.to.d/y out &&
4393 + test_i18ngrep Path.updated.*a/y.renamed.to.c/y.*moving.it.to.d/y out &&
4394 +
4395 + git ls-files >paths &&
4396 + ! grep b/ paths &&
4397 + ! grep c/ paths &&
4398 + grep "d/y" paths &&
4399 +
4400 + test_path_is_missing b/y &&
4401 + test_path_is_missing c/y &&
4402 + test_path_is_file d/y
4403 + )
4404 +'
4405 +
4406 test_done
t/t6046-merge-skip-unneeded-updates.sh
+4 -4
@@ -466,7 +466,7 @@ test_expect_success '3a-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
466
467 git checkout A^0 &&
468
469 - GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
469 + GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
470
471 test_i18ngrep ! "Skipped bar/bq" out &&
472 test_must_be_empty err &&
@@ -495,7 +495,7 @@ test_expect_success '3a-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
495
496 git checkout B^0 &&
497
498 - GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
498 + GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
499
500 test_i18ngrep ! "Skipped bar/bq" out &&
501 test_must_be_empty err &&
@@ -560,7 +560,7 @@ test_expect_success '3b-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
560
561 git checkout A^0 &&
562
563 - GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
563 + GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
564
565 test_i18ngrep ! "Skipped bar/bq" out &&
566 test_must_be_empty err &&
@@ -589,7 +589,7 @@ test_expect_success '3b-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
589
590 git checkout B^0 &&
591
592 - GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
592 + GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
593
594 test_i18ngrep ! "Skipped bar/bq" out &&
595 test_must_be_empty err &&