Revert "Merge branch 'en/rename-directory-detection'"

This reverts commit e4bb62fa1eeee689744b413e29a50b4d1dae6886, reversing changes made to 468165c1d8a442994a825f3684528361727cd8c0. The topic appears to inflict severe regression in renaming merges, even though the promise of it was that it would improve them. We do not yet know which exact change in the topic was wrong, but in the meantime, let's play it safe and revert it out of 'master' before real Git-using projects are harmed. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Apr 11, 2018 at 18:07 UTC 8b026edac3104ecc40a68fd58b764fb3c717babb
9 files changed +115 -5197
merge-recursive.c
+111 -1132
@@ -49,67 +49,6 @@ static unsigned int path_hash(const char *path)
49 return ignore_case ? strihash(path) : strhash(path);
50 }
51
52 -static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,
53 - char *dir)
54 -{
55 - struct dir_rename_entry key;
56 -
57 - if (dir == NULL)
58 - return NULL;
59 - hashmap_entry_init(&key, strhash(dir));
60 - key.dir = dir;
61 - return hashmap_get(hashmap, &key, NULL);
62 -}
63 -
64 -static int dir_rename_cmp(const void *unused_cmp_data,
65 - const void *entry,
66 - const void *entry_or_key,
67 - const void *unused_keydata)
68 -{
69 - const struct dir_rename_entry *e1 = entry;
70 - const struct dir_rename_entry *e2 = entry_or_key;
71 -
72 - return strcmp(e1->dir, e2->dir);
73 -}
74 -
75 -static void dir_rename_init(struct hashmap *map)
76 -{
77 - hashmap_init(map, dir_rename_cmp, NULL, 0);
78 -}
79 -
80 -static void dir_rename_entry_init(struct dir_rename_entry *entry,
81 - char *directory)
82 -{
83 - hashmap_entry_init(entry, strhash(directory));
84 - entry->dir = directory;
85 - entry->non_unique_new_dir = 0;
86 - strbuf_init(&entry->new_dir, 0);
87 - string_list_init(&entry->possible_new_dirs, 0);
88 -}
89 -
90 -static struct collision_entry *collision_find_entry(struct hashmap *hashmap,
91 - char *target_file)
92 -{
93 - struct collision_entry key;
94 -
95 - hashmap_entry_init(&key, strhash(target_file));
96 - key.target_file = target_file;
97 - return hashmap_get(hashmap, &key, NULL);
98 -}
99 -
100 -static int collision_cmp(void *unused_cmp_data,
101 - const struct collision_entry *e1,
102 - const struct collision_entry *e2,
103 - const void *unused_keydata)
104 -{
105 - return strcmp(e1->target_file, e2->target_file);
106 -}
107 -
108 -static void collision_init(struct hashmap *map)
109 -{
110 - hashmap_init(map, (hashmap_cmp_fn) collision_cmp, NULL, 0);
111 -}
112 -
52 static void flush_output(struct merge_options *o)
53 {
54 if (o->buffer_output < 2 && o->obuf.len) {
@@ -180,7 +119,6 @@ static int oid_eq(const struct object_id *a, const struct object_id *b)
119
120 enum rename_type {
121 RENAME_NORMAL = 0,
183 - RENAME_DIR,
122 RENAME_DELETE,
123 RENAME_ONE_FILE_TO_ONE,
124 RENAME_ONE_FILE_TO_TWO,
@@ -337,37 +275,32 @@ static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
275 init_tree_desc(desc, tree->buffer, tree->size);
276 }
277
340 -static int git_merge_trees(struct merge_options *o,
278 +static int git_merge_trees(int index_only,
279 struct tree *common,
280 struct tree *head,
281 struct tree *merge)
282 {
283 int rc;
284 struct tree_desc t[3];
285 + struct unpack_trees_options opts;
286
348 - memset(&o->unpack_opts, 0, sizeof(o->unpack_opts));
349 - if (o->call_depth)
350 - o->unpack_opts.index_only = 1;
287 + memset(&opts, 0, sizeof(opts));
288 + if (index_only)
289 + opts.index_only = 1;
290 else
352 - o->unpack_opts.update = 1;
353 - o->unpack_opts.merge = 1;
354 - o->unpack_opts.head_idx = 2;
355 - o->unpack_opts.fn = threeway_merge;
356 - o->unpack_opts.src_index = &the_index;
357 - o->unpack_opts.dst_index = &the_index;
358 - setup_unpack_trees_porcelain(&o->unpack_opts, "merge");
291 + opts.update = 1;
292 + opts.merge = 1;
293 + opts.head_idx = 2;
294 + opts.fn = threeway_merge;
295 + opts.src_index = &the_index;
296 + opts.dst_index = &the_index;
297 + setup_unpack_trees_porcelain(&opts, "merge");
298
299 init_tree_desc_from_tree(t+0, common);
300 init_tree_desc_from_tree(t+1, head);
301 init_tree_desc_from_tree(t+2, merge);
302
364 - rc = unpack_trees(3, t, &o->unpack_opts);
365 - /*
366 - * unpack_trees NULLifies src_index, but it's used in verify_uptodate,
367 - * so set to the new index which will usually have modification
368 - * timestamp info copied over.
369 - */
370 - o->unpack_opts.src_index = &the_index;
303 + rc = unpack_trees(3, t, &opts);
304 cache_tree_free(&active_cache_tree);
305 return rc;
306 }
@@ -427,21 +360,6 @@ static void get_files_dirs(struct merge_options *o, struct tree *tree)
360 read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o);
361 }
362
430 -static int get_tree_entry_if_blob(struct tree *tree,
431 - const char *path,
432 - struct object_id *hashy,
433 - unsigned int *mode_o)
434 -{
435 - int ret;
436 -
437 - ret = get_tree_entry(&tree->object.oid, path, hashy, mode_o);
438 - if (S_ISDIR(*mode_o)) {
439 - oidcpy(hashy, &null_oid);
440 - *mode_o = 0;
441 - }
442 - return ret;
443 -}
444 -
363 /*
364 * Returns an index_entry instance which doesn't have to correspond to
365 * a real cache entry in Git's index.
@@ -452,12 +370,12 @@ static struct stage_data *insert_stage_data(const char *path,
370 {
371 struct string_list_item *item;
372 struct stage_data *e = xcalloc(1, sizeof(struct stage_data));
455 - get_tree_entry_if_blob(o, path,
456 - &e->stages[1].oid, &e->stages[1].mode);
457 - get_tree_entry_if_blob(a, path,
458 - &e->stages[2].oid, &e->stages[2].mode);
459 - get_tree_entry_if_blob(b, path,
460 - &e->stages[3].oid, &e->stages[3].mode);
373 + get_tree_entry(&o->object.oid, path,
374 + &e->stages[1].oid, &e->stages[1].mode);
375 + get_tree_entry(&a->object.oid, path,
376 + &e->stages[2].oid, &e->stages[2].mode);
377 + get_tree_entry(&b->object.oid, path,
378 + &e->stages[3].oid, &e->stages[3].mode);
379 item = string_list_insert(entries, path);
380 item->util = e;
381 return e;
@@ -616,10 +534,78 @@ struct rename {
534 */
535 struct stage_data *src_entry;
536 struct stage_data *dst_entry;
619 - unsigned add_turned_into_rename:1;
537 unsigned processed:1;
538 };
539
540 +/*
541 + * Get information of all renames which occurred between 'o_tree' and
542 + * 'tree'. We need the three trees in the merge ('o_tree', 'a_tree' and
543 + * 'b_tree') to be able to associate the correct cache entries with
544 + * the rename information. 'tree' is always equal to either a_tree or b_tree.
545 + */
546 +static struct string_list *get_renames(struct merge_options *o,
547 + struct tree *tree,
548 + struct tree *o_tree,
549 + struct tree *a_tree,
550 + struct tree *b_tree,
551 + struct string_list *entries)
552 +{
553 + int i;
554 + struct string_list *renames;
555 + struct diff_options opts;
556 +
557 + renames = xcalloc(1, sizeof(struct string_list));
558 + if (!o->detect_rename)
559 + return renames;
560 +
561 + diff_setup(&opts);
562 + opts.flags.recursive = 1;
563 + opts.flags.rename_empty = 0;
564 + opts.detect_rename = DIFF_DETECT_RENAME;
565 + opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
566 + o->diff_rename_limit >= 0 ? o->diff_rename_limit :
567 + 1000;
568 + opts.rename_score = o->rename_score;
569 + opts.show_rename_progress = o->show_rename_progress;
570 + opts.output_format = DIFF_FORMAT_NO_OUTPUT;
571 + diff_setup_done(&opts);
572 + diff_tree_oid(&o_tree->object.oid, &tree->object.oid, "", &opts);
573 + diffcore_std(&opts);
574 + if (opts.needed_rename_limit > o->needed_rename_limit)
575 + o->needed_rename_limit = opts.needed_rename_limit;
576 + for (i = 0; i < diff_queued_diff.nr; ++i) {
577 + struct string_list_item *item;
578 + struct rename *re;
579 + struct diff_filepair *pair = diff_queued_diff.queue[i];
580 + if (pair->status != 'R') {
581 + diff_free_filepair(pair);
582 + continue;
583 + }
584 + re = xmalloc(sizeof(*re));
585 + re->processed = 0;
586 + re->pair = pair;
587 + item = string_list_lookup(entries, re->pair->one->path);
588 + if (!item)
589 + re->src_entry = insert_stage_data(re->pair->one->path,
590 + o_tree, a_tree, b_tree, entries);
591 + else
592 + re->src_entry = item->util;
593 +
594 + item = string_list_lookup(entries, re->pair->two->path);
595 + if (!item)
596 + re->dst_entry = insert_stage_data(re->pair->two->path,
597 + o_tree, a_tree, b_tree, entries);
598 + else
599 + re->dst_entry = item->util;
600 + item = string_list_insert(renames, pair->one->path);
601 + item->util = re;
602 + }
603 + opts.output_format = DIFF_FORMAT_NO_OUTPUT;
604 + diff_queued_diff.nr = 0;
605 + diff_flush(&opts);
606 + return renames;
607 +}
608 +
609 static int update_stages(struct merge_options *opt, const char *path,
610 const struct diff_filespec *o,
611 const struct diff_filespec *a,
@@ -651,27 +637,6 @@ static int update_stages(struct merge_options *opt, const char *path,
637 return 0;
638 }
639
654 -static int update_stages_for_stage_data(struct merge_options *opt,
655 - const char *path,
656 - const struct stage_data *stage_data)
657 -{
658 - struct diff_filespec o, a, b;
659 -
660 - o.mode = stage_data->stages[1].mode;
661 - oidcpy(&o.oid, &stage_data->stages[1].oid);
662 -
663 - a.mode = stage_data->stages[2].mode;
664 - oidcpy(&a.oid, &stage_data->stages[2].oid);
665 -
666 - b.mode = stage_data->stages[3].mode;
667 - oidcpy(&b.oid, &stage_data->stages[3].oid);
668 -
669 - return update_stages(opt, path,
670 - is_null_oid(&o.oid) ? NULL : &o,
671 - is_null_oid(&a.oid) ? NULL : &a,
672 - is_null_oid(&b.oid) ? NULL : &b);
673 -}
674 -
640 static void update_entry(struct stage_data *entry,
641 struct diff_filespec *o,
642 struct diff_filespec *a,
@@ -800,20 +765,6 @@ static int would_lose_untracked(const char *path)
765 return !was_tracked(path) && file_exists(path);
766 }
767
803 -static int was_dirty(struct merge_options *o, const char *path)
804 -{
805 - struct cache_entry *ce;
806 - int dirty = 1;
807 -
808 - if (o->call_depth || !was_tracked(path))
809 - return !dirty;
810 -
811 - ce = cache_file_exists(path, strlen(path), ignore_case);
812 - dirty = (ce->ce_stat_data.sd_mtime.sec > 0 &&
813 - verify_uptodate(ce, &o->unpack_opts) != 0);
814 - return dirty;
815 -}
816 -
768 static int make_room_for_path(struct merge_options *o, const char *path)
769 {
770 int status, i;
@@ -1163,38 +1114,6 @@ static int merge_file_one(struct merge_options *o,
1114 return merge_file_1(o, &one, &a, &b, branch1, branch2, mfi);
1115 }
1116
1166 -static int conflict_rename_dir(struct merge_options *o,
1167 - struct diff_filepair *pair,
1168 - const char *rename_branch,
1169 - const char *other_branch)
1170 -{
1171 - const struct diff_filespec *dest = pair->two;
1172 -
1173 - if (!o->call_depth && would_lose_untracked(dest->path)) {
1174 - char *alt_path = unique_path(o, dest->path, rename_branch);
1175 -
1176 - output(o, 1, _("Error: Refusing to lose untracked file at %s; "
1177 - "writing to %s instead."),
1178 - dest->path, alt_path);
1179 - /*
1180 - * Write the file in worktree at alt_path, but not in the
1181 - * index. Instead, write to dest->path for the index but
1182 - * only at the higher appropriate stage.
1183 - */
1184 - if (update_file(o, 0, &dest->oid, dest->mode, alt_path))
1185 - return -1;
1186 - free(alt_path);
1187 - return update_stages(o, dest->path, NULL,
1188 - rename_branch == o->branch1 ? dest : NULL,
1189 - rename_branch == o->branch1 ? NULL : dest);
1190 - }
1191 -
1192 - /* Update dest->path both in index and in worktree */
1193 - if (update_file(o, 1, &dest->oid, dest->mode, dest->path))
1194 - return -1;
1195 - return 0;
1196 -}
1197 -
1117 static int handle_change_delete(struct merge_options *o,
1118 const char *path, const char *old_path,
1119 const struct object_id *o_oid, int o_mode,
@@ -1208,8 +1127,7 @@ static int handle_change_delete(struct merge_options *o,
1127 const char *update_path = path;
1128 int ret = 0;
1129
1211 - if (dir_in_way(path, !o->call_depth, 0) ||
1212 - (!o->call_depth && would_lose_untracked(path))) {
1130 + if (dir_in_way(path, !o->call_depth, 0)) {
1131 update_path = alt_path = unique_path(o, path, change_branch);
1132 }
1133
@@ -1324,34 +1242,17 @@ static int handle_file(struct merge_options *o,
1242
1243 add = filespec_from_entry(&other, dst_entry, stage ^ 1);
1244 if (add) {
1327 - int ren_src_was_dirty = was_dirty(o, rename->path);
1245 char *add_name = unique_path(o, rename->path, other_branch);
1246 if (update_file(o, 0, &add->oid, add->mode, add_name))
1247 return -1;
1248
1332 - if (ren_src_was_dirty) {
1333 - output(o, 1, _("Refusing to lose dirty file at %s"),
1334 - rename->path);
1335 - }
1336 - /*
1337 - * Because the double negatives somehow keep confusing me...
1338 - * 1) update_wd iff !ren_src_was_dirty.
1339 - * 2) no_wd iff !update_wd
1340 - * 3) so, no_wd == !!ren_src_was_dirty == ren_src_was_dirty
1341 - */
1342 - remove_file(o, 0, rename->path, ren_src_was_dirty);
1249 + remove_file(o, 0, rename->path, 0);
1250 dst_name = unique_path(o, rename->path, cur_branch);
1251 } else {
1252 if (dir_in_way(rename->path, !o->call_depth, 0)) {
1253 dst_name = unique_path(o, rename->path, cur_branch);
1254 output(o, 1, _("%s is a directory in %s adding as %s instead"),
1255 rename->path, other_branch, dst_name);
1349 - } else if (!o->call_depth &&
1350 - would_lose_untracked(rename->path)) {
1351 - dst_name = unique_path(o, rename->path, cur_branch);
1352 - output(o, 1, _("Refusing to lose untracked file at %s; "
1353 - "adding as %s instead"),
1354 - rename->path, dst_name);
1256 }
1257 }
1258 if ((ret = update_file(o, 0, &rename->oid, rename->mode, dst_name)))
@@ -1477,43 +1378,11 @@ static int conflict_rename_rename_2to1(struct merge_options *o,
1378 char *new_path2 = unique_path(o, path, ci->branch2);
1379 output(o, 1, _("Renaming %s to %s and %s to %s instead"),
1380 a->path, new_path1, b->path, new_path2);
1480 - if (was_dirty(o, path))
1481 - output(o, 1, _("Refusing to lose dirty file at %s"),
1482 - path);
1483 - else if (would_lose_untracked(path))
1484 - /*
1485 - * Only way we get here is if both renames were from
1486 - * a directory rename AND user had an untracked file
1487 - * at the location where both files end up after the
1488 - * two directory renames. See testcase 10d of t6043.
1489 - */
1490 - output(o, 1, _("Refusing to lose untracked file at "
1491 - "%s, even though it's in the way."),
1492 - path);
1493 - else
1494 - remove_file(o, 0, path, 0);
1381 + remove_file(o, 0, path, 0);
1382 ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, new_path1);
1383 if (!ret)
1384 ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
1385 new_path2);
1499 - /*
1500 - * unpack_trees() actually populates the index for us for
1501 - * "normal" rename/rename(2to1) situtations so that the
1502 - * correct entries are at the higher stages, which would
1503 - * make the call below to update_stages_for_stage_data
1504 - * unnecessary. However, if either of the renames came
1505 - * from a directory rename, then unpack_trees() will not
1506 - * have gotten the right data loaded into the index, so we
1507 - * need to do so now. (While it'd be tempting to move this
1508 - * call to update_stages_for_stage_data() to
1509 - * apply_directory_rename_modifications(), that would break
1510 - * our intermediate calls to would_lose_untracked() since
1511 - * those rely on the current in-memory index. See also the
1512 - * big "NOTE" in update_stages()).
1513 - */
1514 - if (update_stages_for_stage_data(o, path, ci->dst_entry1))
1515 - ret = -1;
1516 -
1386 free(new_path2);
1387 free(new_path1);
1388 }
@@ -1521,754 +1390,6 @@ static int conflict_rename_rename_2to1(struct merge_options *o,
1390 return ret;
1391 }
1392
1524 -/*
1525 - * Get the diff_filepairs changed between o_tree and tree.
1526 - */
1527 -static struct diff_queue_struct *get_diffpairs(struct merge_options *o,
1528 - struct tree *o_tree,
1529 - struct tree *tree)
1530 -{
1531 - struct diff_queue_struct *ret;
1532 - struct diff_options opts;
1533 -
1534 - diff_setup(&opts);
1535 - opts.flags.recursive = 1;
1536 - opts.flags.rename_empty = 0;
1537 - opts.detect_rename = DIFF_DETECT_RENAME;
1538 - opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
1539 - o->diff_rename_limit >= 0 ? o->diff_rename_limit :
1540 - 1000;
1541 - opts.rename_score = o->rename_score;
1542 - opts.show_rename_progress = o->show_rename_progress;
1543 - opts.output_format = DIFF_FORMAT_NO_OUTPUT;
1544 - diff_setup_done(&opts);
1545 - diff_tree_oid(&o_tree->object.oid, &tree->object.oid, "", &opts);
1546 - diffcore_std(&opts);
1547 - if (opts.needed_rename_limit > o->needed_rename_limit)
1548 - o->needed_rename_limit = opts.needed_rename_limit;
1549 -
1550 - ret = xmalloc(sizeof(*ret));
1551 - *ret = diff_queued_diff;
1552 -
1553 - opts.output_format = DIFF_FORMAT_NO_OUTPUT;
1554 - diff_queued_diff.nr = 0;
1555 - diff_queued_diff.queue = NULL;
1556 - diff_flush(&opts);
1557 - return ret;
1558 -}
1559 -
1560 -static int tree_has_path(struct tree *tree, const char *path)
1561 -{
1562 - struct object_id hashy;
1563 - unsigned int mode_o;
1564 -
1565 - return !get_tree_entry(&tree->object.oid, path,
1566 - &hashy, &mode_o);
1567 -}
1568 -
1569 -/*
1570 - * Return a new string that replaces the beginning portion (which matches
1571 - * entry->dir), with entry->new_dir. In perl-speak:
1572 - * new_path_name = (old_path =~ s/entry->dir/entry->new_dir/);
1573 - * NOTE:
1574 - * Caller must ensure that old_path starts with entry->dir + '/'.
1575 - */
1576 -static char *apply_dir_rename(struct dir_rename_entry *entry,
1577 - const char *old_path)
1578 -{
1579 - struct strbuf new_path = STRBUF_INIT;
1580 - int oldlen, newlen;
1581 -
1582 - if (entry->non_unique_new_dir)
1583 - return NULL;
1584 -
1585 - oldlen = strlen(entry->dir);
1586 - newlen = entry->new_dir.len + (strlen(old_path) - oldlen) + 1;
1587 - strbuf_grow(&new_path, newlen);
1588 - strbuf_addbuf(&new_path, &entry->new_dir);
1589 - strbuf_addstr(&new_path, &old_path[oldlen]);
1590 -
1591 - return strbuf_detach(&new_path, NULL);
1592 -}
1593 -
1594 -static void get_renamed_dir_portion(const char *old_path, const char *new_path,
1595 - char **old_dir, char **new_dir)
1596 -{
1597 - char *end_of_old, *end_of_new;
1598 - int old_len, new_len;
1599 -
1600 - *old_dir = NULL;
1601 - *new_dir = NULL;
1602 -
1603 - /*
1604 - * For
1605 - * "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
1606 - * the "e/foo.c" part is the same, we just want to know that
1607 - * "a/b/c/d" was renamed to "a/b/some/thing/else"
1608 - * so, for this example, this function returns "a/b/c/d" in
1609 - * *old_dir and "a/b/some/thing/else" in *new_dir.
1610 - *
1611 - * Also, if the basename of the file changed, we don't care. We
1612 - * want to know which portion of the directory, if any, changed.
1613 - */
1614 - end_of_old = strrchr(old_path, '/');
1615 - end_of_new = strrchr(new_path, '/');
1616 -
1617 - if (end_of_old == NULL || end_of_new == NULL)
1618 - return;
1619 - while (*--end_of_new == *--end_of_old &&
1620 - end_of_old != old_path &&
1621 - end_of_new != new_path)
1622 - ; /* Do nothing; all in the while loop */
1623 - /*
1624 - * We've found the first non-matching character in the directory
1625 - * paths. That means the current directory we were comparing
1626 - * represents the rename. Move end_of_old and end_of_new back
1627 - * to the full directory name.
1628 - */
1629 - if (*end_of_old == '/')
1630 - end_of_old++;
1631 - if (*end_of_old != '/')
1632 - end_of_new++;
1633 - end_of_old = strchr(end_of_old, '/');
1634 - end_of_new = strchr(end_of_new, '/');
1635 -
1636 - /*
1637 - * It may have been the case that old_path and new_path were the same
1638 - * directory all along. Don't claim a rename if they're the same.
1639 - */
1640 - old_len = end_of_old - old_path;
1641 - new_len = end_of_new - new_path;
1642 -
1643 - if (old_len != new_len || strncmp(old_path, new_path, old_len)) {
1644 - *old_dir = xstrndup(old_path, old_len);
1645 - *new_dir = xstrndup(new_path, new_len);
1646 - }
1647 -}
1648 -
1649 -static void remove_hashmap_entries(struct hashmap *dir_renames,
1650 - struct string_list *items_to_remove)
1651 -{
1652 - int i;
1653 - struct dir_rename_entry *entry;
1654 -
1655 - for (i = 0; i < items_to_remove->nr; i++) {
1656 - entry = items_to_remove->items[i].util;
1657 - hashmap_remove(dir_renames, entry, NULL);
1658 - }
1659 - string_list_clear(items_to_remove, 0);
1660 -}
1661 -
1662 -/*
1663 - * See if there is a directory rename for path, and if there are any file
1664 - * level conflicts for the renamed location. If there is a rename and
1665 - * there are no conflicts, return the new name. Otherwise, return NULL.
1666 - */
1667 -static char *handle_path_level_conflicts(struct merge_options *o,
1668 - const char *path,
1669 - struct dir_rename_entry *entry,
1670 - struct hashmap *collisions,
1671 - struct tree *tree)
1672 -{
1673 - char *new_path = NULL;
1674 - struct collision_entry *collision_ent;
1675 - int clean = 1;
1676 - struct strbuf collision_paths = STRBUF_INIT;
1677 -
1678 - /*
1679 - * entry has the mapping of old directory name to new directory name
1680 - * that we want to apply to path.
1681 - */
1682 - new_path = apply_dir_rename(entry, path);
1683 -
1684 - if (!new_path) {
1685 - /* This should only happen when entry->non_unique_new_dir set */
1686 - if (!entry->non_unique_new_dir)
1687 - BUG("entry->non_unqiue_dir not set and !new_path");
1688 - output(o, 1, _("CONFLICT (directory rename split): "
1689 - "Unclear where to place %s because directory "
1690 - "%s was renamed to multiple other directories, "
1691 - "with no destination getting a majority of the "
1692 - "files."),
1693 - path, entry->dir);
1694 - clean = 0;
1695 - return NULL;
1696 - }
1697 -
1698 - /*
1699 - * The caller needs to have ensured that it has pre-populated
1700 - * collisions with all paths that map to new_path. Do a quick check
1701 - * to ensure that's the case.
1702 - */
1703 - collision_ent = collision_find_entry(collisions, new_path);
1704 - if (collision_ent == NULL)
1705 - BUG("collision_ent is NULL");
1706 -
1707 - /*
1708 - * Check for one-sided add/add/.../add conflicts, i.e.
1709 - * where implicit renames from the other side doing
1710 - * directory rename(s) can affect this side of history
1711 - * to put multiple paths into the same location. Warn
1712 - * and bail on directory renames for such paths.
1713 - */
1714 - if (collision_ent->reported_already) {
1715 - clean = 0;
1716 - } else if (tree_has_path(tree, new_path)) {
1717 - collision_ent->reported_already = 1;
1718 - strbuf_add_separated_string_list(&collision_paths, ", ",
1719 - &collision_ent->source_files);
1720 - output(o, 1, _("CONFLICT (implicit dir rename): Existing "
1721 - "file/dir at %s in the way of implicit "
1722 - "directory rename(s) putting the following "
1723 - "path(s) there: %s."),
1724 - new_path, collision_paths.buf);
1725 - clean = 0;
1726 - } else if (collision_ent->source_files.nr > 1) {
1727 - collision_ent->reported_already = 1;
1728 - strbuf_add_separated_string_list(&collision_paths, ", ",
1729 - &collision_ent->source_files);
1730 - output(o, 1, _("CONFLICT (implicit dir rename): Cannot map "
1731 - "more than one path to %s; implicit directory "
1732 - "renames tried to put these paths there: %s"),
1733 - new_path, collision_paths.buf);
1734 - clean = 0;
1735 - }
1736 -
1737 - /* Free memory we no longer need */
1738 - strbuf_release(&collision_paths);
1739 - if (!clean && new_path) {
1740 - free(new_path);
1741 - return NULL;
1742 - }
1743 -
1744 - return new_path;
1745 -}
1746 -
1747 -/*
1748 - * There are a couple things we want to do at the directory level:
1749 - * 1. Check for both sides renaming to the same thing, in order to avoid
1750 - * implicit renaming of files that should be left in place. (See
1751 - * testcase 6b in t6043 for details.)
1752 - * 2. Prune directory renames if there are still files left in the
1753 - * the original directory. These represent a partial directory rename,
1754 - * i.e. a rename where only some of the files within the directory
1755 - * were renamed elsewhere. (Technically, this could be done earlier
1756 - * in get_directory_renames(), except that would prevent us from
1757 - * doing the previous check and thus failing testcase 6b.)
1758 - * 3. Check for rename/rename(1to2) conflicts (at the directory level).
1759 - * In the future, we could potentially record this info as well and
1760 - * omit reporting rename/rename(1to2) conflicts for each path within
1761 - * the affected directories, thus cleaning up the merge output.
1762 - * NOTE: We do NOT check for rename/rename(2to1) conflicts at the
1763 - * directory level, because merging directories is fine. If it
1764 - * causes conflicts for files within those merged directories, then
1765 - * that should be detected at the individual path level.
1766 - */
1767 -static void handle_directory_level_conflicts(struct merge_options *o,
1768 - struct hashmap *dir_re_head,
1769 - struct tree *head,
1770 - struct hashmap *dir_re_merge,
1771 - struct tree *merge)
1772 -{
1773 - struct hashmap_iter iter;
1774 - struct dir_rename_entry *head_ent;
1775 - struct dir_rename_entry *merge_ent;
1776 -
1777 - struct string_list remove_from_head = STRING_LIST_INIT_NODUP;
1778 - struct string_list remove_from_merge = STRING_LIST_INIT_NODUP;
1779 -
1780 - hashmap_iter_init(dir_re_head, &iter);
1781 - while ((head_ent = hashmap_iter_next(&iter))) {
1782 - merge_ent = dir_rename_find_entry(dir_re_merge, head_ent->dir);
1783 - if (merge_ent &&
1784 - !head_ent->non_unique_new_dir &&
1785 - !merge_ent->non_unique_new_dir &&
1786 - !strbuf_cmp(&head_ent->new_dir, &merge_ent->new_dir)) {
1787 - /* 1. Renamed identically; remove it from both sides */
1788 - string_list_append(&remove_from_head,
1789 - head_ent->dir)->util = head_ent;
1790 - strbuf_release(&head_ent->new_dir);
1791 - string_list_append(&remove_from_merge,
1792 - merge_ent->dir)->util = merge_ent;
1793 - strbuf_release(&merge_ent->new_dir);
1794 - } else if (tree_has_path(head, head_ent->dir)) {
1795 - /* 2. This wasn't a directory rename after all */
1796 - string_list_append(&remove_from_head,
1797 - head_ent->dir)->util = head_ent;
1798 - strbuf_release(&head_ent->new_dir);
1799 - }
1800 - }
1801 -
1802 - remove_hashmap_entries(dir_re_head, &remove_from_head);
1803 - remove_hashmap_entries(dir_re_merge, &remove_from_merge);
1804 -
1805 - hashmap_iter_init(dir_re_merge, &iter);
1806 - while ((merge_ent = hashmap_iter_next(&iter))) {
1807 - head_ent = dir_rename_find_entry(dir_re_head, merge_ent->dir);
1808 - if (tree_has_path(merge, merge_ent->dir)) {
1809 - /* 2. This wasn't a directory rename after all */
1810 - string_list_append(&remove_from_merge,
1811 - merge_ent->dir)->util = merge_ent;
1812 - } else if (head_ent &&
1813 - !head_ent->non_unique_new_dir &&
1814 - !merge_ent->non_unique_new_dir) {
1815 - /* 3. rename/rename(1to2) */
1816 - /*
1817 - * We can assume it's not rename/rename(1to1) because
1818 - * that was case (1), already checked above. So we
1819 - * know that head_ent->new_dir and merge_ent->new_dir
1820 - * are different strings.
1821 - */
1822 - output(o, 1, _("CONFLICT (rename/rename): "
1823 - "Rename directory %s->%s in %s. "
1824 - "Rename directory %s->%s in %s"),
1825 - head_ent->dir, head_ent->new_dir.buf, o->branch1,
1826 - head_ent->dir, merge_ent->new_dir.buf, o->branch2);
1827 - string_list_append(&remove_from_head,
1828 - head_ent->dir)->util = head_ent;
1829 - strbuf_release(&head_ent->new_dir);
1830 - string_list_append(&remove_from_merge,
1831 - merge_ent->dir)->util = merge_ent;
1832 - strbuf_release(&merge_ent->new_dir);
1833 - }
1834 - }
1835 -
1836 - remove_hashmap_entries(dir_re_head, &remove_from_head);
1837 - remove_hashmap_entries(dir_re_merge, &remove_from_merge);
1838 -}
1839 -
1840 -static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs,
1841 - struct tree *tree)
1842 -{
1843 - struct hashmap *dir_renames;
1844 - struct hashmap_iter iter;
1845 - struct dir_rename_entry *entry;
1846 - int i;
1847 -
1848 - /*
1849 - * Typically, we think of a directory rename as all files from a
1850 - * certain directory being moved to a target directory. However,
1851 - * what if someone first moved two files from the original
1852 - * directory in one commit, and then renamed the directory
1853 - * somewhere else in a later commit? At merge time, we just know
1854 - * that files from the original directory went to two different
1855 - * places, and that the bulk of them ended up in the same place.
1856 - * We want each directory rename to represent where the bulk of the
1857 - * files from that directory end up; this function exists to find
1858 - * where the bulk of the files went.
1859 - *
1860 - * The first loop below simply iterates through the list of file
1861 - * renames, finding out how often each directory rename pair
1862 - * possibility occurs.
1863 - */
1864 - dir_renames = xmalloc(sizeof(struct hashmap));
1865 - dir_rename_init(dir_renames);
1866 - for (i = 0; i < pairs->nr; ++i) {
1867 - struct string_list_item *item;
1868 - int *count;
1869 - struct diff_filepair *pair = pairs->queue[i];
1870 - char *old_dir, *new_dir;
1871 -
1872 - /* File not part of directory rename if it wasn't renamed */
1873 - if (pair->status != 'R')
1874 - continue;
1875 -
1876 - get_renamed_dir_portion(pair->one->path, pair->two->path,
1877 - &old_dir, &new_dir);
1878 - if (!old_dir)
1879 - /* Directory didn't change at all; ignore this one. */
1880 - continue;
1881 -
1882 - entry = dir_rename_find_entry(dir_renames, old_dir);
1883 - if (!entry) {
1884 - entry = xmalloc(sizeof(struct dir_rename_entry));
1885 - dir_rename_entry_init(entry, old_dir);
1886 - hashmap_put(dir_renames, entry);
1887 - } else {
1888 - free(old_dir);
1889 - }
1890 - item = string_list_lookup(&entry->possible_new_dirs, new_dir);
1891 - if (!item) {
1892 - item = string_list_insert(&entry->possible_new_dirs,
1893 - new_dir);
1894 - item->util = xcalloc(1, sizeof(int));
1895 - } else {
1896 - free(new_dir);
1897 - }
1898 - count = item->util;
1899 - *count += 1;
1900 - }
1901 -
1902 - /*
1903 - * For each directory with files moved out of it, we find out which
1904 - * target directory received the most files so we can declare it to
1905 - * be the "winning" target location for the directory rename. This
1906 - * winner gets recorded in new_dir. If there is no winner
1907 - * (multiple target directories received the same number of files),
1908 - * we set non_unique_new_dir. Once we've determined the winner (or
1909 - * that there is no winner), we no longer need possible_new_dirs.
1910 - */
1911 - hashmap_iter_init(dir_renames, &iter);
1912 - while ((entry = hashmap_iter_next(&iter))) {
1913 - int max = 0;
1914 - int bad_max = 0;
1915 - char *best = NULL;
1916 -
1917 - for (i = 0; i < entry->possible_new_dirs.nr; i++) {
1918 - int *count = entry->possible_new_dirs.items[i].util;
1919 -
1920 - if (*count == max)
1921 - bad_max = max;
1922 - else if (*count > max) {
1923 - max = *count;
1924 - best = entry->possible_new_dirs.items[i].string;
1925 - }
1926 - }
1927 - if (bad_max == max)
1928 - entry->non_unique_new_dir = 1;
1929 - else {
1930 - assert(entry->new_dir.len == 0);
1931 - strbuf_addstr(&entry->new_dir, best);
1932 - }
1933 - /*
1934 - * The relevant directory sub-portion of the original full
1935 - * filepaths were xstrndup'ed before inserting into
1936 - * possible_new_dirs, and instead of manually iterating the
1937 - * list and free'ing each, just lie and tell
1938 - * possible_new_dirs that it did the strdup'ing so that it
1939 - * will free them for us.
1940 - */
1941 - entry->possible_new_dirs.strdup_strings = 1;
1942 - string_list_clear(&entry->possible_new_dirs, 1);
1943 - }
1944 -
1945 - return dir_renames;
1946 -}
1947 -
1948 -static struct dir_rename_entry *check_dir_renamed(const char *path,
1949 - struct hashmap *dir_renames)
1950 -{
1951 - char temp[PATH_MAX];
1952 - char *end;
1953 - struct dir_rename_entry *entry;
1954 -
1955 - strcpy(temp, path);
1956 - while ((end = strrchr(temp, '/'))) {
1957 - *end = '\0';
1958 - entry = dir_rename_find_entry(dir_renames, temp);
1959 - if (entry)
1960 - return entry;
1961 - }
1962 - return NULL;
1963 -}
1964 -
1965 -static void compute_collisions(struct hashmap *collisions,
1966 - struct hashmap *dir_renames,
1967 - struct diff_queue_struct *pairs)
1968 -{
1969 - int i;
1970 -
1971 - /*
1972 - * Multiple files can be mapped to the same path due to directory
1973 - * renames done by the other side of history. Since that other
1974 - * side of history could have merged multiple directories into one,
1975 - * if our side of history added the same file basename to each of
1976 - * those directories, then all N of them would get implicitly
1977 - * renamed by the directory rename detection into the same path,
1978 - * and we'd get an add/add/.../add conflict, and all those adds
1979 - * from *this* side of history. This is not representable in the
1980 - * index, and users aren't going to easily be able to make sense of
1981 - * it. So we need to provide a good warning about what's
1982 - * happening, and fall back to no-directory-rename detection
1983 - * behavior for those paths.
1984 - *
1985 - * See testcases 9e and all of section 5 from t6043 for examples.
1986 - */
1987 - collision_init(collisions);
1988 -
1989 - for (i = 0; i < pairs->nr; ++i) {
1990 - struct dir_rename_entry *dir_rename_ent;
1991 - struct collision_entry *collision_ent;
1992 - char *new_path;
1993 - struct diff_filepair *pair = pairs->queue[i];
1994 -
1995 - if (pair->status != 'A' && pair->status != 'R')
1996 - continue;
1997 - dir_rename_ent = check_dir_renamed(pair->two->path,
1998 - dir_renames);
1999 - if (!dir_rename_ent)
2000 - continue;
2001 -
2002 - new_path = apply_dir_rename(dir_rename_ent, pair->two->path);
2003 - if (!new_path)
2004 - /*
2005 - * dir_rename_ent->non_unique_new_path is true, which
2006 - * means there is no directory rename for us to use,
2007 - * which means it won't cause us any additional
2008 - * collisions.
2009 - */
2010 - continue;
2011 - collision_ent = collision_find_entry(collisions, new_path);
2012 - if (!collision_ent) {
2013 - collision_ent = xcalloc(1,
2014 - sizeof(struct collision_entry));
2015 - hashmap_entry_init(collision_ent, strhash(new_path));
2016 - hashmap_put(collisions, collision_ent);
2017 - collision_ent->target_file = new_path;
2018 - } else {
2019 - free(new_path);
2020 - }
2021 - string_list_insert(&collision_ent->source_files,
2022 - pair->two->path);
2023 - }
2024 -}
2025 -
2026 -static char *check_for_directory_rename(struct merge_options *o,
2027 - const char *path,
2028 - struct tree *tree,
2029 - struct hashmap *dir_renames,
2030 - struct hashmap *dir_rename_exclusions,
2031 - struct hashmap *collisions,
2032 - int *clean_merge)
2033 -{
2034 - char *new_path = NULL;
2035 - struct dir_rename_entry *entry = check_dir_renamed(path, dir_renames);
2036 - struct dir_rename_entry *oentry = NULL;
2037 -
2038 - if (!entry)
2039 - return new_path;
2040 -
2041 - /*
2042 - * This next part is a little weird. We do not want to do an
2043 - * implicit rename into a directory we renamed on our side, because
2044 - * that will result in a spurious rename/rename(1to2) conflict. An
2045 - * example:
2046 - * Base commit: dumbdir/afile, otherdir/bfile
2047 - * Side 1: smrtdir/afile, otherdir/bfile
2048 - * Side 2: dumbdir/afile, dumbdir/bfile
2049 - * Here, while working on Side 1, we could notice that otherdir was
2050 - * renamed/merged to dumbdir, and change the diff_filepair for
2051 - * otherdir/bfile into a rename into dumbdir/bfile. However, Side
2052 - * 2 will notice the rename from dumbdir to smrtdir, and do the
2053 - * transitive rename to move it from dumbdir/bfile to
2054 - * smrtdir/bfile. That gives us bfile in dumbdir vs being in
2055 - * smrtdir, a rename/rename(1to2) conflict. We really just want
2056 - * the file to end up in smrtdir. And the way to achieve that is
2057 - * to not let Side1 do the rename to dumbdir, since we know that is
2058 - * the source of one of our directory renames.
2059 - *
2060 - * That's why oentry and dir_rename_exclusions is here.
2061 - *
2062 - * As it turns out, this also prevents N-way transient rename
2063 - * confusion; See testcases 9c and 9d of t6043.
2064 - */
2065 - oentry = dir_rename_find_entry(dir_rename_exclusions, entry->new_dir.buf);
2066 - if (oentry) {
2067 - output(o, 1, _("WARNING: Avoiding applying %s -> %s rename "
2068 - "to %s, because %s itself was renamed."),
2069 - entry->dir, entry->new_dir.buf, path, entry->new_dir.buf);
2070 - } else {
2071 - new_path = handle_path_level_conflicts(o, path, entry,
2072 - collisions, tree);
2073 - *clean_merge &= (new_path != NULL);
2074 - }
2075 -
2076 - return new_path;
2077 -}
2078 -
2079 -static void apply_directory_rename_modifications(struct merge_options *o,
2080 - struct diff_filepair *pair,
2081 - char *new_path,
2082 - struct rename *re,
2083 - struct tree *tree,
2084 - struct tree *o_tree,
2085 - struct tree *a_tree,
2086 - struct tree *b_tree,
2087 - struct string_list *entries,
2088 - int *clean)
2089 -{
2090 - struct string_list_item *item;
2091 - int stage = (tree == a_tree ? 2 : 3);
2092 - int update_wd;
2093 -
2094 - /*
2095 - * In all cases where we can do directory rename detection,
2096 - * unpack_trees() will have read pair->two->path into the
2097 - * index and the working copy. We need to remove it so that
2098 - * we can instead place it at new_path. It is guaranteed to
2099 - * not be untracked (unpack_trees() would have errored out
2100 - * saying the file would have been overwritten), but it might
2101 - * be dirty, though.
2102 - */
2103 - update_wd = !was_dirty(o, pair->two->path);
2104 - if (!update_wd)
2105 - output(o, 1, _("Refusing to lose dirty file at %s"),
2106 - pair->two->path);
2107 - remove_file(o, 1, pair->two->path, !update_wd);
2108 -
2109 - /* Find or create a new re->dst_entry */
2110 - item = string_list_lookup(entries, new_path);
2111 - if (item) {
2112 - /*
2113 - * Since we're renaming on this side of history, and it's
2114 - * due to a directory rename on the other side of history
2115 - * (which we only allow when the directory in question no
2116 - * longer exists on the other side of history), the
2117 - * original entry for re->dst_entry is no longer
2118 - * necessary...
2119 - */
2120 - re->dst_entry->processed = 1;
2121 -
2122 - /*
2123 - * ...because we'll be using this new one.
2124 - */
2125 - re->dst_entry = item->util;
2126 - } else {
2127 - /*
2128 - * re->dst_entry is for the before-dir-rename path, and we
2129 - * need it to hold information for the after-dir-rename
2130 - * path. Before creating a new entry, we need to mark the
2131 - * old one as unnecessary (...unless it is shared by
2132 - * src_entry, i.e. this didn't use to be a rename, in which
2133 - * case we can just allow the normal processing to happen
2134 - * for it).
2135 - */
2136 - if (pair->status == 'R')
2137 - re->dst_entry->processed = 1;
2138 -
2139 - re->dst_entry = insert_stage_data(new_path,
2140 - o_tree, a_tree, b_tree,
2141 - entries);
2142 - item = string_list_insert(entries, new_path);
2143 - item->util = re->dst_entry;
2144 - }
2145 -
2146 - /*
2147 - * Update the stage_data with the information about the path we are
2148 - * moving into place. That slot will be empty and available for us
2149 - * to write to because of the collision checks in
2150 - * handle_path_level_conflicts(). In other words,
2151 - * re->dst_entry->stages[stage].oid will be the null_oid, so it's
2152 - * open for us to write to.
2153 - *
2154 - * It may be tempting to actually update the index at this point as
2155 - * well, using update_stages_for_stage_data(), but as per the big
2156 - * "NOTE" in update_stages(), doing so will modify the current
2157 - * in-memory index which will break calls to would_lose_untracked()
2158 - * that we need to make. Instead, we need to just make sure that
2159 - * the various conflict_rename_*() functions update the index
2160 - * explicitly rather than relying on unpack_trees() to have done it.
2161 - */
2162 - get_tree_entry(&tree->object.oid,
2163 - pair->two->path,
2164 - &re->dst_entry->stages[stage].oid,
2165 - &re->dst_entry->stages[stage].mode);
2166 -
2167 - /* Update pair status */
2168 - if (pair->status == 'A') {
2169 - /*
2170 - * Recording rename information for this add makes it look
2171 - * like a rename/delete conflict. Make sure we can
2172 - * correctly handle this as an add that was moved to a new
2173 - * directory instead of reporting a rename/delete conflict.
2174 - */
2175 - re->add_turned_into_rename = 1;
2176 - }
2177 - /*
2178 - * We don't actually look at pair->status again, but it seems
2179 - * pedagogically correct to adjust it.
2180 - */
2181 - pair->status = 'R';
2182 -
2183 - /*
2184 - * Finally, record the new location.
2185 - */
2186 - pair->two->path = new_path;
2187 -}
2188 -
2189 -/*
2190 - * Get information of all renames which occurred in 'pairs', making use of
2191 - * any implicit directory renames inferred from the other side of history.
2192 - * We need the three trees in the merge ('o_tree', 'a_tree' and 'b_tree')
2193 - * to be able to associate the correct cache entries with the rename
2194 - * information; tree is always equal to either a_tree or b_tree.
2195 - */
2196 -static struct string_list *get_renames(struct merge_options *o,
2197 - struct diff_queue_struct *pairs,
2198 - struct hashmap *dir_renames,
2199 - struct hashmap *dir_rename_exclusions,
2200 - struct tree *tree,
2201 - struct tree *o_tree,
2202 - struct tree *a_tree,
2203 - struct tree *b_tree,
2204 - struct string_list *entries,
2205 - int *clean_merge)
2206 -{
2207 - int i;
2208 - struct hashmap collisions;
2209 - struct hashmap_iter iter;
2210 - struct collision_entry *e;
2211 - struct string_list *renames;
2212 -
2213 - compute_collisions(&collisions, dir_renames, pairs);
2214 - renames = xcalloc(1, sizeof(struct string_list));
2215 -
2216 - for (i = 0; i < pairs->nr; ++i) {
2217 - struct string_list_item *item;
2218 - struct rename *re;
2219 - struct diff_filepair *pair = pairs->queue[i];
2220 - char *new_path; /* non-NULL only with directory renames */
2221 -
2222 - if (pair->status != 'A' && pair->status != 'R') {
2223 - diff_free_filepair(pair);
2224 - continue;
2225 - }
2226 - new_path = check_for_directory_rename(o, pair->two->path, tree,
2227 - dir_renames,
2228 - dir_rename_exclusions,
2229 - &collisions,
2230 - clean_merge);
2231 - if (pair->status != 'R' && !new_path) {
2232 - diff_free_filepair(pair);
2233 - continue;
2234 - }
2235 -
2236 - re = xmalloc(sizeof(*re));
2237 - re->processed = 0;
2238 - re->add_turned_into_rename = 0;
2239 - re->pair = pair;
2240 - item = string_list_lookup(entries, re->pair->one->path);
2241 - if (!item)
2242 - re->src_entry = insert_stage_data(re->pair->one->path,
2243 - o_tree, a_tree, b_tree, entries);
2244 - else
2245 - re->src_entry = item->util;
2246 -
2247 - item = string_list_lookup(entries, re->pair->two->path);
2248 - if (!item)
2249 - re->dst_entry = insert_stage_data(re->pair->two->path,
2250 - o_tree, a_tree, b_tree, entries);
2251 - else
2252 - re->dst_entry = item->util;
2253 - item = string_list_insert(renames, pair->one->path);
2254 - item->util = re;
2255 - if (new_path)
2256 - apply_directory_rename_modifications(o, pair, new_path,
2257 - re, tree, o_tree,
2258 - a_tree, b_tree,
2259 - entries,
2260 - clean_merge);
2261 - }
2262 -
2263 - hashmap_iter_init(&collisions, &iter);
2264 - while ((e = hashmap_iter_next(&iter))) {
2265 - free(e->target_file);
2266 - string_list_clear(&e->source_files, 0);
2267 - }
2268 - hashmap_free(&collisions, 1);
2269 - return renames;
2270 -}
2271 -
1393 static int process_renames(struct merge_options *o,
1394 struct string_list *a_renames,
1395 struct string_list *b_renames)
@@ -2427,19 +1548,7 @@ static int process_renames(struct merge_options *o,
1548 dst_other.mode = ren1->dst_entry->stages[other_stage].mode;
1549 try_merge = 0;
1550
2430 - if (oid_eq(&src_other.oid, &null_oid) &&
2431 - ren1->add_turned_into_rename) {
2432 - setup_rename_conflict_info(RENAME_DIR,
2433 - ren1->pair,
2434 - NULL,
2435 - branch1,
2436 - branch2,
2437 - ren1->dst_entry,
2438 - NULL,
2439 - o,
2440 - NULL,
2441 - NULL);
2442 - } else if (oid_eq(&src_other.oid, &null_oid)) {
1551 + if (oid_eq(&src_other.oid, &null_oid)) {
1552 setup_rename_conflict_info(RENAME_DELETE,
1553 ren1->pair,
1554 NULL,
@@ -2536,105 +1645,6 @@ cleanup_and_return:
1645 return clean_merge;
1646 }
1647
2539 -struct rename_info {
2540 - struct string_list *head_renames;
2541 - struct string_list *merge_renames;
2542 -};
2543 -
2544 -static void initial_cleanup_rename(struct diff_queue_struct *pairs,
2545 - struct hashmap *dir_renames)
2546 -{
2547 - struct hashmap_iter iter;
2548 - struct dir_rename_entry *e;
2549 -
2550 - hashmap_iter_init(dir_renames, &iter);
2551 - while ((e = hashmap_iter_next(&iter))) {
2552 - free(e->dir);
2553 - strbuf_release(&e->new_dir);
2554 - /* possible_new_dirs already cleared in get_directory_renames */
2555 - }
2556 - hashmap_free(dir_renames, 1);
2557 - free(dir_renames);
2558 -
2559 - free(pairs->queue);
2560 - free(pairs);
2561 -}
2562 -
2563 -static int handle_renames(struct merge_options *o,
2564 - struct tree *common,
2565 - struct tree *head,
2566 - struct tree *merge,
2567 - struct string_list *entries,
2568 - struct rename_info *ri)
2569 -{
2570 - struct diff_queue_struct *head_pairs, *merge_pairs;
2571 - struct hashmap *dir_re_head, *dir_re_merge;
2572 - int clean = 1;
2573 -
2574 - ri->head_renames = NULL;
2575 - ri->merge_renames = NULL;
2576 -
2577 - if (!o->detect_rename)
2578 - return 1;
2579 -
2580 - head_pairs = get_diffpairs(o, common, head);
2581 - merge_pairs = get_diffpairs(o, common, merge);
2582 -
2583 - dir_re_head = get_directory_renames(head_pairs, head);
2584 - dir_re_merge = get_directory_renames(merge_pairs, merge);
2585 -
2586 - handle_directory_level_conflicts(o,
2587 - dir_re_head, head,
2588 - dir_re_merge, merge);
2589 -
2590 - ri->head_renames = get_renames(o, head_pairs,
2591 - dir_re_merge, dir_re_head, head,
2592 - common, head, merge, entries,
2593 - &clean);
2594 - if (clean < 0)
2595 - goto cleanup;
2596 - ri->merge_renames = get_renames(o, merge_pairs,
2597 - dir_re_head, dir_re_merge, merge,
2598 - common, head, merge, entries,
2599 - &clean);
2600 - if (clean < 0)
2601 - goto cleanup;
2602 - clean &= process_renames(o, ri->head_renames, ri->merge_renames);
2603 -
2604 -cleanup:
2605 - /*
2606 - * Some cleanup is deferred until cleanup_renames() because the
2607 - * data structures are still needed and referenced in
2608 - * process_entry(). But there are a few things we can free now.
2609 - */
2610 - initial_cleanup_rename(head_pairs, dir_re_head);
2611 - initial_cleanup_rename(merge_pairs, dir_re_merge);
2612 -
2613 - return clean;
2614 -}
2615 -
2616 -static void final_cleanup_rename(struct string_list *rename)
2617 -{
2618 - const struct rename *re;
2619 - int i;
2620 -
2621 - if (rename == NULL)
2622 - return;
2623 -
2624 - for (i = 0; i < rename->nr; i++) {
2625 - re = rename->items[i].util;
2626 - diff_free_filepair(re->pair);
2627 - }
2628 - string_list_clear(rename, 1);
2629 - free(rename);
2630 -}
2631 -
2632 -static void final_cleanup_renames(struct rename_info *re_info)
2633 -{
2634 - final_cleanup_rename(re_info->head_renames);
2635 - final_cleanup_rename(re_info->merge_renames);
2636 -}
2637 -
1648 static struct object_id *stage_oid(const struct object_id *oid, unsigned mode)
1649 {
1650 return (is_null_oid(oid) || mode == 0) ? NULL: (struct object_id *)oid;
@@ -2725,7 +1735,6 @@ static int handle_modify_delete(struct merge_options *o,
1735
1736 static int merge_content(struct merge_options *o,
1737 const char *path,
2728 - int file_in_way,
1738 struct object_id *o_oid, int o_mode,
1739 struct object_id *a_oid, int a_mode,
1740 struct object_id *b_oid, int b_mode,
@@ -2773,6 +1782,7 @@ static int merge_content(struct merge_options *o,
1782
1783 if (mfi.clean && !df_conflict_remains &&
1784 oid_eq(&mfi.oid, a_oid) && mfi.mode == a_mode) {
1785 + int path_renamed_outside_HEAD;
1786 output(o, 3, _("Skipped %s (merged same as existing)"), path);
1787 /*
1788 * The content merge resulted in the same file contents we
@@ -2780,7 +1790,8 @@ static int merge_content(struct merge_options *o,
1790 * are recorded at the correct path (which may not be true
1791 * if the merge involves a rename).
1792 */
2783 - if (was_tracked(path)) {
1793 + path_renamed_outside_HEAD = !path2 || !strcmp(path, path2);
1794 + if (!path_renamed_outside_HEAD) {
1795 add_cacheinfo(o, mfi.mode, &mfi.oid, path,
1796 0, (!o->call_depth), 0);
1797 return mfi.clean;
@@ -2798,7 +1809,7 @@ static int merge_content(struct merge_options *o,
1809 return -1;
1810 }
1811
2801 - if (df_conflict_remains || file_in_way) {
1812 + if (df_conflict_remains) {
1813 char *new_path;
1814 if (o->call_depth) {
1815 remove_file_from_cache(path);
@@ -2832,30 +1843,6 @@ static int merge_content(struct merge_options *o,
1843 return mfi.clean;
1844 }
1845
2835 -static int conflict_rename_normal(struct merge_options *o,
2836 - const char *path,
2837 - struct object_id *o_oid, unsigned int o_mode,
2838 - struct object_id *a_oid, unsigned int a_mode,
2839 - struct object_id *b_oid, unsigned int b_mode,
2840 - struct rename_conflict_info *ci)
2841 -{
2842 - int clean_merge;
2843 - int file_in_the_way = 0;
2844 -
2845 - if (was_dirty(o, path)) {
2846 - file_in_the_way = 1;
2847 - output(o, 1, _("Refusing to lose dirty file at %s"), path);
2848 - }
2849 -
2850 - /* Merge the content and write it out */
2851 - clean_merge = merge_content(o, path, file_in_the_way,
2852 - o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
2853 - ci);
2854 - if (clean_merge > 0 && file_in_the_way)
2855 - clean_merge = 0;
2856 - return clean_merge;
2857 -}
2858 -
1846 /* Per entry merge function */
1847 static int process_entry(struct merge_options *o,
1848 const char *path, struct stage_data *entry)
@@ -2875,20 +1862,9 @@ static int process_entry(struct merge_options *o,
1862 switch (conflict_info->rename_type) {
1863 case RENAME_NORMAL:
1864 case RENAME_ONE_FILE_TO_ONE:
2878 - clean_merge = conflict_rename_normal(o,
2879 - path,
2880 - o_oid, o_mode,
2881 - a_oid, a_mode,
2882 - b_oid, b_mode,
2883 - conflict_info);
2884 - break;
2885 - case RENAME_DIR:
2886 - clean_merge = 1;
2887 - if (conflict_rename_dir(o,
2888 - conflict_info->pair1,
2889 - conflict_info->branch1,
2890 - conflict_info->branch2))
2891 - clean_merge = -1;
1865 + clean_merge = merge_content(o, path,
1866 + o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
1867 + conflict_info);
1868 break;
1869 case RENAME_DELETE:
1870 clean_merge = 0;
@@ -2976,7 +1952,7 @@ static int process_entry(struct merge_options *o,
1952 } else if (a_oid && b_oid) {
1953 /* Case C: Added in both (check for same permissions) and */
1954 /* case D: Modified in both, but differently. */
2979 - clean_merge = merge_content(o, path, 0 /* file_in_way */,
1955 + clean_merge = merge_content(o, path,
1956 o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
1957 NULL);
1958 } else if (!o_oid && !a_oid && !b_oid) {
@@ -3017,7 +1993,7 @@ int merge_trees(struct merge_options *o,
1993 return 1;
1994 }
1995
3020 - code = git_merge_trees(o, common, head, merge);
1996 + code = git_merge_trees(o->call_depth, common, head, merge);
1997
1998 if (code != 0) {
1999 if (show(o, 4) || o->call_depth)
@@ -3028,8 +2004,7 @@ int merge_trees(struct merge_options *o,
2004 }
2005
2006 if (unmerged_cache()) {
3031 - struct string_list *entries;
3032 - struct rename_info re_info;
2007 + struct string_list *entries, *re_head, *re_merge;
2008 int i;
2009 /*
2010 * Only need the hashmap while processing entries, so
@@ -3043,8 +2018,9 @@ int merge_trees(struct merge_options *o,
2018 get_files_dirs(o, merge);
2019
2020 entries = get_unmerged();
3046 - clean = handle_renames(o, common, head, merge, entries,
3047 - &re_info);
2021 + re_head = get_renames(o, head, common, head, merge, entries);
2022 + re_merge = get_renames(o, merge, common, head, merge, entries);
2023 + clean = process_renames(o, re_head, re_merge);
2024 record_df_conflict_files(o, entries);
2025 if (clean < 0)
2026 goto cleanup;
@@ -3069,13 +2045,16 @@ int merge_trees(struct merge_options *o,
2045 }
2046
2047 cleanup:
3072 - final_cleanup_renames(&re_info);
3073 -
2048 + string_list_clear(re_merge, 0);
2049 + string_list_clear(re_head, 0);
2050 string_list_clear(entries, 1);
3075 - free(entries);
2051
2052 hashmap_free(&o->current_file_dir_set, 1);
2053
2054 + free(re_merge);
2055 + free(re_head);
2056 + free(entries);
2057 +
2058 if (clean < 0)
2059 return clean;
2060 }
merge-recursive.h
-27
@@ -1,7 +1,6 @@
1 #ifndef MERGE_RECURSIVE_H
2 #define MERGE_RECURSIVE_H
3
4 -#include "unpack-trees.h"
4 #include "string-list.h"
5
6 struct merge_options {
@@ -28,32 +27,6 @@ struct merge_options {
27 struct strbuf obuf;
28 struct hashmap current_file_dir_set;
29 struct string_list df_conflict_file_set;
31 - struct unpack_trees_options unpack_opts;
32 -};
33 -
34 -/*
35 - * For dir_rename_entry, directory names are stored as a full path from the
36 - * toplevel of the repository and do not include a trailing '/'. Also:
37 - *
38 - * dir: original name of directory being renamed
39 - * non_unique_new_dir: if true, could not determine new_dir
40 - * new_dir: final name of directory being renamed
41 - * possible_new_dirs: temporary used to help determine new_dir; see comments
42 - * in get_directory_renames() for details
43 - */
44 -struct dir_rename_entry {
45 - struct hashmap_entry ent; /* must be the first member! */
46 - char *dir;
47 - unsigned non_unique_new_dir:1;
48 - struct strbuf new_dir;
49 - struct string_list possible_new_dirs;
50 -};
51 -
52 -struct collision_entry {
53 - struct hashmap_entry ent; /* must be the first member! */
54 - char *target_file;
55 - struct string_list source_files;
56 - unsigned reported_already:1;
30 };
31
32 /* merge_trees() but with recursive ancestor consolidation */
strbuf.c
-16
@@ -1,6 +1,5 @@
1 #include "cache.h"
2 #include "refs.h"
3 -#include "string-list.h"
3 #include "utf8.h"
4
5 int starts_with(const char *str, const char *prefix)
@@ -172,21 +171,6 @@ struct strbuf **strbuf_split_buf(const char *str, size_t slen,
171 return ret;
172 }
173
175 -void strbuf_add_separated_string_list(struct strbuf *str,
176 - const char *sep,
177 - struct string_list *slist)
178 -{
179 - struct string_list_item *item;
180 - int sep_needed = 0;
181 -
182 - for_each_string_list_item(item, slist) {
183 - if (sep_needed)
184 - strbuf_addstr(str, sep);
185 - strbuf_addstr(str, item->string);
186 - sep_needed = 1;
187 - }
188 -}
189 -
174 void strbuf_list_free(struct strbuf **sbs)
175 {
176 struct strbuf **s = sbs;
strbuf.h
-16
@@ -1,8 +1,6 @@
1 #ifndef STRBUF_H
2 #define STRBUF_H
3
4 -struct string_list;
5 -
4 /**
5 * strbuf's are meant to be used with all the usual C string and memory
6 * APIs. Given that the length of the buffer is known, it's often better to
@@ -539,20 +537,6 @@ static inline struct strbuf **strbuf_split(const struct strbuf *sb,
537 return strbuf_split_max(sb, terminator, 0);
538 }
539
542 -/*
543 - * Adds all strings of a string list to the strbuf, separated by the given
544 - * separator. For example, if sep is
545 - * ', '
546 - * and slist contains
547 - * ['element1', 'element2', ..., 'elementN'],
548 - * then write:
549 - * 'element1, element2, ..., elementN'
550 - * to str. If only one element, just write "element1" to str.
551 - */
552 -extern void strbuf_add_separated_string_list(struct strbuf *str,
553 - const char *sep,
554 - struct string_list *slist);
555 -
540 /**
541 * Free a NULL-terminated list of strbufs (for example, the return
542 * values of the strbuf_split*() functions).
t/t3501-revert-cherry-pick.sh
+1 -1
@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick "-" works with arguments' '
141 test_cmp expect actual
142 '
143
144 -test_expect_success 'cherry-pick works with dirty renamed file' '
144 +test_expect_failure 'cherry-pick works with dirty renamed file' '
145 test_commit to-rename &&
146 git checkout -b unrelated &&
147 test_commit unrelated &&
t/t6043-merge-rename-directories.sh deleted
-3998
@@ -1,3998 +0,0 @@
1 -#!/bin/sh
2 -
3 -test_description="recursive merge with directory renames"
4 -# includes checking of many corner cases, with a similar methodology to:
5 -# t6042: corner cases with renames but not criss-cross merges
6 -# t6036: corner cases with both renames and criss-cross merges
7 -#
8 -# The setup for all of them, pictorially, is:
9 -#
10 -# A
11 -# o
12 -# / \
13 -# O o ?
14 -# \ /
15 -# o
16 -# B
17 -#
18 -# To help make it easier to follow the flow of tests, they have been
19 -# divided into sections and each test will start with a quick explanation
20 -# of what commits O, A, and B contain.
21 -#
22 -# Notation:
23 -# z/{b,c} means files z/b and z/c both exist
24 -# x/d_1 means file x/d exists with content d1. (Purpose of the
25 -# underscore notation is to differentiate different
26 -# files that might be renamed into each other's paths.)
27 -
28 -. ./test-lib.sh
29 -
30 -
31 -###########################################################################
32 -# SECTION 1: Basic cases we should be able to handle
33 -###########################################################################
34 -
35 -# Testcase 1a, Basic directory rename.
36 -# Commit O: z/{b,c}
37 -# Commit A: y/{b,c}
38 -# Commit B: z/{b,c,d,e/f}
39 -# Expected: y/{b,c,d,e/f}
40 -
41 -test_expect_success '1a-setup: Simple directory rename detection' '
42 - test_create_repo 1a &&
43 - (
44 - cd 1a &&
45 -
46 - mkdir z &&
47 - echo b >z/b &&
48 - echo c >z/c &&
49 - git add z &&
50 - test_tick &&
51 - git commit -m "O" &&
52 -
53 - git branch O &&
54 - git branch A &&
55 - git branch B &&
56 -
57 - git checkout A &&
58 - git mv z y &&
59 - test_tick &&
60 - git commit -m "A" &&
61 -
62 - git checkout B &&
63 - echo d >z/d &&
64 - mkdir z/e &&
65 - echo f >z/e/f &&
66 - git add z/d z/e/f &&
67 - test_tick &&
68 - git commit -m "B"
69 - )
70 -'
71 -
72 -test_expect_success '1a-check: Simple directory rename detection' '
73 - (
74 - cd 1a &&
75 -
76 - git checkout A^0 &&
77 -
78 - git merge -s recursive B^0 &&
79 -
80 - git ls-files -s >out &&
81 - test_line_count = 4 out &&
82 -
83 - git rev-parse >actual \
84 - HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e/f &&
85 - git rev-parse >expect \
86 - O:z/b O:z/c B:z/d B:z/e/f &&
87 - test_cmp expect actual &&
88 -
89 - git hash-object y/d >actual &&
90 - git rev-parse B:z/d >expect &&
91 - test_cmp expect actual &&
92 -
93 - test_must_fail git rev-parse HEAD:z/d &&
94 - test_must_fail git rev-parse HEAD:z/e/f &&
95 - test_path_is_missing z/d &&
96 - test_path_is_missing z/e/f
97 - )
98 -'
99 -
100 -# Testcase 1b, Merge a directory with another
101 -# Commit O: z/{b,c}, y/d
102 -# Commit A: z/{b,c,e}, y/d
103 -# Commit B: y/{b,c,d}
104 -# Expected: y/{b,c,d,e}
105 -
106 -test_expect_success '1b-setup: Merge a directory with another' '
107 - test_create_repo 1b &&
108 - (
109 - cd 1b &&
110 -
111 - mkdir z &&
112 - echo b >z/b &&
113 - echo c >z/c &&
114 - mkdir y &&
115 - echo d >y/d &&
116 - git add z y &&
117 - test_tick &&
118 - git commit -m "O" &&
119 -
120 - git branch O &&
121 - git branch A &&
122 - git branch B &&
123 -
124 - git checkout A &&
125 - echo e >z/e &&
126 - git add z/e &&
127 - test_tick &&
128 - git commit -m "A" &&
129 -
130 - git checkout B &&
131 - git mv z/b y &&
132 - git mv z/c y &&
133 - rmdir z &&
134 - test_tick &&
135 - git commit -m "B"
136 - )
137 -'
138 -
139 -test_expect_success '1b-check: Merge a directory with another' '
140 - (
141 - cd 1b &&
142 -
143 - git checkout A^0 &&
144 -
145 - git merge -s recursive B^0 &&
146 -
147 - git ls-files -s >out &&
148 - test_line_count = 4 out &&
149 -
150 - git rev-parse >actual \
151 - HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e &&
152 - git rev-parse >expect \
153 - O:z/b O:z/c O:y/d A:z/e &&
154 - test_cmp expect actual &&
155 - test_must_fail git rev-parse HEAD:z/e
156 - )
157 -'
158 -
159 -# Testcase 1c, Transitive renaming
160 -# (Related to testcases 3a and 6d -- when should a transitive rename apply?)
161 -# (Related to testcases 9c and 9d -- can transitivity repeat?)
162 -# (Related to testcase 12b -- joint-transitivity?)
163 -# Commit O: z/{b,c}, x/d
164 -# Commit A: y/{b,c}, x/d
165 -# Commit B: z/{b,c,d}
166 -# Expected: y/{b,c,d} (because x/d -> z/d -> y/d)
167 -
168 -test_expect_success '1c-setup: Transitive renaming' '
169 - test_create_repo 1c &&
170 - (
171 - cd 1c &&
172 -
173 - mkdir z &&
174 - echo b >z/b &&
175 - echo c >z/c &&
176 - mkdir x &&
177 - echo d >x/d &&
178 - git add z x &&
179 - test_tick &&
180 - git commit -m "O" &&
181 -
182 - git branch O &&
183 - git branch A &&
184 - git branch B &&
185 -
186 - git checkout A &&
187 - git mv z y &&
188 - test_tick &&
189 - git commit -m "A" &&
190 -
191 - git checkout B &&
192 - git mv x/d z/d &&
193 - test_tick &&
194 - git commit -m "B"
195 - )
196 -'
197 -
198 -test_expect_success '1c-check: Transitive renaming' '
199 - (
200 - cd 1c &&
201 -
202 - git checkout A^0 &&
203 -
204 - git merge -s recursive B^0 &&
205 -
206 - git ls-files -s >out &&
207 - test_line_count = 3 out &&
208 -
209 - git rev-parse >actual \
210 - HEAD:y/b HEAD:y/c HEAD:y/d &&
211 - git rev-parse >expect \
212 - O:z/b O:z/c O:x/d &&
213 - test_cmp expect actual &&
214 - test_must_fail git rev-parse HEAD:x/d &&
215 - test_must_fail git rev-parse HEAD:z/d &&
216 - test_path_is_missing z/d
217 - )
218 -'
219 -
220 -# Testcase 1d, Directory renames (merging two directories into one new one)
221 -# cause a rename/rename(2to1) conflict
222 -# (Related to testcases 1c and 7b)
223 -# Commit O. z/{b,c}, y/{d,e}
224 -# Commit A. x/{b,c}, y/{d,e,m,wham_1}
225 -# Commit B. z/{b,c,n,wham_2}, x/{d,e}
226 -# Expected: x/{b,c,d,e,m,n}, CONFLICT:(y/wham_1 & z/wham_2 -> x/wham)
227 -# Note: y/m & z/n should definitely move into x. By the same token, both
228 -# y/wham_1 & z/wham_2 should too...giving us a conflict.
229 -
230 -test_expect_success '1d-setup: Directory renames cause a rename/rename(2to1) conflict' '
231 - test_create_repo 1d &&
232 - (
233 - cd 1d &&
234 -
235 - mkdir z &&
236 - echo b >z/b &&
237 - echo c >z/c &&
238 - mkdir y &&
239 - echo d >y/d &&
240 - echo e >y/e &&
241 - git add z y &&
242 - test_tick &&
243 - git commit -m "O" &&
244 -
245 - git branch O &&
246 - git branch A &&
247 - git branch B &&
248 -
249 - git checkout A &&
250 - git mv z x &&
251 - echo m >y/m &&
252 - echo wham1 >y/wham &&
253 - git add y &&
254 - test_tick &&
255 - git commit -m "A" &&
256 -
257 - git checkout B &&
258 - git mv y x &&
259 - echo n >z/n &&
260 - echo wham2 >z/wham &&
261 - git add z &&
262 - test_tick &&
263 - git commit -m "B"
264 - )
265 -'
266 -
267 -test_expect_success '1d-check: Directory renames cause a rename/rename(2to1) conflict' '
268 - (
269 - cd 1d &&
270 -
271 - git checkout A^0 &&
272 -
273 - test_must_fail git merge -s recursive B^0 >out &&
274 - test_i18ngrep "CONFLICT (rename/rename)" out &&
275 -
276 - git ls-files -s >out &&
277 - test_line_count = 8 out &&
278 - git ls-files -u >out &&
279 - test_line_count = 2 out &&
280 - git ls-files -o >out &&
281 - test_line_count = 3 out &&
282 -
283 - git rev-parse >actual \
284 - :0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n &&
285 - git rev-parse >expect \
286 - O:z/b O:z/c O:y/d O:y/e A:y/m B:z/n &&
287 - test_cmp expect actual &&
288 -
289 - test_must_fail git rev-parse :0:x/wham &&
290 - git rev-parse >actual \
291 - :2:x/wham :3:x/wham &&
292 - git rev-parse >expect \
293 - A:y/wham B:z/wham &&
294 - test_cmp expect actual &&
295 -
296 - test_path_is_missing x/wham &&
297 - test_path_is_file x/wham~HEAD &&
298 - test_path_is_file x/wham~B^0 &&
299 -
300 - git hash-object >actual \
301 - x/wham~HEAD x/wham~B^0 &&
302 - git rev-parse >expect \
303 - A:y/wham B:z/wham &&
304 - test_cmp expect actual
305 - )
306 -'
307 -
308 -# Testcase 1e, Renamed directory, with all filenames being renamed too
309 -# (Related to testcases 9f & 9g)
310 -# Commit O: z/{oldb,oldc}
311 -# Commit A: y/{newb,newc}
312 -# Commit B: z/{oldb,oldc,d}
313 -# Expected: y/{newb,newc,d}
314 -
315 -test_expect_success '1e-setup: Renamed directory, with all files being renamed too' '
316 - test_create_repo 1e &&
317 - (
318 - cd 1e &&
319 -
320 - mkdir z &&
321 - echo b >z/oldb &&
322 - echo c >z/oldc &&
323 - git add z &&
324 - test_tick &&
325 - git commit -m "O" &&
326 -
327 - git branch O &&
328 - git branch A &&
329 - git branch B &&
330 -
331 - git checkout A &&
332 - mkdir y &&
333 - git mv z/oldb y/newb &&
334 - git mv z/oldc y/newc &&
335 - test_tick &&
336 - git commit -m "A" &&
337 -
338 - git checkout B &&
339 - echo d >z/d &&
340 - git add z/d &&
341 - test_tick &&
342 - git commit -m "B"
343 - )
344 -'
345 -
346 -test_expect_success '1e-check: Renamed directory, with all files being renamed too' '
347 - (
348 - cd 1e &&
349 -
350 - git checkout A^0 &&
351 -
352 - git merge -s recursive B^0 &&
353 -
354 - git ls-files -s >out &&
355 - test_line_count = 3 out &&
356 -
357 - git rev-parse >actual \
358 - HEAD:y/newb HEAD:y/newc HEAD:y/d &&
359 - git rev-parse >expect \
360 - O:z/oldb O:z/oldc B:z/d &&
361 - test_cmp expect actual &&
362 - test_must_fail git rev-parse HEAD:z/d
363 - )
364 -'
365 -
366 -# Testcase 1f, Split a directory into two other directories
367 -# (Related to testcases 3a, all of section 2, and all of section 4)
368 -# Commit O: z/{b,c,d,e,f}
369 -# Commit A: z/{b,c,d,e,f,g}
370 -# Commit B: y/{b,c}, x/{d,e,f}
371 -# Expected: y/{b,c}, x/{d,e,f,g}
372 -
373 -test_expect_success '1f-setup: Split a directory into two other directories' '
374 - test_create_repo 1f &&
375 - (
376 - cd 1f &&
377 -
378 - mkdir z &&
379 - echo b >z/b &&
380 - echo c >z/c &&
381 - echo d >z/d &&
382 - echo e >z/e &&
383 - echo f >z/f &&
384 - git add z &&
385 - test_tick &&
386 - git commit -m "O" &&
387 -
388 - git branch O &&
389 - git branch A &&
390 - git branch B &&
391 -
392 - git checkout A &&
393 - echo g >z/g &&
394 - git add z/g &&
395 - test_tick &&
396 - git commit -m "A" &&
397 -
398 - git checkout B &&
399 - mkdir y &&
400 - mkdir x &&
401 - git mv z/b y/ &&
402 - git mv z/c y/ &&
403 - git mv z/d x/ &&
404 - git mv z/e x/ &&
405 - git mv z/f x/ &&
406 - rmdir z &&
407 - test_tick &&
408 - git commit -m "B"
409 - )
410 -'
411 -
412 -test_expect_success '1f-check: Split a directory into two other directories' '
413 - (
414 - cd 1f &&
415 -
416 - git checkout A^0 &&
417 -
418 - git merge -s recursive B^0 &&
419 -
420 - git ls-files -s >out &&
421 - test_line_count = 6 out &&
422 -
423 - git rev-parse >actual \
424 - HEAD:y/b HEAD:y/c HEAD:x/d HEAD:x/e HEAD:x/f HEAD:x/g &&
425 - git rev-parse >expect \
426 - O:z/b O:z/c O:z/d O:z/e O:z/f A:z/g &&
427 - test_cmp expect actual &&
428 - test_path_is_missing z/g &&
429 - test_must_fail git rev-parse HEAD:z/g
430 - )
431 -'
432 -
433 -###########################################################################
434 -# Rules suggested by testcases in section 1:
435 -#
436 -# We should still detect the directory rename even if it wasn't just
437 -# the directory renamed, but the files within it. (see 1b)
438 -#
439 -# If renames split a directory into two or more others, the directory
440 -# with the most renames, "wins" (see 1c). However, see the testcases
441 -# in section 2, plus testcases 3a and 4a.
442 -###########################################################################
443 -
444 -
445 -###########################################################################
446 -# SECTION 2: Split into multiple directories, with equal number of paths
447 -#
448 -# Explore the splitting-a-directory rules a bit; what happens in the
449 -# edge cases?
450 -#
451 -# Note that there is a closely related case of a directory not being
452 -# split on either side of history, but being renamed differently on
453 -# each side. See testcase 8e for that.
454 -###########################################################################
455 -
456 -# Testcase 2a, Directory split into two on one side, with equal numbers of paths
457 -# Commit O: z/{b,c}
458 -# Commit A: y/b, w/c
459 -# Commit B: z/{b,c,d}
460 -# Expected: y/b, w/c, z/d, with warning about z/ -> (y/ vs. w/) conflict
461 -test_expect_success '2a-setup: Directory split into two on one side, with equal numbers of paths' '
462 - test_create_repo 2a &&
463 - (
464 - cd 2a &&
465 -
466 - mkdir z &&
467 - echo b >z/b &&
468 - echo c >z/c &&
469 - git add z &&
470 - test_tick &&
471 - git commit -m "O" &&
472 -
473 - git branch O &&
474 - git branch A &&
475 - git branch B &&
476 -
477 - git checkout A &&
478 - mkdir y &&
479 - mkdir w &&
480 - git mv z/b y/ &&
481 - git mv z/c w/ &&
482 - test_tick &&
483 - git commit -m "A" &&
484 -
485 - git checkout B &&
486 - echo d >z/d &&
487 - git add z/d &&
488 - test_tick &&
489 - git commit -m "B"
490 - )
491 -'
492 -
493 -test_expect_success '2a-check: Directory split into two on one side, with equal numbers of paths' '
494 - (
495 - cd 2a &&
496 -
497 - git checkout A^0 &&
498 -
499 - test_must_fail git merge -s recursive B^0 >out &&
500 - test_i18ngrep "CONFLICT.*directory rename split" out &&
501 -
502 - git ls-files -s >out &&
503 - test_line_count = 3 out &&
504 - git ls-files -u >out &&
505 - test_line_count = 0 out &&
506 - git ls-files -o >out &&
507 - test_line_count = 1 out &&
508 -
509 - git rev-parse >actual \
510 - :0:y/b :0:w/c :0:z/d &&
511 - git rev-parse >expect \
512 - O:z/b O:z/c B:z/d &&
513 - test_cmp expect actual
514 - )
515 -'
516 -
517 -# Testcase 2b, Directory split into two on one side, with equal numbers of paths
518 -# Commit O: z/{b,c}
519 -# Commit A: y/b, w/c
520 -# Commit B: z/{b,c}, x/d
521 -# Expected: y/b, w/c, x/d; No warning about z/ -> (y/ vs. w/) conflict
522 -test_expect_success '2b-setup: Directory split into two on one side, with equal numbers of paths' '
523 - test_create_repo 2b &&
524 - (
525 - cd 2b &&
526 -
527 - mkdir z &&
528 - echo b >z/b &&
529 - echo c >z/c &&
530 - git add z &&
531 - test_tick &&
532 - git commit -m "O" &&
533 -
534 - git branch O &&
535 - git branch A &&
536 - git branch B &&
537 -
538 - git checkout A &&
539 - mkdir y &&
540 - mkdir w &&
541 - git mv z/b y/ &&
542 - git mv z/c w/ &&
543 - test_tick &&
544 - git commit -m "A" &&
545 -
546 - git checkout B &&
547 - mkdir x &&
548 - echo d >x/d &&
549 - git add x/d &&
550 - test_tick &&
551 - git commit -m "B"
552 - )
553 -'
554 -
555 -test_expect_success '2b-check: Directory split into two on one side, with equal numbers of paths' '
556 - (
557 - cd 2b &&
558 -
559 - git checkout A^0 &&
560 -
561 - git merge -s recursive B^0 >out &&
562 -
563 - git ls-files -s >out &&
564 - test_line_count = 3 out &&
565 - git ls-files -u >out &&
566 - test_line_count = 0 out &&
567 - git ls-files -o >out &&
568 - test_line_count = 1 out &&
569 -
570 - git rev-parse >actual \
571 - :0:y/b :0:w/c :0:x/d &&
572 - git rev-parse >expect \
573 - O:z/b O:z/c B:x/d &&
574 - test_cmp expect actual &&
575 - test_i18ngrep ! "CONFLICT.*directory rename split" out
576 - )
577 -'
578 -
579 -###########################################################################
580 -# Rules suggested by section 2:
581 -#
582 -# None; the rule was already covered in section 1. These testcases are
583 -# here just to make sure the conflict resolution and necessary warning
584 -# messages are handled correctly.
585 -###########################################################################
586 -
587 -
588 -###########################################################################
589 -# SECTION 3: Path in question is the source path for some rename already
590 -#
591 -# Combining cases from Section 1 and trying to handle them could lead to
592 -# directory renaming detection being over-applied. So, this section
593 -# provides some good testcases to check that the implementation doesn't go
594 -# too far.
595 -###########################################################################
596 -
597 -# Testcase 3a, Avoid implicit rename if involved as source on other side
598 -# (Related to testcases 1c, 1f, and 9h)
599 -# Commit O: z/{b,c,d}
600 -# Commit A: z/{b,c,d} (no change)
601 -# Commit B: y/{b,c}, x/d
602 -# Expected: y/{b,c}, x/d
603 -test_expect_success '3a-setup: Avoid implicit rename if involved as source on other side' '
604 - test_create_repo 3a &&
605 - (
606 - cd 3a &&
607 -
608 - mkdir z &&
609 - echo b >z/b &&
610 - echo c >z/c &&
611 - echo d >z/d &&
612 - git add z &&
613 - test_tick &&
614 - git commit -m "O" &&
615 -
616 - git branch O &&
617 - git branch A &&
618 - git branch B &&
619 -
620 - git checkout A &&
621 - test_tick &&
622 - git commit --allow-empty -m "A" &&
623 -
624 - git checkout B &&
625 - mkdir y &&
626 - mkdir x &&
627 - git mv z/b y/ &&
628 - git mv z/c y/ &&
629 - git mv z/d x/ &&
630 - rmdir z &&
631 - test_tick &&
632 - git commit -m "B"
633 - )
634 -'
635 -
636 -test_expect_success '3a-check: Avoid implicit rename if involved as source on other side' '
637 - (
638 - cd 3a &&
639 -
640 - git checkout A^0 &&
641 -
642 - git merge -s recursive B^0 &&
643 -
644 - git ls-files -s >out &&
645 - test_line_count = 3 out &&
646 -
647 - git rev-parse >actual \
648 - HEAD:y/b HEAD:y/c HEAD:x/d &&
649 - git rev-parse >expect \
650 - O:z/b O:z/c O:z/d &&
651 - test_cmp expect actual
652 - )
653 -'
654 -
655 -# Testcase 3b, Avoid implicit rename if involved as source on other side
656 -# (Related to testcases 5c and 7c, also kind of 1e and 1f)
657 -# Commit O: z/{b,c,d}
658 -# Commit A: y/{b,c}, x/d
659 -# Commit B: z/{b,c}, w/d
660 -# Expected: y/{b,c}, CONFLICT:(z/d -> x/d vs. w/d)
661 -# NOTE: We're particularly checking that since z/d is already involved as
662 -# a source in a file rename on the same side of history, that we don't
663 -# get it involved in directory rename detection. If it were, we might
664 -# end up with CONFLICT:(z/d -> y/d vs. x/d vs. w/d), i.e. a
665 -# rename/rename/rename(1to3) conflict, which is just weird.
666 -test_expect_success '3b-setup: Avoid implicit rename if involved as source on current side' '
667 - test_create_repo 3b &&
668 - (
669 - cd 3b &&
670 -
671 - mkdir z &&
672 - echo b >z/b &&
673 - echo c >z/c &&
674 - echo d >z/d &&
675 - git add z &&
676 - test_tick &&
677 - git commit -m "O" &&
678 -
679 - git branch O &&
680 - git branch A &&
681 - git branch B &&
682 -
683 - git checkout A &&
684 - mkdir y &&
685 - mkdir x &&
686 - git mv z/b y/ &&
687 - git mv z/c y/ &&
688 - git mv z/d x/ &&
689 - rmdir z &&
690 - test_tick &&
691 - git commit -m "A" &&
692 -
693 - git checkout B &&
694 - mkdir w &&
695 - git mv z/d w/ &&
696 - test_tick &&
697 - git commit -m "B"
698 - )
699 -'
700 -
701 -test_expect_success '3b-check: Avoid implicit rename if involved as source on current side' '
702 - (
703 - cd 3b &&
704 -
705 - git checkout A^0 &&
706 -
707 - test_must_fail git merge -s recursive B^0 >out &&
708 - test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out &&
709 - test_i18ngrep ! CONFLICT.*rename/rename.*y/d out &&
710 -
711 - git ls-files -s >out &&
712 - test_line_count = 5 out &&
713 - git ls-files -u >out &&
714 - test_line_count = 3 out &&
715 - git ls-files -o >out &&
716 - test_line_count = 1 out &&
717 -
718 - git rev-parse >actual \
719 - :0:y/b :0:y/c :1:z/d :2:x/d :3:w/d &&
720 - git rev-parse >expect \
721 - O:z/b O:z/c O:z/d O:z/d O:z/d &&
722 - test_cmp expect actual &&
723 -
724 - test_path_is_missing z/d &&
725 - git hash-object >actual \
726 - x/d w/d &&
727 - git rev-parse >expect \
728 - O:z/d O:z/d &&
729 - test_cmp expect actual
730 - )
731 -'
732 -
733 -###########################################################################
734 -# Rules suggested by section 3:
735 -#
736 -# Avoid directory-rename-detection for a path, if that path is the source
737 -# of a rename on either side of a merge.
738 -###########################################################################
739 -
740 -
741 -###########################################################################
742 -# SECTION 4: Partially renamed directory; still exists on both sides of merge
743 -#
744 -# What if we were to attempt to do directory rename detection when someone
745 -# "mostly" moved a directory but still left some files around, or,
746 -# equivalently, fully renamed a directory in one commmit and then recreated
747 -# that directory in a later commit adding some new files and then tried to
748 -# merge?
749 -#
750 -# It's hard to divine user intent in these cases, because you can make an
751 -# argument that, depending on the intermediate history of the side being
752 -# merged, that some users will want files in that directory to
753 -# automatically be detected and renamed, while users with a different
754 -# intermediate history wouldn't want that rename to happen.
755 -#
756 -# I think that it is best to simply not have directory rename detection
757 -# apply to such cases. My reasoning for this is four-fold: (1) it's
758 -# easiest for users in general to figure out what happened if we don't
759 -# apply directory rename detection in any such case, (2) it's an easy rule
760 -# to explain ["We don't do directory rename detection if the directory
761 -# still exists on both sides of the merge"], (3) we can get some hairy
762 -# edge/corner cases that would be really confusing and possibly not even
763 -# representable in the index if we were to even try, and [related to 3] (4)
764 -# attempting to resolve this issue of divining user intent by examining
765 -# intermediate history goes against the spirit of three-way merges and is a
766 -# path towards crazy corner cases that are far more complex than what we're
767 -# already dealing with.
768 -#
769 -# Note that the wording of the rule ("We don't do directory rename
770 -# detection if the directory still exists on both sides of the merge.")
771 -# also excludes "renaming" of a directory into a subdirectory of itself
772 -# (e.g. /some/dir/* -> /some/dir/subdir/*). It may be possible to carve
773 -# out an exception for "renaming"-beneath-itself cases without opening
774 -# weird edge/corner cases for other partial directory renames, but for now
775 -# we are keeping the rule simple.
776 -#
777 -# This section contains a test for a partially-renamed-directory case.
778 -###########################################################################
779 -
780 -# Testcase 4a, Directory split, with original directory still present
781 -# (Related to testcase 1f)
782 -# Commit O: z/{b,c,d,e}
783 -# Commit A: y/{b,c,d}, z/e
784 -# Commit B: z/{b,c,d,e,f}
785 -# Expected: y/{b,c,d}, z/{e,f}
786 -# NOTE: Even though most files from z moved to y, we don't want f to follow.
787 -
788 -test_expect_success '4a-setup: Directory split, with original directory still present' '
789 - test_create_repo 4a &&
790 - (
791 - cd 4a &&
792 -
793 - mkdir z &&
794 - echo b >z/b &&
795 - echo c >z/c &&
796 - echo d >z/d &&
797 - echo e >z/e &&
798 - git add z &&
799 - test_tick &&
800 - git commit -m "O" &&
801 -
802 - git branch O &&
803 - git branch A &&
804 - git branch B &&
805 -
806 - git checkout A &&
807 - mkdir y &&
808 - git mv z/b y/ &&
809 - git mv z/c y/ &&
810 - git mv z/d y/ &&
811 - test_tick &&
812 - git commit -m "A" &&
813 -
814 - git checkout B &&
815 - echo f >z/f &&
816 - git add z/f &&
817 - test_tick &&
818 - git commit -m "B"
819 - )
820 -'
821 -
822 -test_expect_success '4a-check: Directory split, with original directory still present' '
823 - (
824 - cd 4a &&
825 -
826 - git checkout A^0 &&
827 -
828 - git merge -s recursive B^0 &&
829 -
830 - git ls-files -s >out &&
831 - test_line_count = 5 out &&
832 - git ls-files -u >out &&
833 - test_line_count = 0 out &&
834 - git ls-files -o >out &&
835 - test_line_count = 1 out &&
836 -
837 - git rev-parse >actual \
838 - HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/e HEAD:z/f &&
839 - git rev-parse >expect \
840 - O:z/b O:z/c O:z/d O:z/e B:z/f &&
841 - test_cmp expect actual
842 - )
843 -'
844 -
845 -###########################################################################
846 -# Rules suggested by section 4:
847 -#
848 -# Directory-rename-detection should be turned off for any directories (as
849 -# a source for renames) that exist on both sides of the merge. (The "as
850 -# a source for renames" clarification is due to cases like 1c where
851 -# the target directory exists on both sides and we do want the rename
852 -# detection.) But, sadly, see testcase 8b.
853 -###########################################################################
854 -
855 -
856 -###########################################################################
857 -# SECTION 5: Files/directories in the way of subset of to-be-renamed paths
858 -#
859 -# Implicitly renaming files due to a detected directory rename could run
860 -# into problems if there are files or directories in the way of the paths
861 -# we want to rename. Explore such cases in this section.
862 -###########################################################################
863 -
864 -# Testcase 5a, Merge directories, other side adds files to original and target
865 -# Commit O: z/{b,c}, y/d
866 -# Commit A: z/{b,c,e_1,f}, y/{d,e_2}
867 -# Commit B: y/{b,c,d}
868 -# Expected: z/e_1, y/{b,c,d,e_2,f} + CONFLICT warning
869 -# NOTE: While directory rename detection is active here causing z/f to
870 -# become y/f, we did not apply this for z/e_1 because that would
871 -# give us an add/add conflict for y/e_1 vs y/e_2. This problem with
872 -# this add/add, is that both versions of y/e are from the same side
873 -# of history, giving us no way to represent this conflict in the
874 -# index.
875 -
876 -test_expect_success '5a-setup: Merge directories, other side adds files to original and target' '
877 - test_create_repo 5a &&
878 - (
879 - cd 5a &&
880 -
881 - mkdir z &&
882 - echo b >z/b &&
883 - echo c >z/c &&
884 - mkdir y &&
885 - echo d >y/d &&
886 - git add z y &&
887 - test_tick &&
888 - git commit -m "O" &&
889 -
890 - git branch O &&
891 - git branch A &&
892 - git branch B &&
893 -
894 - git checkout A &&
895 - echo e1 >z/e &&
896 - echo f >z/f &&
897 - echo e2 >y/e &&
898 - git add z/e z/f y/e &&
899 - test_tick &&
900 - git commit -m "A" &&
901 -
902 - git checkout B &&
903 - git mv z/b y/ &&
904 - git mv z/c y/ &&
905 - rmdir z &&
906 - test_tick &&
907 - git commit -m "B"
908 - )
909 -'
910 -
911 -test_expect_success '5a-check: Merge directories, other side adds files to original and target' '
912 - (
913 - cd 5a &&
914 -
915 - git checkout A^0 &&
916 -
917 - test_must_fail git merge -s recursive B^0 >out &&
918 - test_i18ngrep "CONFLICT.*implicit dir rename" out &&
919 -
920 - git ls-files -s >out &&
921 - test_line_count = 6 out &&
922 - git ls-files -u >out &&
923 - test_line_count = 0 out &&
924 - git ls-files -o >out &&
925 - test_line_count = 1 out &&
926 -
927 - git rev-parse >actual \
928 - :0:y/b :0:y/c :0:y/d :0:y/e :0:z/e :0:y/f &&
929 - git rev-parse >expect \
930 - O:z/b O:z/c O:y/d A:y/e A:z/e A:z/f &&
931 - test_cmp expect actual
932 - )
933 -'
934 -
935 -# Testcase 5b, Rename/delete in order to get add/add/add conflict
936 -# (Related to testcase 8d; these may appear slightly inconsistent to users;
937 -# Also related to testcases 7d and 7e)
938 -# Commit O: z/{b,c,d_1}
939 -# Commit A: y/{b,c,d_2}
940 -# Commit B: z/{b,c,d_1,e}, y/d_3
941 -# Expected: y/{b,c,e}, CONFLICT(add/add: y/d_2 vs. y/d_3)
942 -# NOTE: If z/d_1 in commit B were to be involved in dir rename detection, as
943 -# we normaly would since z/ is being renamed to y/, then this would be
944 -# a rename/delete (z/d_1 -> y/d_1 vs. deleted) AND an add/add/add
945 -# conflict of y/d_1 vs. y/d_2 vs. y/d_3. Add/add/add is not
946 -# representable in the index, so the existence of y/d_3 needs to
947 -# cause us to bail on directory rename detection for that path, falling
948 -# back to git behavior without the directory rename detection.
949 -
950 -test_expect_success '5b-setup: Rename/delete in order to get add/add/add conflict' '
951 - test_create_repo 5b &&
952 - (
953 - cd 5b &&
954 -
955 - mkdir z &&
956 - echo b >z/b &&
957 - echo c >z/c &&
958 - echo d1 >z/d &&
959 - git add z &&
960 - test_tick &&
961 - git commit -m "O" &&
962 -
963 - git branch O &&
964 - git branch A &&
965 - git branch B &&
966 -
967 - git checkout A &&
968 - git rm z/d &&
969 - git mv z y &&
970 - echo d2 >y/d &&
971 - git add y/d &&
972 - test_tick &&
973 - git commit -m "A" &&
974 -
975 - git checkout B &&
976 - mkdir y &&
977 - echo d3 >y/d &&
978 - echo e >z/e &&
979 - git add y/d z/e &&
980 - test_tick &&
981 - git commit -m "B"
982 - )
983 -'
984 -
985 -test_expect_success '5b-check: Rename/delete in order to get add/add/add conflict' '
986 - (
987 - cd 5b &&
988 -
989 - git checkout A^0 &&
990 -
991 - test_must_fail git merge -s recursive B^0 >out &&
992 - test_i18ngrep "CONFLICT (add/add).* y/d" out &&
993 -
994 - git ls-files -s >out &&
995 - test_line_count = 5 out &&
996 - git ls-files -u >out &&
997 - test_line_count = 2 out &&
998 - git ls-files -o >out &&
999 - test_line_count = 1 out &&
1000 -
1001 - git rev-parse >actual \
1002 - :0:y/b :0:y/c :0:y/e :2:y/d :3:y/d &&
1003 - git rev-parse >expect \
1004 - O:z/b O:z/c B:z/e A:y/d B:y/d &&
1005 - test_cmp expect actual &&
1006 -
1007 - test_must_fail git rev-parse :1:y/d &&
1008 - test_path_is_file y/d
1009 - )
1010 -'
1011 -
1012 -# Testcase 5c, Transitive rename would cause rename/rename/rename/add/add/add
1013 -# (Directory rename detection would result in transitive rename vs.
1014 -# rename/rename(1to2) and turn it into a rename/rename(1to3). Further,
1015 -# rename paths conflict with separate adds on the other side)
1016 -# (Related to testcases 3b and 7c)
1017 -# Commit O: z/{b,c}, x/d_1
1018 -# Commit A: y/{b,c,d_2}, w/d_1
1019 -# Commit B: z/{b,c,d_1,e}, w/d_3, y/d_4
1020 -# Expected: A mess, but only a rename/rename(1to2)/add/add mess. Use the
1021 -# presence of y/d_4 in B to avoid doing transitive rename of
1022 -# x/d_1 -> z/d_1 -> y/d_1, so that the only paths we have at
1023 -# y/d are y/d_2 and y/d_4. We still do the move from z/e to y/e,
1024 -# though, because it doesn't have anything in the way.
1025 -
1026 -test_expect_success '5c-setup: Transitive rename would cause rename/rename/rename/add/add/add' '
1027 - test_create_repo 5c &&
1028 - (
1029 - cd 5c &&
1030 -
1031 - mkdir z &&
1032 - echo b >z/b &&
1033 - echo c >z/c &&
1034 - mkdir x &&
1035 - echo d1 >x/d &&
1036 - git add z x &&
1037 - test_tick &&
1038 - git commit -m "O" &&
1039 -
1040 - git branch O &&
1041 - git branch A &&
1042 - git branch B &&
1043 -
1044 - git checkout A &&
1045 - git mv z y &&
1046 - echo d2 >y/d &&
1047 - git add y/d &&
1048 - git mv x w &&
1049 - test_tick &&
1050 - git commit -m "A" &&
1051 -
1052 - git checkout B &&
1053 - git mv x/d z/ &&
1054 - mkdir w &&
1055 - mkdir y &&
1056 - echo d3 >w/d &&
1057 - echo d4 >y/d &&
1058 - echo e >z/e &&
1059 - git add w/ y/ z/e &&
1060 - test_tick &&
1061 - git commit -m "B"
1062 - )
1063 -'
1064 -
1065 -test_expect_success '5c-check: Transitive rename would cause rename/rename/rename/add/add/add' '
1066 - (
1067 - cd 5c &&
1068 -
1069 - git checkout A^0 &&
1070 -
1071 - test_must_fail git merge -s recursive B^0 >out &&
1072 - test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&
1073 - test_i18ngrep "CONFLICT (add/add).* y/d" out &&
1074 -
1075 - git ls-files -s >out &&
1076 - test_line_count = 9 out &&
1077 - git ls-files -u >out &&
1078 - test_line_count = 6 out &&
1079 - git ls-files -o >out &&
1080 - test_line_count = 3 out &&
1081 -
1082 - git rev-parse >actual \
1083 - :0:y/b :0:y/c :0:y/e &&
1084 - git rev-parse >expect \
1085 - O:z/b O:z/c B:z/e &&
1086 - test_cmp expect actual &&
1087 -
1088 - test_must_fail git rev-parse :1:y/d &&
1089 - git rev-parse >actual \
1090 - :2:w/d :3:w/d :1:x/d :2:y/d :3:y/d :3:z/d &&
1091 - git rev-parse >expect \
1092 - O:x/d B:w/d O:x/d A:y/d B:y/d O:x/d &&
1093 - test_cmp expect actual &&
1094 -
1095 - git hash-object >actual \
1096 - w/d~HEAD w/d~B^0 z/d &&
1097 - git rev-parse >expect \
1098 - O:x/d B:w/d O:x/d &&
1099 - test_cmp expect actual &&
1100 - test_path_is_missing x/d &&
1101 - test_path_is_file y/d &&
1102 - grep -q "<<<<" y/d # conflict markers should be present
1103 - )
1104 -'
1105 -
1106 -# Testcase 5d, Directory/file/file conflict due to directory rename
1107 -# Commit O: z/{b,c}
1108 -# Commit A: y/{b,c,d_1}
1109 -# Commit B: z/{b,c,d_2,f}, y/d/e
1110 -# Expected: y/{b,c,d/e,f}, z/d_2, CONFLICT(file/directory), y/d_1~HEAD
1111 -# Note: The fact that y/d/ exists in B makes us bail on directory rename
1112 -# detection for z/d_2, but that doesn't prevent us from applying the
1113 -# directory rename detection for z/f -> y/f.
1114 -
1115 -test_expect_success '5d-setup: Directory/file/file conflict due to directory rename' '
1116 - test_create_repo 5d &&
1117 - (
1118 - cd 5d &&
1119 -
1120 - mkdir z &&
1121 - echo b >z/b &&
1122 - echo c >z/c &&
1123 - git add z &&
1124 - test_tick &&
1125 - git commit -m "O" &&
1126 -
1127 - git branch O &&
1128 - git branch A &&
1129 - git branch B &&
1130 -
1131 - git checkout A &&
1132 - git mv z y &&
1133 - echo d1 >y/d &&
1134 - git add y/d &&
1135 - test_tick &&
1136 - git commit -m "A" &&
1137 -
1138 - git checkout B &&
1139 - mkdir -p y/d &&
1140 - echo e >y/d/e &&
1141 - echo d2 >z/d &&
1142 - echo f >z/f &&
1143 - git add y/d/e z/d z/f &&
1144 - test_tick &&
1145 - git commit -m "B"
1146 - )
1147 -'
1148 -
1149 -test_expect_success '5d-check: Directory/file/file conflict due to directory rename' '
1150 - (
1151 - cd 5d &&
1152 -
1153 - git checkout A^0 &&
1154 -
1155 - test_must_fail git merge -s recursive B^0 >out &&
1156 - test_i18ngrep "CONFLICT (file/directory).*y/d" out &&
1157 -
1158 - git ls-files -s >out &&
1159 - test_line_count = 6 out &&
1160 - git ls-files -u >out &&
1161 - test_line_count = 1 out &&
1162 - git ls-files -o >out &&
1163 - test_line_count = 2 out &&
1164 -
1165 - git rev-parse >actual \
1166 - :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d :0:y/d/e &&
1167 - git rev-parse >expect \
1168 - O:z/b O:z/c B:z/d B:z/f A:y/d B:y/d/e &&
1169 - test_cmp expect actual &&
1170 -
1171 - git hash-object y/d~HEAD >actual &&
1172 - git rev-parse A:y/d >expect &&
1173 - test_cmp expect actual
1174 - )
1175 -'
1176 -
1177 -###########################################################################
1178 -# Rules suggested by section 5:
1179 -#
1180 -# If a subset of to-be-renamed files have a file or directory in the way,
1181 -# "turn off" the directory rename for those specific sub-paths, falling
1182 -# back to old handling. But, sadly, see testcases 8a and 8b.
1183 -###########################################################################
1184 -
1185 -
1186 -###########################################################################
1187 -# SECTION 6: Same side of the merge was the one that did the rename
1188 -#
1189 -# It may sound obvious that you only want to apply implicit directory
1190 -# renames to directories if the _other_ side of history did the renaming.
1191 -# If you did make an implementation that didn't explicitly enforce this
1192 -# rule, the majority of cases that would fall under this section would
1193 -# also be solved by following the rules from the above sections. But
1194 -# there are still a few that stick out, so this section covers them just
1195 -# to make sure we also get them right.
1196 -###########################################################################
1197 -
1198 -# Testcase 6a, Tricky rename/delete
1199 -# Commit O: z/{b,c,d}
1200 -# Commit A: z/b
1201 -# Commit B: y/{b,c}, z/d
1202 -# Expected: y/b, CONFLICT(rename/delete, z/c -> y/c vs. NULL)
1203 -# Note: We're just checking here that the rename of z/b and z/c to put
1204 -# them under y/ doesn't accidentally catch z/d and make it look like
1205 -# it is also involved in a rename/delete conflict.
1206 -
1207 -test_expect_success '6a-setup: Tricky rename/delete' '
1208 - test_create_repo 6a &&
1209 - (
1210 - cd 6a &&
1211 -
1212 - mkdir z &&
1213 - echo b >z/b &&
1214 - echo c >z/c &&
1215 - echo d >z/d &&
1216 - git add z &&
1217 - test_tick &&
1218 - git commit -m "O" &&
1219 -
1220 - git branch O &&
1221 - git branch A &&
1222 - git branch B &&
1223 -
1224 - git checkout A &&
1225 - git rm z/c &&
1226 - git rm z/d &&
1227 - test_tick &&
1228 - git commit -m "A" &&
1229 -
1230 - git checkout B &&
1231 - mkdir y &&
1232 - git mv z/b y/ &&
1233 - git mv z/c y/ &&
1234 - test_tick &&
1235 - git commit -m "B"
1236 - )
1237 -'
1238 -
1239 -test_expect_success '6a-check: Tricky rename/delete' '
1240 - (
1241 - cd 6a &&
1242 -
1243 - git checkout A^0 &&
1244 -
1245 - test_must_fail git merge -s recursive B^0 >out &&
1246 - test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&
1247 -
1248 - git ls-files -s >out &&
1249 - test_line_count = 2 out &&
1250 - git ls-files -u >out &&
1251 - test_line_count = 1 out &&
1252 - git ls-files -o >out &&
1253 - test_line_count = 1 out &&
1254 -
1255 - git rev-parse >actual \
1256 - :0:y/b :3:y/c &&
1257 - git rev-parse >expect \
1258 - O:z/b O:z/c &&
1259 - test_cmp expect actual
1260 - )
1261 -'
1262 -
1263 -# Testcase 6b, Same rename done on both sides
1264 -# (Related to testcases 6c and 8e)
1265 -# Commit O: z/{b,c}
1266 -# Commit A: y/{b,c}
1267 -# Commit B: y/{b,c}, z/d
1268 -# Expected: y/{b,c}, z/d
1269 -# Note: If we did directory rename detection here, we'd move z/d into y/,
1270 -# but B did that rename and still decided to put the file into z/,
1271 -# so we probably shouldn't apply directory rename detection for it.
1272 -
1273 -test_expect_success '6b-setup: Same rename done on both sides' '
1274 - test_create_repo 6b &&
1275 - (
1276 - cd 6b &&
1277 -
1278 - mkdir z &&
1279 - echo b >z/b &&
1280 - echo c >z/c &&
1281 - git add z &&
1282 - test_tick &&
1283 - git commit -m "O" &&
1284 -
1285 - git branch O &&
1286 - git branch A &&
1287 - git branch B &&
1288 -
1289 - git checkout A &&
1290 - git mv z y &&
1291 - test_tick &&
1292 - git commit -m "A" &&
1293 -
1294 - git checkout B &&
1295 - git mv z y &&
1296 - mkdir z &&
1297 - echo d >z/d &&
1298 - git add z/d &&
1299 - test_tick &&
1300 - git commit -m "B"
1301 - )
1302 -'
1303 -
1304 -test_expect_success '6b-check: Same rename done on both sides' '
1305 - (
1306 - cd 6b &&
1307 -
1308 - git checkout A^0 &&
1309 -
1310 - git merge -s recursive B^0 &&
1311 -
1312 - git ls-files -s >out &&
1313 - test_line_count = 3 out &&
1314 - git ls-files -u >out &&
1315 - test_line_count = 0 out &&
1316 - git ls-files -o >out &&
1317 - test_line_count = 1 out &&
1318 -
1319 - git rev-parse >actual \
1320 - HEAD:y/b HEAD:y/c HEAD:z/d &&
1321 - git rev-parse >expect \
1322 - O:z/b O:z/c B:z/d &&
1323 - test_cmp expect actual
1324 - )
1325 -'
1326 -
1327 -# Testcase 6c, Rename only done on same side
1328 -# (Related to testcases 6b and 8e)
1329 -# Commit O: z/{b,c}
1330 -# Commit A: z/{b,c} (no change)
1331 -# Commit B: y/{b,c}, z/d
1332 -# Expected: y/{b,c}, z/d
1333 -# NOTE: Seems obvious, but just checking that the implementation doesn't
1334 -# "accidentally detect a rename" and give us y/{b,c,d}.
1335 -
1336 -test_expect_success '6c-setup: Rename only done on same side' '
1337 - test_create_repo 6c &&
1338 - (
1339 - cd 6c &&
1340 -
1341 - mkdir z &&
1342 - echo b >z/b &&
1343 - echo c >z/c &&
1344 - git add z &&
1345 - test_tick &&
1346 - git commit -m "O" &&
1347 -
1348 - git branch O &&
1349 - git branch A &&
1350 - git branch B &&
1351 -
1352 - git checkout A &&
1353 - test_tick &&
1354 - git commit --allow-empty -m "A" &&
1355 -
1356 - git checkout B &&
1357 - git mv z y &&
1358 - mkdir z &&
1359 - echo d >z/d &&
1360 - git add z/d &&
1361 - test_tick &&
1362 - git commit -m "B"
1363 - )
1364 -'
1365 -
1366 -test_expect_success '6c-check: Rename only done on same side' '
1367 - (
1368 - cd 6c &&
1369 -
1370 - git checkout A^0 &&
1371 -
1372 - git merge -s recursive B^0 &&
1373 -
1374 - git ls-files -s >out &&
1375 - test_line_count = 3 out &&
1376 - git ls-files -u >out &&
1377 - test_line_count = 0 out &&
1378 - git ls-files -o >out &&
1379 - test_line_count = 1 out &&
1380 -
1381 - git rev-parse >actual \
1382 - HEAD:y/b HEAD:y/c HEAD:z/d &&
1383 - git rev-parse >expect \
1384 - O:z/b O:z/c B:z/d &&
1385 - test_cmp expect actual
1386 - )
1387 -'
1388 -
1389 -# Testcase 6d, We don't always want transitive renaming
1390 -# (Related to testcase 1c)
1391 -# Commit O: z/{b,c}, x/d
1392 -# Commit A: z/{b,c}, x/d (no change)
1393 -# Commit B: y/{b,c}, z/d
1394 -# Expected: y/{b,c}, z/d
1395 -# NOTE: Again, this seems obvious but just checking that the implementation
1396 -# doesn't "accidentally detect a rename" and give us y/{b,c,d}.
1397 -
1398 -test_expect_success '6d-setup: We do not always want transitive renaming' '
1399 - test_create_repo 6d &&
1400 - (
1401 - cd 6d &&
1402 -
1403 - mkdir z &&
1404 - echo b >z/b &&
1405 - echo c >z/c &&
1406 - mkdir x &&
1407 - echo d >x/d &&
1408 - git add z x &&
1409 - test_tick &&
1410 - git commit -m "O" &&
1411 -
1412 - git branch O &&
1413 - git branch A &&
1414 - git branch B &&
1415 -
1416 - git checkout A &&
1417 - test_tick &&
1418 - git commit --allow-empty -m "A" &&
1419 -
1420 - git checkout B &&
1421 - git mv z y &&
1422 - git mv x z &&
1423 - test_tick &&
1424 - git commit -m "B"
1425 - )
1426 -'
1427 -
1428 -test_expect_success '6d-check: We do not always want transitive renaming' '
1429 - (
1430 - cd 6d &&
1431 -
1432 - git checkout A^0 &&
1433 -
1434 - git merge -s recursive B^0 &&
1435 -
1436 - git ls-files -s >out &&
1437 - test_line_count = 3 out &&
1438 - git ls-files -u >out &&
1439 - test_line_count = 0 out &&
1440 - git ls-files -o >out &&
1441 - test_line_count = 1 out &&
1442 -
1443 - git rev-parse >actual \
1444 - HEAD:y/b HEAD:y/c HEAD:z/d &&
1445 - git rev-parse >expect \
1446 - O:z/b O:z/c O:x/d &&
1447 - test_cmp expect actual
1448 - )
1449 -'
1450 -
1451 -# Testcase 6e, Add/add from one-side
1452 -# Commit O: z/{b,c}
1453 -# Commit A: z/{b,c} (no change)
1454 -# Commit B: y/{b,c,d_1}, z/d_2
1455 -# Expected: y/{b,c,d_1}, z/d_2
1456 -# NOTE: Again, this seems obvious but just checking that the implementation
1457 -# doesn't "accidentally detect a rename" and give us y/{b,c} +
1458 -# add/add conflict on y/d_1 vs y/d_2.
1459 -
1460 -test_expect_success '6e-setup: Add/add from one side' '
1461 - test_create_repo 6e &&
1462 - (
1463 - cd 6e &&
1464 -
1465 - mkdir z &&
1466 - echo b >z/b &&
1467 - echo c >z/c &&
1468 - git add z &&
1469 - test_tick &&
1470 - git commit -m "O" &&
1471 -
1472 - git branch O &&
1473 - git branch A &&
1474 - git branch B &&
1475 -
1476 - git checkout A &&
1477 - test_tick &&
1478 - git commit --allow-empty -m "A" &&
1479 -
1480 - git checkout B &&
1481 - git mv z y &&
1482 - echo d1 > y/d &&
1483 - mkdir z &&
1484 - echo d2 > z/d &&
1485 - git add y/d z/d &&
1486 - test_tick &&
1487 - git commit -m "B"
1488 - )
1489 -'
1490 -
1491 -test_expect_success '6e-check: Add/add from one side' '
1492 - (
1493 - cd 6e &&
1494 -
1495 - git checkout A^0 &&
1496 -
1497 - git merge -s recursive B^0 &&
1498 -
1499 - git ls-files -s >out &&
1500 - test_line_count = 4 out &&
1501 - git ls-files -u >out &&
1502 - test_line_count = 0 out &&
1503 - git ls-files -o >out &&
1504 - test_line_count = 1 out &&
1505 -
1506 - git rev-parse >actual \
1507 - HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/d &&
1508 - git rev-parse >expect \
1509 - O:z/b O:z/c B:y/d B:z/d &&
1510 - test_cmp expect actual
1511 - )
1512 -'
1513 -
1514 -###########################################################################
1515 -# Rules suggested by section 6:
1516 -#
1517 -# Only apply implicit directory renames to directories if the other
1518 -# side of history is the one doing the renaming.
1519 -###########################################################################
1520 -
1521 -
1522 -###########################################################################
1523 -# SECTION 7: More involved Edge/Corner cases
1524 -#
1525 -# The ruleset we have generated in the above sections seems to provide
1526 -# well-defined merges. But can we find edge/corner cases that either (a)
1527 -# are harder for users to understand, or (b) have a resolution that is
1528 -# non-intuitive or suboptimal?
1529 -#
1530 -# The testcases in this section dive into cases that I've tried to craft in
1531 -# a way to find some that might be surprising to users or difficult for
1532 -# them to understand (the next section will look at non-intuitive or
1533 -# suboptimal merge results). Some of the testcases are similar to ones
1534 -# from past sections, but have been simplified to try to highlight error
1535 -# messages using a "modified" path (due to the directory rename). Are
1536 -# users okay with these?
1537 -#
1538 -# In my opinion, testcases that are difficult to understand from this
1539 -# section is due to difficulty in the testcase rather than the directory
1540 -# renaming (similar to how t6042 and t6036 have difficult resolutions due
1541 -# to the problem setup itself being complex). And I don't think the
1542 -# error messages are a problem.
1543 -#
1544 -# On the other hand, the testcases in section 8 worry me slightly more...
1545 -###########################################################################
1546 -
1547 -# Testcase 7a, rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file
1548 -# Commit O: z/{b,c}
1549 -# Commit A: y/{b,c}
1550 -# Commit B: w/b, x/c, z/d
1551 -# Expected: y/d, CONFLICT(rename/rename for both z/b and z/c)
1552 -# NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.
1553 -
1554 -test_expect_success '7a-setup: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1555 - test_create_repo 7a &&
1556 - (
1557 - cd 7a &&
1558 -
1559 - mkdir z &&
1560 - echo b >z/b &&
1561 - echo c >z/c &&
1562 - git add z &&
1563 - test_tick &&
1564 - git commit -m "O" &&
1565 -
1566 - git branch O &&
1567 - git branch A &&
1568 - git branch B &&
1569 -
1570 - git checkout A &&
1571 - git mv z y &&
1572 - test_tick &&
1573 - git commit -m "A" &&
1574 -
1575 - git checkout B &&
1576 - mkdir w &&
1577 - mkdir x &&
1578 - git mv z/b w/ &&
1579 - git mv z/c x/ &&
1580 - echo d > z/d &&
1581 - git add z/d &&
1582 - test_tick &&
1583 - git commit -m "B"
1584 - )
1585 -'
1586 -
1587 -test_expect_success '7a-check: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1588 - (
1589 - cd 7a &&
1590 -
1591 - git checkout A^0 &&
1592 -
1593 - test_must_fail git merge -s recursive B^0 >out &&
1594 - test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
1595 - test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
1596 -
1597 - git ls-files -s >out &&
1598 - test_line_count = 7 out &&
1599 - git ls-files -u >out &&
1600 - test_line_count = 6 out &&
1601 - git ls-files -o >out &&
1602 - test_line_count = 1 out &&
1603 -
1604 - git rev-parse >actual \
1605 - :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:x/c :0:y/d &&
1606 - git rev-parse >expect \
1607 - O:z/b O:z/b O:z/b O:z/c O:z/c O:z/c B:z/d &&
1608 - test_cmp expect actual &&
1609 -
1610 - git hash-object >actual \
1611 - y/b w/b y/c x/c &&
1612 - git rev-parse >expect \
1613 - O:z/b O:z/b O:z/c O:z/c &&
1614 - test_cmp expect actual
1615 - )
1616 -'
1617 -
1618 -# Testcase 7b, rename/rename(2to1), but only due to transitive rename
1619 -# (Related to testcase 1d)
1620 -# Commit O: z/{b,c}, x/d_1, w/d_2
1621 -# Commit A: y/{b,c,d_2}, x/d_1
1622 -# Commit B: z/{b,c,d_1}, w/d_2
1623 -# Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)
1624 -
1625 -test_expect_success '7b-setup: rename/rename(2to1), but only due to transitive rename' '
1626 - test_create_repo 7b &&
1627 - (
1628 - cd 7b &&
1629 -
1630 - mkdir z &&
1631 - mkdir x &&
1632 - mkdir w &&
1633 - echo b >z/b &&
1634 - echo c >z/c &&
1635 - echo d1 > x/d &&
1636 - echo d2 > w/d &&
1637 - git add z x w &&
1638 - test_tick &&
1639 - git commit -m "O" &&
1640 -
1641 - git branch O &&
1642 - git branch A &&
1643 - git branch B &&
1644 -
1645 - git checkout A &&
1646 - git mv z y &&
1647 - git mv w/d y/ &&
1648 - test_tick &&
1649 - git commit -m "A" &&
1650 -
1651 - git checkout B &&
1652 - git mv x/d z/ &&
1653 - rmdir x &&
1654 - test_tick &&
1655 - git commit -m "B"
1656 - )
1657 -'
1658 -
1659 -test_expect_success '7b-check: rename/rename(2to1), but only due to transitive rename' '
1660 - (
1661 - cd 7b &&
1662 -
1663 - git checkout A^0 &&
1664 -
1665 - test_must_fail git merge -s recursive B^0 >out &&
1666 - test_i18ngrep "CONFLICT (rename/rename)" out &&
1667 -
1668 - git ls-files -s >out &&
1669 - test_line_count = 4 out &&
1670 - git ls-files -u >out &&
1671 - test_line_count = 2 out &&
1672 - git ls-files -o >out &&
1673 - test_line_count = 3 out &&
1674 -
1675 - git rev-parse >actual \
1676 - :0:y/b :0:y/c :2:y/d :3:y/d &&
1677 - git rev-parse >expect \
1678 - O:z/b O:z/c O:w/d O:x/d &&
1679 - test_cmp expect actual &&
1680 -
1681 - test_path_is_missing y/d &&
1682 - test_path_is_file y/d~HEAD &&
1683 - test_path_is_file y/d~B^0 &&
1684 -
1685 - git hash-object >actual \
1686 - y/d~HEAD y/d~B^0 &&
1687 - git rev-parse >expect \
1688 - O:w/d O:x/d &&
1689 - test_cmp expect actual
1690 - )
1691 -'
1692 -
1693 -# Testcase 7c, rename/rename(1to...2or3); transitive rename may add complexity
1694 -# (Related to testcases 3b and 5c)
1695 -# Commit O: z/{b,c}, x/d
1696 -# Commit A: y/{b,c}, w/d
1697 -# Commit B: z/{b,c,d}
1698 -# Expected: y/{b,c}, CONFLICT(x/d -> w/d vs. y/d)
1699 -# NOTE: z/ was renamed to y/ so we do want to report
1700 -# neither CONFLICT(x/d -> w/d vs. z/d)
1701 -# nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)
1702 -
1703 -test_expect_success '7c-setup: rename/rename(1to...2or3); transitive rename may add complexity' '
1704 - test_create_repo 7c &&
1705 - (
1706 - cd 7c &&
1707 -
1708 - mkdir z &&
1709 - echo b >z/b &&
1710 - echo c >z/c &&
1711 - mkdir x &&
1712 - echo d >x/d &&
1713 - git add z x &&
1714 - test_tick &&
1715 - git commit -m "O" &&
1716 -
1717 - git branch O &&
1718 - git branch A &&
1719 - git branch B &&
1720 -
1721 - git checkout A &&
1722 - git mv z y &&
1723 - git mv x w &&
1724 - test_tick &&
1725 - git commit -m "A" &&
1726 -
1727 - git checkout B &&
1728 - git mv x/d z/ &&
1729 - rmdir x &&
1730 - test_tick &&
1731 - git commit -m "B"
1732 - )
1733 -'
1734 -
1735 -test_expect_success '7c-check: rename/rename(1to...2or3); transitive rename may add complexity' '
1736 - (
1737 - cd 7c &&
1738 -
1739 - git checkout A^0 &&
1740 -
1741 - test_must_fail git merge -s recursive B^0 >out &&
1742 - test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
1743 -
1744 - git ls-files -s >out &&
1745 - test_line_count = 5 out &&
1746 - git ls-files -u >out &&
1747 - test_line_count = 3 out &&
1748 - git ls-files -o >out &&
1749 - test_line_count = 1 out &&
1750 -
1751 - git rev-parse >actual \
1752 - :0:y/b :0:y/c :1:x/d :2:w/d :3:y/d &&
1753 - git rev-parse >expect \
1754 - O:z/b O:z/c O:x/d O:x/d O:x/d &&
1755 - test_cmp expect actual
1756 - )
1757 -'
1758 -
1759 -# Testcase 7d, transitive rename involved in rename/delete; how is it reported?
1760 -# (Related somewhat to testcases 5b and 8d)
1761 -# Commit O: z/{b,c}, x/d
1762 -# Commit A: y/{b,c}
1763 -# Commit B: z/{b,c,d}
1764 -# Expected: y/{b,c}, CONFLICT(delete x/d vs rename to y/d)
1765 -# NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)
1766 -
1767 -test_expect_success '7d-setup: transitive rename involved in rename/delete; how is it reported?' '
1768 - test_create_repo 7d &&
1769 - (
1770 - cd 7d &&
1771 -
1772 - mkdir z &&
1773 - echo b >z/b &&
1774 - echo c >z/c &&
1775 - mkdir x &&
1776 - echo d >x/d &&
1777 - git add z x &&
1778 - test_tick &&
1779 - git commit -m "O" &&
1780 -
1781 - git branch O &&
1782 - git branch A &&
1783 - git branch B &&
1784 -
1785 - git checkout A &&
1786 - git mv z y &&
1787 - git rm -rf x &&
1788 - test_tick &&
1789 - git commit -m "A" &&
1790 -
1791 - git checkout B &&
1792 - git mv x/d z/ &&
1793 - rmdir x &&
1794 - test_tick &&
1795 - git commit -m "B"
1796 - )
1797 -'
1798 -
1799 -test_expect_success '7d-check: transitive rename involved in rename/delete; how is it reported?' '
1800 - (
1801 - cd 7d &&
1802 -
1803 - git checkout A^0 &&
1804 -
1805 - test_must_fail git merge -s recursive B^0 >out &&
1806 - test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1807 -
1808 - git ls-files -s >out &&
1809 - test_line_count = 3 out &&
1810 - git ls-files -u >out &&
1811 - test_line_count = 1 out &&
1812 - git ls-files -o >out &&
1813 - test_line_count = 1 out &&
1814 -
1815 - git rev-parse >actual \
1816 - :0:y/b :0:y/c :3:y/d &&
1817 - git rev-parse >expect \
1818 - O:z/b O:z/c O:x/d &&
1819 - test_cmp expect actual
1820 - )
1821 -'
1822 -
1823 -# Testcase 7e, transitive rename in rename/delete AND dirs in the way
1824 -# (Very similar to 'both rename source and destination involved in D/F conflict' from t6022-merge-rename.sh)
1825 -# (Also related to testcases 9c and 9d)
1826 -# Commit O: z/{b,c}, x/d_1
1827 -# Commit A: y/{b,c,d/g}, x/d/f
1828 -# Commit B: z/{b,c,d_1}
1829 -# Expected: rename/delete(x/d_1->y/d_1 vs. None) + D/F conflict on y/d
1830 -# y/{b,c,d/g}, y/d_1~B^0, x/d/f
1831 -
1832 -# NOTE: The main path of interest here is d_1 and where it ends up, but
1833 -# this is actually a case that has two potential directory renames
1834 -# involved and D/F conflict(s), so it makes sense to walk through
1835 -# each step.
1836 -#
1837 -# Commit A renames z/ -> y/. Thus everything that B adds to z/
1838 -# should be instead moved to y/. This gives us the D/F conflict on
1839 -# y/d because x/d_1 -> z/d_1 -> y/d_1 conflicts with y/d/g.
1840 -#
1841 -# Further, commit B renames x/ -> z/, thus everything A adds to x/
1842 -# should instead be moved to z/...BUT we removed z/ and renamed it
1843 -# to y/, so maybe everything should move not from x/ to z/, but
1844 -# from x/ to z/ to y/. Doing so might make sense from the logic so
1845 -# far, but note that commit A had both an x/ and a y/; it did the
1846 -# renaming of z/ to y/ and created x/d/f and it clearly made these
1847 -# things separate, so it doesn't make much sense to push these
1848 -# together. Doing so is what I'd call a doubly transitive rename;
1849 -# see testcases 9c and 9d for further discussion of this issue and
1850 -# how it's resolved.
1851 -
1852 -test_expect_success '7e-setup: transitive rename in rename/delete AND dirs in the way' '
1853 - test_create_repo 7e &&
1854 - (
1855 - cd 7e &&
1856 -
1857 - mkdir z &&
1858 - echo b >z/b &&
1859 - echo c >z/c &&
1860 - mkdir x &&
1861 - echo d1 >x/d &&
1862 - git add z x &&
1863 - test_tick &&
1864 - git commit -m "O" &&
1865 -
1866 - git branch O &&
1867 - git branch A &&
1868 - git branch B &&
1869 -
1870 - git checkout A &&
1871 - git mv z y &&
1872 - git rm x/d &&
1873 - mkdir -p x/d &&
1874 - mkdir -p y/d &&
1875 - echo f >x/d/f &&
1876 - echo g >y/d/g &&
1877 - git add x/d/f y/d/g &&
1878 - test_tick &&
1879 - git commit -m "A" &&
1880 -
1881 - git checkout B &&
1882 - git mv x/d z/ &&
1883 - rmdir x &&
1884 - test_tick &&
1885 - git commit -m "B"
1886 - )
1887 -'
1888 -
1889 -test_expect_success '7e-check: transitive rename in rename/delete AND dirs in the way' '
1890 - (
1891 - cd 7e &&
1892 -
1893 - git checkout A^0 &&
1894 -
1895 - test_must_fail git merge -s recursive B^0 >out &&
1896 - test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1897 -
1898 - git ls-files -s >out &&
1899 - test_line_count = 5 out &&
1900 - git ls-files -u >out &&
1901 - test_line_count = 1 out &&
1902 - git ls-files -o >out &&
1903 - test_line_count = 2 out &&
1904 -
1905 - git rev-parse >actual \
1906 - :0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&
1907 - git rev-parse >expect \
1908 - A:x/d/f A:y/d/g O:z/b O:z/c O:x/d &&
1909 - test_cmp expect actual &&
1910 -
1911 - git hash-object y/d~B^0 >actual &&
1912 - git rev-parse O:x/d >expect &&
1913 - test_cmp expect actual
1914 - )
1915 -'
1916 -
1917 -###########################################################################
1918 -# SECTION 8: Suboptimal merges
1919 -#
1920 -# As alluded to in the last section, the ruleset we have built up for
1921 -# detecting directory renames unfortunately has some special cases where it
1922 -# results in slightly suboptimal or non-intuitive behavior. This section
1923 -# explores these cases.
1924 -#
1925 -# To be fair, we already had non-intuitive or suboptimal behavior for most
1926 -# of these cases in git before introducing implicit directory rename
1927 -# detection, but it'd be nice if there was a modified ruleset out there
1928 -# that handled these cases a bit better.
1929 -###########################################################################
1930 -
1931 -# Testcase 8a, Dual-directory rename, one into the others' way
1932 -# Commit O. x/{a,b}, y/{c,d}
1933 -# Commit A. x/{a,b,e}, y/{c,d,f}
1934 -# Commit B. y/{a,b}, z/{c,d}
1935 -#
1936 -# Possible Resolutions:
1937 -# w/o dir-rename detection: y/{a,b,f}, z/{c,d}, x/e
1938 -# Currently expected: y/{a,b,e,f}, z/{c,d}
1939 -# Optimal: y/{a,b,e}, z/{c,d,f}
1940 -#
1941 -# Note: Both x and y got renamed and it'd be nice to detect both, and we do
1942 -# better with directory rename detection than git did without, but the
1943 -# simple rule from section 5 prevents me from handling this as optimally as
1944 -# we potentially could.
1945 -
1946 -test_expect_success '8a-setup: Dual-directory rename, one into the others way' '
1947 - test_create_repo 8a &&
1948 - (
1949 - cd 8a &&
1950 -
1951 - mkdir x &&
1952 - mkdir y &&
1953 - echo a >x/a &&
1954 - echo b >x/b &&
1955 - echo c >y/c &&
1956 - echo d >y/d &&
1957 - git add x y &&
1958 - test_tick &&
1959 - git commit -m "O" &&
1960 -
1961 - git branch O &&
1962 - git branch A &&
1963 - git branch B &&
1964 -
1965 - git checkout A &&
1966 - echo e >x/e &&
1967 - echo f >y/f &&
1968 - git add x/e y/f &&
1969 - test_tick &&
1970 - git commit -m "A" &&
1971 -
1972 - git checkout B &&
1973 - git mv y z &&
1974 - git mv x y &&
1975 - test_tick &&
1976 - git commit -m "B"
1977 - )
1978 -'
1979 -
1980 -test_expect_success '8a-check: Dual-directory rename, one into the others way' '
1981 - (
1982 - cd 8a &&
1983 -
1984 - git checkout A^0 &&
1985 -
1986 - git merge -s recursive B^0 &&
1987 -
1988 - git ls-files -s >out &&
1989 - test_line_count = 6 out &&
1990 - git ls-files -u >out &&
1991 - test_line_count = 0 out &&
1992 - git ls-files -o >out &&
1993 - test_line_count = 1 out &&
1994 -
1995 - git rev-parse >actual \
1996 - HEAD:y/a HEAD:y/b HEAD:y/e HEAD:y/f HEAD:z/c HEAD:z/d &&
1997 - git rev-parse >expect \
1998 - O:x/a O:x/b A:x/e A:y/f O:y/c O:y/d &&
1999 - test_cmp expect actual
2000 - )
2001 -'
2002 -
2003 -# Testcase 8b, Dual-directory rename, one into the others' way, with conflicting filenames
2004 -# Commit O. x/{a_1,b_1}, y/{a_2,b_2}
2005 -# Commit A. x/{a_1,b_1,e_1}, y/{a_2,b_2,e_2}
2006 -# Commit B. y/{a_1,b_1}, z/{a_2,b_2}
2007 -#
2008 -# w/o dir-rename detection: y/{a_1,b_1,e_2}, z/{a_2,b_2}, x/e_1
2009 -# Currently expected: <same>
2010 -# Scary: y/{a_1,b_1}, z/{a_2,b_2}, CONFLICT(add/add, e_1 vs. e_2)
2011 -# Optimal: y/{a_1,b_1,e_1}, z/{a_2,b_2,e_2}
2012 -#
2013 -# Note: Very similar to 8a, except instead of 'e' and 'f' in directories x and
2014 -# y, both are named 'e'. Without directory rename detection, neither file
2015 -# moves directories. Implement directory rename detection suboptimally, and
2016 -# you get an add/add conflict, but both files were added in commit A, so this
2017 -# is an add/add conflict where one side of history added both files --
2018 -# something we can't represent in the index. Obviously, we'd prefer the last
2019 -# resolution, but our previous rules are too coarse to allow it. Using both
2020 -# the rules from section 4 and section 5 save us from the Scary resolution,
2021 -# making us fall back to pre-directory-rename-detection behavior for both
2022 -# e_1 and e_2.
2023 -
2024 -test_expect_success '8b-setup: Dual-directory rename, one into the others way, with conflicting filenames' '
2025 - test_create_repo 8b &&
2026 - (
2027 - cd 8b &&
2028 -
2029 - mkdir x &&
2030 - mkdir y &&
2031 - echo a1 >x/a &&
2032 - echo b1 >x/b &&
2033 - echo a2 >y/a &&
2034 - echo b2 >y/b &&
2035 - git add x y &&
2036 - test_tick &&
2037 - git commit -m "O" &&
2038 -
2039 - git branch O &&
2040 - git branch A &&
2041 - git branch B &&
2042 -
2043 - git checkout A &&
2044 - echo e1 >x/e &&
2045 - echo e2 >y/e &&
2046 - git add x/e y/e &&
2047 - test_tick &&
2048 - git commit -m "A" &&
2049 -
2050 - git checkout B &&
2051 - git mv y z &&
2052 - git mv x y &&
2053 - test_tick &&
2054 - git commit -m "B"
2055 - )
2056 -'
2057 -
2058 -test_expect_success '8b-check: Dual-directory rename, one into the others way, with conflicting filenames' '
2059 - (
2060 - cd 8b &&
2061 -
2062 - git checkout A^0 &&
2063 -
2064 - git merge -s recursive B^0 &&
2065 -
2066 - git ls-files -s >out &&
2067 - test_line_count = 6 out &&
2068 - git ls-files -u >out &&
2069 - test_line_count = 0 out &&
2070 - git ls-files -o >out &&
2071 - test_line_count = 1 out &&
2072 -
2073 - git rev-parse >actual \
2074 - HEAD:y/a HEAD:y/b HEAD:z/a HEAD:z/b HEAD:x/e HEAD:y/e &&
2075 - git rev-parse >expect \
2076 - O:x/a O:x/b O:y/a O:y/b A:x/e A:y/e &&
2077 - test_cmp expect actual
2078 - )
2079 -'
2080 -
2081 -# Testcase 8c, modify/delete or rename+modify/delete?
2082 -# (Related to testcases 5b, 8d, and 9h)
2083 -# Commit O: z/{b,c,d}
2084 -# Commit A: y/{b,c}
2085 -# Commit B: z/{b,c,d_modified,e}
2086 -# Expected: y/{b,c,e}, CONFLICT(modify/delete: on z/d)
2087 -#
2088 -# Note: It could easily be argued that the correct resolution here is
2089 -# y/{b,c,e}, CONFLICT(rename/delete: z/d -> y/d vs deleted)
2090 -# and that the modifed version of d should be present in y/ after
2091 -# the merge, just marked as conflicted. Indeed, I previously did
2092 -# argue that. But applying directory renames to the side of
2093 -# history where a file is merely modified results in spurious
2094 -# rename/rename(1to2) conflicts -- see testcase 9h. See also
2095 -# notes in 8d.
2096 -
2097 -test_expect_success '8c-setup: modify/delete or rename+modify/delete?' '
2098 - test_create_repo 8c &&
2099 - (
2100 - cd 8c &&
2101 -
2102 - mkdir z &&
2103 - echo b >z/b &&
2104 - echo c >z/c &&
2105 - test_seq 1 10 >z/d &&
2106 - git add z &&
2107 - test_tick &&
2108 - git commit -m "O" &&
2109 -
2110 - git branch O &&
2111 - git branch A &&
2112 - git branch B &&
2113 -
2114 - git checkout A &&
2115 - git rm z/d &&
2116 - git mv z y &&
2117 - test_tick &&
2118 - git commit -m "A" &&
2119 -
2120 - git checkout B &&
2121 - echo 11 >z/d &&
2122 - test_chmod +x z/d &&
2123 - echo e >z/e &&
2124 - git add z/d z/e &&
2125 - test_tick &&
2126 - git commit -m "B"
2127 - )
2128 -'
2129 -
2130 -test_expect_success '8c-check: modify/delete or rename+modify/delete' '
2131 - (
2132 - cd 8c &&
2133 -
2134 - git checkout A^0 &&
2135 -
2136 - test_must_fail git merge -s recursive B^0 >out &&
2137 - test_i18ngrep "CONFLICT (modify/delete).* z/d" out &&
2138 -
2139 - git ls-files -s >out &&
2140 - test_line_count = 5 out &&
2141 - git ls-files -u >out &&
2142 - test_line_count = 2 out &&
2143 - git ls-files -o >out &&
2144 - test_line_count = 1 out &&
2145 -
2146 - git rev-parse >actual \
2147 - :0:y/b :0:y/c :0:y/e :1:z/d :3:z/d &&
2148 - git rev-parse >expect \
2149 - O:z/b O:z/c B:z/e O:z/d B:z/d &&
2150 - test_cmp expect actual &&
2151 -
2152 - test_must_fail git rev-parse :2:z/d &&
2153 - git ls-files -s z/d | grep ^100755 &&
2154 - test_path_is_file z/d &&
2155 - test_path_is_missing y/d
2156 - )
2157 -'
2158 -
2159 -# Testcase 8d, rename/delete...or not?
2160 -# (Related to testcase 5b; these may appear slightly inconsistent to users;
2161 -# Also related to testcases 7d and 7e)
2162 -# Commit O: z/{b,c,d}
2163 -# Commit A: y/{b,c}
2164 -# Commit B: z/{b,c,d,e}
2165 -# Expected: y/{b,c,e}
2166 -#
2167 -# Note: It would also be somewhat reasonable to resolve this as
2168 -# y/{b,c,e}, CONFLICT(rename/delete: x/d -> y/d or deleted)
2169 -#
2170 -# In this case, I'm leaning towards: commit A was the one that deleted z/d
2171 -# and it did the rename of z to y, so the two "conflicts" (rename vs.
2172 -# delete) are both coming from commit A, which is illogical. Conflicts
2173 -# during merging are supposed to be about opposite sides doing things
2174 -# differently.
2175 -
2176 -test_expect_success '8d-setup: rename/delete...or not?' '
2177 - test_create_repo 8d &&
2178 - (
2179 - cd 8d &&
2180 -
2181 - mkdir z &&
2182 - echo b >z/b &&
2183 - echo c >z/c &&
2184 - test_seq 1 10 >z/d &&
2185 - git add z &&
2186 - test_tick &&
2187 - git commit -m "O" &&
2188 -
2189 - git branch O &&
2190 - git branch A &&
2191 - git branch B &&
2192 -
2193 - git checkout A &&
2194 - git rm z/d &&
2195 - git mv z y &&
2196 - test_tick &&
2197 - git commit -m "A" &&
2198 -
2199 - git checkout B &&
2200 - echo e >z/e &&
2201 - git add z/e &&
2202 - test_tick &&
2203 - git commit -m "B"
2204 - )
2205 -'
2206 -
2207 -test_expect_success '8d-check: rename/delete...or not?' '
2208 - (
2209 - cd 8d &&
2210 -
2211 - git checkout A^0 &&
2212 -
2213 - git merge -s recursive B^0 &&
2214 -
2215 - git ls-files -s >out &&
2216 - test_line_count = 3 out &&
2217 -
2218 - git rev-parse >actual \
2219 - HEAD:y/b HEAD:y/c HEAD:y/e &&
2220 - git rev-parse >expect \
2221 - O:z/b O:z/c B:z/e &&
2222 - test_cmp expect actual
2223 - )
2224 -'
2225 -
2226 -# Testcase 8e, Both sides rename, one side adds to original directory
2227 -# Commit O: z/{b,c}
2228 -# Commit A: y/{b,c}
2229 -# Commit B: w/{b,c}, z/d
2230 -#
2231 -# Possible Resolutions:
2232 -# w/o dir-rename detection: z/d, CONFLICT(z/b -> y/b vs. w/b),
2233 -# CONFLICT(z/c -> y/c vs. w/c)
2234 -# Currently expected: y/d, CONFLICT(z/b -> y/b vs. w/b),
2235 -# CONFLICT(z/c -> y/c vs. w/c)
2236 -# Optimal: ??
2237 -#
2238 -# Notes: In commit A, directory z got renamed to y. In commit B, directory z
2239 -# did NOT get renamed; the directory is still present; instead it is
2240 -# considered to have just renamed a subset of paths in directory z
2241 -# elsewhere. Therefore, the directory rename done in commit A to z/
2242 -# applies to z/d and maps it to y/d.
2243 -#
2244 -# It's possible that users would get confused about this, but what
2245 -# should we do instead? Silently leaving at z/d seems just as bad or
2246 -# maybe even worse. Perhaps we could print a big warning about z/d
2247 -# and how we're moving to y/d in this case, but when I started thinking
2248 -# about the ramifications of doing that, I didn't know how to rule out
2249 -# that opening other weird edge and corner cases so I just punted.
2250 -
2251 -test_expect_success '8e-setup: Both sides rename, one side adds to original directory' '
2252 - test_create_repo 8e &&
2253 - (
2254 - cd 8e &&
2255 -
2256 - mkdir z &&
2257 - echo b >z/b &&
2258 - echo c >z/c &&
2259 - git add z &&
2260 - test_tick &&
2261 - git commit -m "O" &&
2262 -
2263 - git branch O &&
2264 - git branch A &&
2265 - git branch B &&
2266 -
2267 - git checkout A &&
2268 - git mv z y &&
2269 - test_tick &&
2270 - git commit -m "A" &&
2271 -
2272 - git checkout B &&
2273 - git mv z w &&
2274 - mkdir z &&
2275 - echo d >z/d &&
2276 - git add z/d &&
2277 - test_tick &&
2278 - git commit -m "B"
2279 - )
2280 -'
2281 -
2282 -test_expect_success '8e-check: Both sides rename, one side adds to original directory' '
2283 - (
2284 - cd 8e &&
2285 -
2286 - git checkout A^0 &&
2287 -
2288 - test_must_fail git merge -s recursive B^0 >out 2>err &&
2289 - test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
2290 - test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
2291 -
2292 - git ls-files -s >out &&
2293 - test_line_count = 7 out &&
2294 - git ls-files -u >out &&
2295 - test_line_count = 6 out &&
2296 - git ls-files -o >out &&
2297 - test_line_count = 2 out &&
2298 -
2299 - git rev-parse >actual \
2300 - :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:w/c :0:y/d &&
2301 - git rev-parse >expect \
2302 - O:z/b O:z/b O:z/b O:z/c O:z/c O:z/c B:z/d &&
2303 - test_cmp expect actual &&
2304 -
2305 - git hash-object >actual \
2306 - y/b w/b y/c w/c &&
2307 - git rev-parse >expect \
2308 - O:z/b O:z/b O:z/c O:z/c &&
2309 - test_cmp expect actual &&
2310 -
2311 - test_path_is_missing z/b &&
2312 - test_path_is_missing z/c
2313 - )
2314 -'
2315 -
2316 -###########################################################################
2317 -# SECTION 9: Other testcases
2318 -#
2319 -# This section consists of miscellaneous testcases I thought of during
2320 -# the implementation which round out the testing.
2321 -###########################################################################
2322 -
2323 -# Testcase 9a, Inner renamed directory within outer renamed directory
2324 -# (Related to testcase 1f)
2325 -# Commit O: z/{b,c,d/{e,f,g}}
2326 -# Commit A: y/{b,c}, x/w/{e,f,g}
2327 -# Commit B: z/{b,c,d/{e,f,g,h},i}
2328 -# Expected: y/{b,c,i}, x/w/{e,f,g,h}
2329 -# NOTE: The only reason this one is interesting is because when a directory
2330 -# is split into multiple other directories, we determine by the weight
2331 -# of which one had the most paths going to it. A naive implementation
2332 -# of that could take the new file in commit B at z/i to x/w/i or x/i.
2333 -
2334 -test_expect_success '9a-setup: Inner renamed directory within outer renamed directory' '
2335 - test_create_repo 9a &&
2336 - (
2337 - cd 9a &&
2338 -
2339 - mkdir -p z/d &&
2340 - echo b >z/b &&
2341 - echo c >z/c &&
2342 - echo e >z/d/e &&
2343 - echo f >z/d/f &&
2344 - echo g >z/d/g &&
2345 - git add z &&
2346 - test_tick &&
2347 - git commit -m "O" &&
2348 -
2349 - git branch O &&
2350 - git branch A &&
2351 - git branch B &&
2352 -
2353 - git checkout A &&
2354 - mkdir x &&
2355 - git mv z/d x/w &&
2356 - git mv z y &&
2357 - test_tick &&
2358 - git commit -m "A" &&
2359 -
2360 - git checkout B &&
2361 - echo h >z/d/h &&
2362 - echo i >z/i &&
2363 - git add z &&
2364 - test_tick &&
2365 - git commit -m "B"
2366 - )
2367 -'
2368 -
2369 -test_expect_success '9a-check: Inner renamed directory within outer renamed directory' '
2370 - (
2371 - cd 9a &&
2372 -
2373 - git checkout A^0 &&
2374 -
2375 - git merge -s recursive B^0 &&
2376 -
2377 - git ls-files -s >out &&
2378 - test_line_count = 7 out &&
2379 - git ls-files -u >out &&
2380 - test_line_count = 0 out &&
2381 - git ls-files -o >out &&
2382 - test_line_count = 1 out &&
2383 -
2384 - git rev-parse >actual \
2385 - HEAD:y/b HEAD:y/c HEAD:y/i &&
2386 - git rev-parse >expect \
2387 - O:z/b O:z/c B:z/i &&
2388 - test_cmp expect actual &&
2389 -
2390 - git rev-parse >actual \
2391 - HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&
2392 - git rev-parse >expect \
2393 - O:z/d/e O:z/d/f O:z/d/g B:z/d/h &&
2394 - test_cmp expect actual
2395 - )
2396 -'
2397 -
2398 -# Testcase 9b, Transitive rename with content merge
2399 -# (Related to testcase 1c)
2400 -# Commit O: z/{b,c}, x/d_1
2401 -# Commit A: y/{b,c}, x/d_2
2402 -# Commit B: z/{b,c,d_3}
2403 -# Expected: y/{b,c,d_merged}
2404 -
2405 -test_expect_success '9b-setup: Transitive rename with content merge' '
2406 - test_create_repo 9b &&
2407 - (
2408 - cd 9b &&
2409 -
2410 - mkdir z &&
2411 - echo b >z/b &&
2412 - echo c >z/c &&
2413 - mkdir x &&
2414 - test_seq 1 10 >x/d &&
2415 - git add z x &&
2416 - test_tick &&
2417 - git commit -m "O" &&
2418 -
2419 - git branch O &&
2420 - git branch A &&
2421 - git branch B &&
2422 -
2423 - git checkout A &&
2424 - git mv z y &&
2425 - test_seq 1 11 >x/d &&
2426 - git add x/d &&
2427 - test_tick &&
2428 - git commit -m "A" &&
2429 -
2430 - git checkout B &&
2431 - test_seq 0 10 >x/d &&
2432 - git mv x/d z/d &&
2433 - git add z/d &&
2434 - test_tick &&
2435 - git commit -m "B"
2436 - )
2437 -'
2438 -
2439 -test_expect_success '9b-check: Transitive rename with content merge' '
2440 - (
2441 - cd 9b &&
2442 -
2443 - git checkout A^0 &&
2444 -
2445 - git merge -s recursive B^0 &&
2446 -
2447 - git ls-files -s >out &&
2448 - test_line_count = 3 out &&
2449 -
2450 - test_seq 0 11 >expected &&
2451 - test_cmp expected y/d &&
2452 - git add expected &&
2453 - git rev-parse >actual \
2454 - HEAD:y/b HEAD:y/c HEAD:y/d &&
2455 - git rev-parse >expect \
2456 - O:z/b O:z/c :0:expected &&
2457 - test_cmp expect actual &&
2458 - test_must_fail git rev-parse HEAD:x/d &&
2459 - test_must_fail git rev-parse HEAD:z/d &&
2460 - test_path_is_missing z/d &&
2461 -
2462 - test $(git rev-parse HEAD:y/d) != $(git rev-parse O:x/d) &&
2463 - test $(git rev-parse HEAD:y/d) != $(git rev-parse A:x/d) &&
2464 - test $(git rev-parse HEAD:y/d) != $(git rev-parse B:z/d)
2465 - )
2466 -'
2467 -
2468 -# Testcase 9c, Doubly transitive rename?
2469 -# (Related to testcase 1c, 7e, and 9d)
2470 -# Commit O: z/{b,c}, x/{d,e}, w/f
2471 -# Commit A: y/{b,c}, x/{d,e,f,g}
2472 -# Commit B: z/{b,c,d,e}, w/f
2473 -# Expected: y/{b,c,d,e}, x/{f,g}
2474 -#
2475 -# NOTE: x/f and x/g may be slightly confusing here. The rename from w/f to
2476 -# x/f is clear. Let's look beyond that. Here's the logic:
2477 -# Commit B renamed x/ -> z/
2478 -# Commit A renamed z/ -> y/
2479 -# So, we could possibly further rename x/f to z/f to y/f, a doubly
2480 -# transient rename. However, where does it end? We can chain these
2481 -# indefinitely (see testcase 9d). What if there is a D/F conflict
2482 -# at z/f/ or y/f/? Or just another file conflict at one of those
2483 -# paths? In the case of an N-long chain of transient renamings,
2484 -# where do we "abort" the rename at? Can the user make sense of
2485 -# the resulting conflict and resolve it?
2486 -#
2487 -# To avoid this confusion I use the simple rule that if the other side
2488 -# of history did a directory rename to a path that your side renamed
2489 -# away, then ignore that particular rename from the other side of
2490 -# history for any implicit directory renames.
2491 -
2492 -test_expect_success '9c-setup: Doubly transitive rename?' '
2493 - test_create_repo 9c &&
2494 - (
2495 - cd 9c &&
2496 -
2497 - mkdir z &&
2498 - echo b >z/b &&
2499 - echo c >z/c &&
2500 - mkdir x &&
2501 - echo d >x/d &&
2502 - echo e >x/e &&
2503 - mkdir w &&
2504 - echo f >w/f &&
2505 - git add z x w &&
2506 - test_tick &&
2507 - git commit -m "O" &&
2508 -
2509 - git branch O &&
2510 - git branch A &&
2511 - git branch B &&
2512 -
2513 - git checkout A &&
2514 - git mv z y &&
2515 - git mv w/f x/ &&
2516 - echo g >x/g &&
2517 - git add x/g &&
2518 - test_tick &&
2519 - git commit -m "A" &&
2520 -
2521 - git checkout B &&
2522 - git mv x/d z/d &&
2523 - git mv x/e z/e &&
2524 - test_tick &&
2525 - git commit -m "B"
2526 - )
2527 -'
2528 -
2529 -test_expect_success '9c-check: Doubly transitive rename?' '
2530 - (
2531 - cd 9c &&
2532 -
2533 - git checkout A^0 &&
2534 -
2535 - git merge -s recursive B^0 >out &&
2536 - test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
2537 -
2538 - git ls-files -s >out &&
2539 - test_line_count = 6 out &&
2540 - git ls-files -o >out &&
2541 - test_line_count = 1 out &&
2542 -
2543 - git rev-parse >actual \
2544 - HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&
2545 - git rev-parse >expect \
2546 - O:z/b O:z/c O:x/d O:x/e O:w/f A:x/g &&
2547 - test_cmp expect actual
2548 - )
2549 -'
2550 -
2551 -# Testcase 9d, N-fold transitive rename?
2552 -# (Related to testcase 9c...and 1c and 7e)
2553 -# Commit O: z/a, y/b, x/c, w/d, v/e, u/f
2554 -# Commit A: y/{a,b}, w/{c,d}, u/{e,f}
2555 -# Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f
2556 -# Expected: <see NOTE first>
2557 -#
2558 -# NOTE: z/ -> y/ (in commit A)
2559 -# y/ -> x/ (in commit B)
2560 -# x/ -> w/ (in commit A)
2561 -# w/ -> v/ (in commit B)
2562 -# v/ -> u/ (in commit A)
2563 -# So, if we add a file to z, say z/t, where should it end up? In u?
2564 -# What if there's another file or directory named 't' in one of the
2565 -# intervening directories and/or in u itself? Also, shouldn't the
2566 -# same logic that places 't' in u/ also move ALL other files to u/?
2567 -# What if there are file or directory conflicts in any of them? If
2568 -# we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames
2569 -# like this, would the user have any hope of understanding any
2570 -# conflicts or how their working tree ended up? I think not, so I'm
2571 -# ruling out N-ary transitive renames for N>1.
2572 -#
2573 -# Therefore our expected result is:
2574 -# z/t, y/a, x/b, w/c, u/d, u/e, u/f
2575 -# The reason that v/d DOES get transitively renamed to u/d is that u/ isn't
2576 -# renamed somewhere. A slightly sub-optimal result, but it uses fairly
2577 -# simple rules that are consistent with what we need for all the other
2578 -# testcases and simplifies things for the user.
2579 -
2580 -test_expect_success '9d-setup: N-way transitive rename?' '
2581 - test_create_repo 9d &&
2582 - (
2583 - cd 9d &&
2584 -
2585 - mkdir z y x w v u &&
2586 - echo a >z/a &&
2587 - echo b >y/b &&
2588 - echo c >x/c &&
2589 - echo d >w/d &&
2590 - echo e >v/e &&
2591 - echo f >u/f &&
2592 - git add z y x w v u &&
2593 - test_tick &&
2594 - git commit -m "O" &&
2595 -
2596 - git branch O &&
2597 - git branch A &&
2598 - git branch B &&
2599 -
2600 - git checkout A &&
2601 - git mv z/a y/ &&
2602 - git mv x/c w/ &&
2603 - git mv v/e u/ &&
2604 - test_tick &&
2605 - git commit -m "A" &&
2606 -
2607 - git checkout B &&
2608 - echo t >z/t &&
2609 - git mv y/b x/ &&
2610 - git mv w/d v/ &&
2611 - git add z/t &&
2612 - test_tick &&
2613 - git commit -m "B"
2614 - )
2615 -'
2616 -
2617 -test_expect_success '9d-check: N-way transitive rename?' '
2618 - (
2619 - cd 9d &&
2620 -
2621 - git checkout A^0 &&
2622 -
2623 - git merge -s recursive B^0 >out &&
2624 - test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
2625 - test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
2626 - test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
2627 - test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&
2628 -
2629 - git ls-files -s >out &&
2630 - test_line_count = 7 out &&
2631 - git ls-files -o >out &&
2632 - test_line_count = 1 out &&
2633 -
2634 - git rev-parse >actual \
2635 - HEAD:z/t \
2636 - HEAD:y/a HEAD:x/b HEAD:w/c \
2637 - HEAD:u/d HEAD:u/e HEAD:u/f &&
2638 - git rev-parse >expect \
2639 - B:z/t \
2640 - O:z/a O:y/b O:x/c \
2641 - O:w/d O:v/e A:u/f &&
2642 - test_cmp expect actual
2643 - )
2644 -'
2645 -
2646 -# Testcase 9e, N-to-1 whammo
2647 -# (Related to testcase 9c...and 1c and 7e)
2648 -# Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}
2649 -# Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}
2650 -# Commit B: combined/{a,b,d,e,g,h,j,k}
2651 -# Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,
2652 -# dir1/yo, dir2/yo, dir3/yo, dirN/yo
2653 -
2654 -test_expect_success '9e-setup: N-to-1 whammo' '
2655 - test_create_repo 9e &&
2656 - (
2657 - cd 9e &&
2658 -
2659 - mkdir dir1 dir2 dir3 dirN &&
2660 - echo a >dir1/a &&
2661 - echo b >dir1/b &&
2662 - echo d >dir2/d &&
2663 - echo e >dir2/e &&
2664 - echo g >dir3/g &&
2665 - echo h >dir3/h &&
2666 - echo j >dirN/j &&
2667 - echo k >dirN/k &&
2668 - git add dir* &&
2669 - test_tick &&
2670 - git commit -m "O" &&
2671 -
2672 - git branch O &&
2673 - git branch A &&
2674 - git branch B &&
2675 -
2676 - git checkout A &&
2677 - echo c >dir1/c &&
2678 - echo yo >dir1/yo &&
2679 - echo f >dir2/f &&
2680 - echo yo >dir2/yo &&
2681 - echo i >dir3/i &&
2682 - echo yo >dir3/yo &&
2683 - echo l >dirN/l &&
2684 - echo yo >dirN/yo &&
2685 - git add dir* &&
2686 - test_tick &&
2687 - git commit -m "A" &&
2688 -
2689 - git checkout B &&
2690 - git mv dir1 combined &&
2691 - git mv dir2/* combined/ &&
2692 - git mv dir3/* combined/ &&
2693 - git mv dirN/* combined/ &&
2694 - test_tick &&
2695 - git commit -m "B"
2696 - )
2697 -'
2698 -
2699 -test_expect_success C_LOCALE_OUTPUT '9e-check: N-to-1 whammo' '
2700 - (
2701 - cd 9e &&
2702 -
2703 - git checkout A^0 &&
2704 -
2705 - test_must_fail git merge -s recursive B^0 >out &&
2706 - grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&
2707 - grep -q dir1/yo error_line &&
2708 - grep -q dir2/yo error_line &&
2709 - grep -q dir3/yo error_line &&
2710 - grep -q dirN/yo error_line &&
2711 -
2712 - git ls-files -s >out &&
2713 - test_line_count = 16 out &&
2714 - git ls-files -u >out &&
2715 - test_line_count = 0 out &&
2716 - git ls-files -o >out &&
2717 - test_line_count = 2 out &&
2718 -
2719 - git rev-parse >actual \
2720 - :0:combined/a :0:combined/b :0:combined/c \
2721 - :0:combined/d :0:combined/e :0:combined/f \
2722 - :0:combined/g :0:combined/h :0:combined/i \
2723 - :0:combined/j :0:combined/k :0:combined/l &&
2724 - git rev-parse >expect \
2725 - O:dir1/a O:dir1/b A:dir1/c \
2726 - O:dir2/d O:dir2/e A:dir2/f \
2727 - O:dir3/g O:dir3/h A:dir3/i \
2728 - O:dirN/j O:dirN/k A:dirN/l &&
2729 - test_cmp expect actual &&
2730 -
2731 - git rev-parse >actual \
2732 - :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&
2733 - git rev-parse >expect \
2734 - A:dir1/yo A:dir2/yo A:dir3/yo A:dirN/yo &&
2735 - test_cmp expect actual
2736 - )
2737 -'
2738 -
2739 -# Testcase 9f, Renamed directory that only contained immediate subdirs
2740 -# (Related to testcases 1e & 9g)
2741 -# Commit O: goal/{a,b}/$more_files
2742 -# Commit A: priority/{a,b}/$more_files
2743 -# Commit B: goal/{a,b}/$more_files, goal/c
2744 -# Expected: priority/{a,b}/$more_files, priority/c
2745 -
2746 -test_expect_success '9f-setup: Renamed directory that only contained immediate subdirs' '
2747 - test_create_repo 9f &&
2748 - (
2749 - cd 9f &&
2750 -
2751 - mkdir -p goal/a &&
2752 - mkdir -p goal/b &&
2753 - echo foo >goal/a/foo &&
2754 - echo bar >goal/b/bar &&
2755 - echo baz >goal/b/baz &&
2756 - git add goal &&
2757 - test_tick &&
2758 - git commit -m "O" &&
2759 -
2760 - git branch O &&
2761 - git branch A &&
2762 - git branch B &&
2763 -
2764 - git checkout A &&
2765 - git mv goal/ priority &&
2766 - test_tick &&
2767 - git commit -m "A" &&
2768 -
2769 - git checkout B &&
2770 - echo c >goal/c &&
2771 - git add goal/c &&
2772 - test_tick &&
2773 - git commit -m "B"
2774 - )
2775 -'
2776 -
2777 -test_expect_success '9f-check: Renamed directory that only contained immediate subdirs' '
2778 - (
2779 - cd 9f &&
2780 -
2781 - git checkout A^0 &&
2782 -
2783 - git merge -s recursive B^0 &&
2784 -
2785 - git ls-files -s >out &&
2786 - test_line_count = 4 out &&
2787 -
2788 - git rev-parse >actual \
2789 - HEAD:priority/a/foo \
2790 - HEAD:priority/b/bar \
2791 - HEAD:priority/b/baz \
2792 - HEAD:priority/c &&
2793 - git rev-parse >expect \
2794 - O:goal/a/foo \
2795 - O:goal/b/bar \
2796 - O:goal/b/baz \
2797 - B:goal/c &&
2798 - test_cmp expect actual &&
2799 - test_must_fail git rev-parse HEAD:goal/c
2800 - )
2801 -'
2802 -
2803 -# Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed
2804 -# (Related to testcases 1e & 9f)
2805 -# Commit O: goal/{a,b}/$more_files
2806 -# Commit A: priority/{alpha,bravo}/$more_files
2807 -# Commit B: goal/{a,b}/$more_files, goal/c
2808 -# Expected: priority/{alpha,bravo}/$more_files, priority/c
2809 -
2810 -test_expect_success '9g-setup: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2811 - test_create_repo 9g &&
2812 - (
2813 - cd 9g &&
2814 -
2815 - mkdir -p goal/a &&
2816 - mkdir -p goal/b &&
2817 - echo foo >goal/a/foo &&
2818 - echo bar >goal/b/bar &&
2819 - echo baz >goal/b/baz &&
2820 - git add goal &&
2821 - test_tick &&
2822 - git commit -m "O" &&
2823 -
2824 - git branch O &&
2825 - git branch A &&
2826 - git branch B &&
2827 -
2828 - git checkout A &&
2829 - mkdir priority &&
2830 - git mv goal/a/ priority/alpha &&
2831 - git mv goal/b/ priority/beta &&
2832 - rmdir goal/ &&
2833 - test_tick &&
2834 - git commit -m "A" &&
2835 -
2836 - git checkout B &&
2837 - echo c >goal/c &&
2838 - git add goal/c &&
2839 - test_tick &&
2840 - git commit -m "B"
2841 - )
2842 -'
2843 -
2844 -test_expect_failure '9g-check: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2845 - (
2846 - cd 9g &&
2847 -
2848 - git checkout A^0 &&
2849 -
2850 - git merge -s recursive B^0 &&
2851 -
2852 - git ls-files -s >out &&
2853 - test_line_count = 4 out &&
2854 -
2855 - git rev-parse >actual \
2856 - HEAD:priority/alpha/foo \
2857 - HEAD:priority/beta/bar \
2858 - HEAD:priority/beta/baz \
2859 - HEAD:priority/c &&
2860 - git rev-parse >expect \
2861 - O:goal/a/foo \
2862 - O:goal/b/bar \
2863 - O:goal/b/baz \
2864 - B:goal/c &&
2865 - test_cmp expect actual &&
2866 - test_must_fail git rev-parse HEAD:goal/c
2867 - )
2868 -'
2869 -
2870 -# Testcase 9h, Avoid implicit rename if involved as source on other side
2871 -# (Extremely closely related to testcase 3a)
2872 -# Commit O: z/{b,c,d_1}
2873 -# Commit A: z/{b,c,d_2}
2874 -# Commit B: y/{b,c}, x/d_1
2875 -# Expected: y/{b,c}, x/d_2
2876 -# NOTE: If we applied the z/ -> y/ rename to z/d, then we'd end up with
2877 -# a rename/rename(1to2) conflict (z/d -> y/d vs. x/d)
2878 -test_expect_success '9h-setup: Avoid dir rename on merely modified path' '
2879 - test_create_repo 9h &&
2880 - (
2881 - cd 9h &&
2882 -
2883 - mkdir z &&
2884 - echo b >z/b &&
2885 - echo c >z/c &&
2886 - printf "1\n2\n3\n4\n5\n6\n7\n8\nd\n" >z/d &&
2887 - git add z &&
2888 - test_tick &&
2889 - git commit -m "O" &&
2890 -
2891 - git branch O &&
2892 - git branch A &&
2893 - git branch B &&
2894 -
2895 - git checkout A &&
2896 - test_tick &&
2897 - echo more >>z/d &&
2898 - git add z/d &&
2899 - git commit -m "A" &&
2900 -
2901 - git checkout B &&
2902 - mkdir y &&
2903 - mkdir x &&
2904 - git mv z/b y/ &&
2905 - git mv z/c y/ &&
2906 - git mv z/d x/ &&
2907 - rmdir z &&
2908 - test_tick &&
2909 - git commit -m "B"
2910 - )
2911 -'
2912 -
2913 -test_expect_success '9h-check: Avoid dir rename on merely modified path' '
2914 - (
2915 - cd 9h &&
2916 -
2917 - git checkout A^0 &&
2918 -
2919 - git merge -s recursive B^0 &&
2920 -
2921 - git ls-files -s >out &&
2922 - test_line_count = 3 out &&
2923 -
2924 - git rev-parse >actual \
2925 - HEAD:y/b HEAD:y/c HEAD:x/d &&
2926 - git rev-parse >expect \
2927 - O:z/b O:z/c A:z/d &&
2928 - test_cmp expect actual
2929 - )
2930 -'
2931 -
2932 -###########################################################################
2933 -# Rules suggested by section 9:
2934 -#
2935 -# If the other side of history did a directory rename to a path that your
2936 -# side renamed away, then ignore that particular rename from the other
2937 -# side of history for any implicit directory renames.
2938 -###########################################################################
2939 -
2940 -###########################################################################
2941 -# SECTION 10: Handling untracked files
2942 -#
2943 -# unpack_trees(), upon which the recursive merge algorithm is based, aborts
2944 -# the operation if untracked or dirty files would be deleted or overwritten
2945 -# by the merge. Unfortunately, unpack_trees() does not understand renames,
2946 -# and if it doesn't abort, then it muddies up the working directory before
2947 -# we even get to the point of detecting renames, so we need some special
2948 -# handling, at least in the case of directory renames.
2949 -###########################################################################
2950 -
2951 -# Testcase 10a, Overwrite untracked: normal rename/delete
2952 -# Commit O: z/{b,c_1}
2953 -# Commit A: z/b + untracked z/c + untracked z/d
2954 -# Commit B: z/{b,d_1}
2955 -# Expected: Aborted Merge +
2956 -# ERROR_MSG(untracked working tree files would be overwritten by merge)
2957 -
2958 -test_expect_success '10a-setup: Overwrite untracked with normal rename/delete' '
2959 - test_create_repo 10a &&
2960 - (
2961 - cd 10a &&
2962 -
2963 - mkdir z &&
2964 - echo b >z/b &&
2965 - echo c >z/c &&
2966 - git add z &&
2967 - test_tick &&
2968 - git commit -m "O" &&
2969 -
2970 - git branch O &&
2971 - git branch A &&
2972 - git branch B &&
2973 -
2974 - git checkout A &&
2975 - git rm z/c &&
2976 - test_tick &&
2977 - git commit -m "A" &&
2978 -
2979 - git checkout B &&
2980 - git mv z/c z/d &&
2981 - test_tick &&
2982 - git commit -m "B"
2983 - )
2984 -'
2985 -
2986 -test_expect_success '10a-check: Overwrite untracked with normal rename/delete' '
2987 - (
2988 - cd 10a &&
2989 -
2990 - git checkout A^0 &&
2991 - echo very >z/c &&
2992 - echo important >z/d &&
2993 -
2994 - test_must_fail git merge -s recursive B^0 >out 2>err &&
2995 - test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&
2996 -
2997 - git ls-files -s >out &&
2998 - test_line_count = 1 out &&
2999 - git ls-files -o >out &&
3000 - test_line_count = 4 out &&
3001 -
3002 - echo very >expect &&
3003 - test_cmp expect z/c &&
3004 -
3005 - echo important >expect &&
3006 - test_cmp expect z/d &&
3007 -
3008 - git rev-parse HEAD:z/b >actual &&
3009 - git rev-parse O:z/b >expect &&
3010 - test_cmp expect actual
3011 - )
3012 -'
3013 -
3014 -# Testcase 10b, Overwrite untracked: dir rename + delete
3015 -# Commit O: z/{b,c_1}
3016 -# Commit A: y/b + untracked y/{c,d,e}
3017 -# Commit B: z/{b,d_1,e}
3018 -# Expected: Failed Merge; y/b + untracked y/c + untracked y/d on disk +
3019 -# z/c_1 -> z/d_1 rename recorded at stage 3 for y/d +
3020 -# ERROR_MSG(refusing to lose untracked file at 'y/d')
3021 -
3022 -test_expect_success '10b-setup: Overwrite untracked with dir rename + delete' '
3023 - test_create_repo 10b &&
3024 - (
3025 - cd 10b &&
3026 -
3027 - mkdir z &&
3028 - echo b >z/b &&
3029 - echo c >z/c &&
3030 - git add z &&
3031 - test_tick &&
3032 - git commit -m "O" &&
3033 -
3034 - git branch O &&
3035 - git branch A &&
3036 - git branch B &&
3037 -
3038 - git checkout A &&
3039 - git rm z/c &&
3040 - git mv z/ y/ &&
3041 - test_tick &&
3042 - git commit -m "A" &&
3043 -
3044 - git checkout B &&
3045 - git mv z/c z/d &&
3046 - echo e >z/e &&
3047 - git add z/e &&
3048 - test_tick &&
3049 - git commit -m "B"
3050 - )
3051 -'
3052 -
3053 -test_expect_success '10b-check: Overwrite untracked with dir rename + delete' '
3054 - (
3055 - cd 10b &&
3056 -
3057 - git checkout A^0 &&
3058 - echo very >y/c &&
3059 - echo important >y/d &&
3060 - echo contents >y/e &&
3061 -
3062 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3063 - test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
3064 - test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
3065 -
3066 - git ls-files -s >out &&
3067 - test_line_count = 3 out &&
3068 - git ls-files -u >out &&
3069 - test_line_count = 2 out &&
3070 - git ls-files -o >out &&
3071 - test_line_count = 5 out &&
3072 -
3073 - git rev-parse >actual \
3074 - :0:y/b :3:y/d :3:y/e &&
3075 - git rev-parse >expect \
3076 - O:z/b O:z/c B:z/e &&
3077 - test_cmp expect actual &&
3078 -
3079 - echo very >expect &&
3080 - test_cmp expect y/c &&
3081 -
3082 - echo important >expect &&
3083 - test_cmp expect y/d &&
3084 -
3085 - echo contents >expect &&
3086 - test_cmp expect y/e
3087 - )
3088 -'
3089 -
3090 -# Testcase 10c, Overwrite untracked: dir rename/rename(1to2)
3091 -# Commit O: z/{a,b}, x/{c,d}
3092 -# Commit A: y/{a,b}, w/c, x/d + different untracked y/c
3093 -# Commit B: z/{a,b,c}, x/d
3094 -# Expected: Failed Merge; y/{a,b} + x/d + untracked y/c +
3095 -# CONFLICT(rename/rename) x/c -> w/c vs y/c +
3096 -# y/c~B^0 +
3097 -# ERROR_MSG(Refusing to lose untracked file at y/c)
3098 -
3099 -test_expect_success '10c-setup: Overwrite untracked with dir rename/rename(1to2)' '
3100 - test_create_repo 10c &&
3101 - (
3102 - cd 10c &&
3103 -
3104 - mkdir z x &&
3105 - echo a >z/a &&
3106 - echo b >z/b &&
3107 - echo c >x/c &&
3108 - echo d >x/d &&
3109 - git add z x &&
3110 - test_tick &&
3111 - git commit -m "O" &&
3112 -
3113 - git branch O &&
3114 - git branch A &&
3115 - git branch B &&
3116 -
3117 - git checkout A &&
3118 - mkdir w &&
3119 - git mv x/c w/c &&
3120 - git mv z/ y/ &&
3121 - test_tick &&
3122 - git commit -m "A" &&
3123 -
3124 - git checkout B &&
3125 - git mv x/c z/ &&
3126 - test_tick &&
3127 - git commit -m "B"
3128 - )
3129 -'
3130 -
3131 -test_expect_success '10c-check: Overwrite untracked with dir rename/rename(1to2)' '
3132 - (
3133 - cd 10c &&
3134 -
3135 - git checkout A^0 &&
3136 - echo important >y/c &&
3137 -
3138 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3139 - test_i18ngrep "CONFLICT (rename/rename)" out &&
3140 - test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
3141 -
3142 - git ls-files -s >out &&
3143 - test_line_count = 6 out &&
3144 - git ls-files -u >out &&
3145 - test_line_count = 3 out &&
3146 - git ls-files -o >out &&
3147 - test_line_count = 3 out &&
3148 -
3149 - git rev-parse >actual \
3150 - :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&
3151 - git rev-parse >expect \
3152 - O:z/a O:z/b O:x/d O:x/c O:x/c O:x/c &&
3153 - test_cmp expect actual &&
3154 -
3155 - git hash-object y/c~B^0 >actual &&
3156 - git rev-parse O:x/c >expect &&
3157 - test_cmp expect actual &&
3158 -
3159 - echo important >expect &&
3160 - test_cmp expect y/c
3161 - )
3162 -'
3163 -
3164 -# Testcase 10d, Delete untracked w/ dir rename/rename(2to1)
3165 -# Commit O: z/{a,b,c_1}, x/{d,e,f_2}
3166 -# Commit A: y/{a,b}, x/{d,e,f_2,wham_1} + untracked y/wham
3167 -# Commit B: z/{a,b,c_1,wham_2}, y/{d,e}
3168 -# Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~B^0,wham~HEAD}+
3169 -# CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham
3170 -# ERROR_MSG(Refusing to lose untracked file at y/wham)
3171 -
3172 -test_expect_success '10d-setup: Delete untracked with dir rename/rename(2to1)' '
3173 - test_create_repo 10d &&
3174 - (
3175 - cd 10d &&
3176 -
3177 - mkdir z x &&
3178 - echo a >z/a &&
3179 - echo b >z/b &&
3180 - echo c >z/c &&
3181 - echo d >x/d &&
3182 - echo e >x/e &&
3183 - echo f >x/f &&
3184 - git add z x &&
3185 - test_tick &&
3186 - git commit -m "O" &&
3187 -
3188 - git branch O &&
3189 - git branch A &&
3190 - git branch B &&
3191 -
3192 - git checkout A &&
3193 - git mv z/c x/wham &&
3194 - git mv z/ y/ &&
3195 - test_tick &&
3196 - git commit -m "A" &&
3197 -
3198 - git checkout B &&
3199 - git mv x/f z/wham &&
3200 - git mv x/ y/ &&
3201 - test_tick &&
3202 - git commit -m "B"
3203 - )
3204 -'
3205 -
3206 -test_expect_success '10d-check: Delete untracked with dir rename/rename(2to1)' '
3207 - (
3208 - cd 10d &&
3209 -
3210 - git checkout A^0 &&
3211 - echo important >y/wham &&
3212 -
3213 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3214 - test_i18ngrep "CONFLICT (rename/rename)" out &&
3215 - test_i18ngrep "Refusing to lose untracked file at y/wham" out &&
3216 -
3217 - git ls-files -s >out &&
3218 - test_line_count = 6 out &&
3219 - git ls-files -u >out &&
3220 - test_line_count = 2 out &&
3221 - git ls-files -o >out &&
3222 - test_line_count = 4 out &&
3223 -
3224 - git rev-parse >actual \
3225 - :0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&
3226 - git rev-parse >expect \
3227 - O:z/a O:z/b O:x/d O:x/e O:z/c O:x/f &&
3228 - test_cmp expect actual &&
3229 -
3230 - test_must_fail git rev-parse :1:y/wham &&
3231 -
3232 - echo important >expect &&
3233 - test_cmp expect y/wham &&
3234 -
3235 - git hash-object >actual \
3236 - y/wham~B^0 y/wham~HEAD &&
3237 - git rev-parse >expect \
3238 - O:x/f O:z/c &&
3239 - test_cmp expect actual
3240 - )
3241 -'
3242 -
3243 -# Testcase 10e, Does git complain about untracked file that's not in the way?
3244 -# Commit O: z/{a,b}
3245 -# Commit A: y/{a,b} + untracked z/c
3246 -# Commit B: z/{a,b,c}
3247 -# Expected: y/{a,b,c} + untracked z/c
3248 -
3249 -test_expect_success '10e-setup: Does git complain about untracked file that is not really in the way?' '
3250 - test_create_repo 10e &&
3251 - (
3252 - cd 10e &&
3253 -
3254 - mkdir z &&
3255 - echo a >z/a &&
3256 - echo b >z/b &&
3257 - git add z &&
3258 - test_tick &&
3259 - git commit -m "O" &&
3260 -
3261 - git branch O &&
3262 - git branch A &&
3263 - git branch B &&
3264 -
3265 - git checkout A &&
3266 - git mv z/ y/ &&
3267 - test_tick &&
3268 - git commit -m "A" &&
3269 -
3270 - git checkout B &&
3271 - echo c >z/c &&
3272 - git add z/c &&
3273 - test_tick &&
3274 - git commit -m "B"
3275 - )
3276 -'
3277 -
3278 -test_expect_failure '10e-check: Does git complain about untracked file that is not really in the way?' '
3279 - (
3280 - cd 10e &&
3281 -
3282 - git checkout A^0 &&
3283 - mkdir z &&
3284 - echo random >z/c &&
3285 -
3286 - git merge -s recursive B^0 >out 2>err &&
3287 - test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&
3288 -
3289 - git ls-files -s >out &&
3290 - test_line_count = 3 out &&
3291 - git ls-files -u >out &&
3292 - test_line_count = 0 out &&
3293 - git ls-files -o >out &&
3294 - test_line_count = 3 out &&
3295 -
3296 - git rev-parse >actual \
3297 - :0:y/a :0:y/b :0:y/c &&
3298 - git rev-parse >expect \
3299 - O:z/a O:z/b B:z/c &&
3300 - test_cmp expect actual &&
3301 -
3302 - echo random >expect &&
3303 - test_cmp expect z/c
3304 - )
3305 -'
3306 -
3307 -###########################################################################
3308 -# SECTION 11: Handling dirty (not up-to-date) files
3309 -#
3310 -# unpack_trees(), upon which the recursive merge algorithm is based, aborts
3311 -# the operation if untracked or dirty files would be deleted or overwritten
3312 -# by the merge. Unfortunately, unpack_trees() does not understand renames,
3313 -# and if it doesn't abort, then it muddies up the working directory before
3314 -# we even get to the point of detecting renames, so we need some special
3315 -# handling. This was true even of normal renames, but there are additional
3316 -# codepaths that need special handling with directory renames. Add
3317 -# testcases for both renamed-by-directory-rename-detection and standard
3318 -# rename cases.
3319 -###########################################################################
3320 -
3321 -# Testcase 11a, Avoid losing dirty contents with simple rename
3322 -# Commit O: z/{a,b_v1},
3323 -# Commit A: z/{a,c_v1}, and z/c_v1 has uncommitted mods
3324 -# Commit B: z/{a,b_v2}
3325 -# Expected: ERROR_MSG(Refusing to lose dirty file at z/c) +
3326 -# z/a, staged version of z/c has sha1sum matching B:z/b_v2,
3327 -# z/c~HEAD with contents of B:z/b_v2,
3328 -# z/c with uncommitted mods on top of A:z/c_v1
3329 -
3330 -test_expect_success '11a-setup: Avoid losing dirty contents with simple rename' '
3331 - test_create_repo 11a &&
3332 - (
3333 - cd 11a &&
3334 -
3335 - mkdir z &&
3336 - echo a >z/a &&
3337 - test_seq 1 10 >z/b &&
3338 - git add z &&
3339 - test_tick &&
3340 - git commit -m "O" &&
3341 -
3342 - git branch O &&
3343 - git branch A &&
3344 - git branch B &&
3345 -
3346 - git checkout A &&
3347 - git mv z/b z/c &&
3348 - test_tick &&
3349 - git commit -m "A" &&
3350 -
3351 - git checkout B &&
3352 - echo 11 >>z/b &&
3353 - git add z/b &&
3354 - test_tick &&
3355 - git commit -m "B"
3356 - )
3357 -'
3358 -
3359 -test_expect_success '11a-check: Avoid losing dirty contents with simple rename' '
3360 - (
3361 - cd 11a &&
3362 -
3363 - git checkout A^0 &&
3364 - echo stuff >>z/c &&
3365 -
3366 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3367 - test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3368 -
3369 - test_seq 1 10 >expected &&
3370 - echo stuff >>expected &&
3371 - test_cmp expected z/c &&
3372 -
3373 - git ls-files -s >out &&
3374 - test_line_count = 2 out &&
3375 - git ls-files -u >out &&
3376 - test_line_count = 1 out &&
3377 - git ls-files -o >out &&
3378 - test_line_count = 4 out &&
3379 -
3380 - git rev-parse >actual \
3381 - :0:z/a :2:z/c &&
3382 - git rev-parse >expect \
3383 - O:z/a B:z/b &&
3384 - test_cmp expect actual &&
3385 -
3386 - git hash-object z/c~HEAD >actual &&
3387 - git rev-parse B:z/b >expect &&
3388 - test_cmp expect actual
3389 - )
3390 -'
3391 -
3392 -# Testcase 11b, Avoid losing dirty file involved in directory rename
3393 -# Commit O: z/a, x/{b,c_v1}
3394 -# Commit A: z/{a,c_v1}, x/b, and z/c_v1 has uncommitted mods
3395 -# Commit B: y/a, x/{b,c_v2}
3396 -# Expected: y/{a,c_v2}, x/b, z/c_v1 with uncommitted mods untracked,
3397 -# ERROR_MSG(Refusing to lose dirty file at z/c)
3398 -
3399 -
3400 -test_expect_success '11b-setup: Avoid losing dirty file involved in directory rename' '
3401 - test_create_repo 11b &&
3402 - (
3403 - cd 11b &&
3404 -
3405 - mkdir z x &&
3406 - echo a >z/a &&
3407 - echo b >x/b &&
3408 - test_seq 1 10 >x/c &&
3409 - git add z x &&
3410 - test_tick &&
3411 - git commit -m "O" &&
3412 -
3413 - git branch O &&
3414 - git branch A &&
3415 - git branch B &&
3416 -
3417 - git checkout A &&
3418 - git mv x/c z/c &&
3419 - test_tick &&
3420 - git commit -m "A" &&
3421 -
3422 - git checkout B &&
3423 - git mv z y &&
3424 - echo 11 >>x/c &&
3425 - git add x/c &&
3426 - test_tick &&
3427 - git commit -m "B"
3428 - )
3429 -'
3430 -
3431 -test_expect_success '11b-check: Avoid losing dirty file involved in directory rename' '
3432 - (
3433 - cd 11b &&
3434 -
3435 - git checkout A^0 &&
3436 - echo stuff >>z/c &&
3437 -
3438 - git merge -s recursive B^0 >out 2>err &&
3439 - test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3440 -
3441 - grep -q stuff z/c &&
3442 - test_seq 1 10 >expected &&
3443 - echo stuff >>expected &&
3444 - test_cmp expected z/c &&
3445 -
3446 - git ls-files -s >out &&
3447 - test_line_count = 3 out &&
3448 - git ls-files -u >out &&
3449 - test_line_count = 0 out &&
3450 - git ls-files -m >out &&
3451 - test_line_count = 0 out &&
3452 - git ls-files -o >out &&
3453 - test_line_count = 4 out &&
3454 -
3455 - git rev-parse >actual \
3456 - :0:x/b :0:y/a :0:y/c &&
3457 - git rev-parse >expect \
3458 - O:x/b O:z/a B:x/c &&
3459 - test_cmp expect actual &&
3460 -
3461 - git hash-object y/c >actual &&
3462 - git rev-parse B:x/c >expect &&
3463 - test_cmp expect actual
3464 - )
3465 -'
3466 -
3467 -# Testcase 11c, Avoid losing not-up-to-date with rename + D/F conflict
3468 -# Commit O: y/a, x/{b,c_v1}
3469 -# Commit A: y/{a,c_v1}, x/b, and y/c_v1 has uncommitted mods
3470 -# Commit B: y/{a,c/d}, x/{b,c_v2}
3471 -# Expected: Abort_msg("following files would be overwritten by merge") +
3472 -# y/c left untouched (still has uncommitted mods)
3473 -
3474 -test_expect_success '11c-setup: Avoid losing not-uptodate with rename + D/F conflict' '
3475 - test_create_repo 11c &&
3476 - (
3477 - cd 11c &&
3478 -
3479 - mkdir y x &&
3480 - echo a >y/a &&
3481 - echo b >x/b &&
3482 - test_seq 1 10 >x/c &&
3483 - git add y x &&
3484 - test_tick &&
3485 - git commit -m "O" &&
3486 -
3487 - git branch O &&
3488 - git branch A &&
3489 - git branch B &&
3490 -
3491 - git checkout A &&
3492 - git mv x/c y/c &&
3493 - test_tick &&
3494 - git commit -m "A" &&
3495 -
3496 - git checkout B &&
3497 - mkdir y/c &&
3498 - echo d >y/c/d &&
3499 - echo 11 >>x/c &&
3500 - git add x/c y/c/d &&
3501 - test_tick &&
3502 - git commit -m "B"
3503 - )
3504 -'
3505 -
3506 -test_expect_success '11c-check: Avoid losing not-uptodate with rename + D/F conflict' '
3507 - (
3508 - cd 11c &&
3509 -
3510 - git checkout A^0 &&
3511 - echo stuff >>y/c &&
3512 -
3513 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3514 - test_i18ngrep "following files would be overwritten by merge" err &&
3515 -
3516 - grep -q stuff y/c &&
3517 - test_seq 1 10 >expected &&
3518 - echo stuff >>expected &&
3519 - test_cmp expected y/c &&
3520 -
3521 - git ls-files -s >out &&
3522 - test_line_count = 3 out &&
3523 - git ls-files -u >out &&
3524 - test_line_count = 0 out &&
3525 - git ls-files -m >out &&
3526 - test_line_count = 1 out &&
3527 - git ls-files -o >out &&
3528 - test_line_count = 3 out
3529 - )
3530 -'
3531 -
3532 -# Testcase 11d, Avoid losing not-up-to-date with rename + D/F conflict
3533 -# Commit O: z/a, x/{b,c_v1}
3534 -# Commit A: z/{a,c_v1}, x/b, and z/c_v1 has uncommitted mods
3535 -# Commit B: y/{a,c/d}, x/{b,c_v2}
3536 -# Expected: D/F: y/c_v2 vs y/c/d) +
3537 -# Warning_Msg("Refusing to lose dirty file at z/c) +
3538 -# y/{a,c~HEAD,c/d}, x/b, now-untracked z/c_v1 with uncommitted mods
3539 -
3540 -test_expect_success '11d-setup: Avoid losing not-uptodate with rename + D/F conflict' '
3541 - test_create_repo 11d &&
3542 - (
3543 - cd 11d &&
3544 -
3545 - mkdir z x &&
3546 - echo a >z/a &&
3547 - echo b >x/b &&
3548 - test_seq 1 10 >x/c &&
3549 - git add z x &&
3550 - test_tick &&
3551 - git commit -m "O" &&
3552 -
3553 - git branch O &&
3554 - git branch A &&
3555 - git branch B &&
3556 -
3557 - git checkout A &&
3558 - git mv x/c z/c &&
3559 - test_tick &&
3560 - git commit -m "A" &&
3561 -
3562 - git checkout B &&
3563 - git mv z y &&
3564 - mkdir y/c &&
3565 - echo d >y/c/d &&
3566 - echo 11 >>x/c &&
3567 - git add x/c y/c/d &&
3568 - test_tick &&
3569 - git commit -m "B"
3570 - )
3571 -'
3572 -
3573 -test_expect_success '11d-check: Avoid losing not-uptodate with rename + D/F conflict' '
3574 - (
3575 - cd 11d &&
3576 -
3577 - git checkout A^0 &&
3578 - echo stuff >>z/c &&
3579 -
3580 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3581 - test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3582 -
3583 - grep -q stuff z/c &&
3584 - test_seq 1 10 >expected &&
3585 - echo stuff >>expected &&
3586 - test_cmp expected z/c
3587 -
3588 - git ls-files -s >out &&
3589 - test_line_count = 4 out &&
3590 - git ls-files -u >out &&
3591 - test_line_count = 1 out &&
3592 - git ls-files -o >out &&
3593 - test_line_count = 5 out &&
3594 -
3595 - git rev-parse >actual \
3596 - :0:x/b :0:y/a :0:y/c/d :3:y/c &&
3597 - git rev-parse >expect \
3598 - O:x/b O:z/a B:y/c/d B:x/c &&
3599 - test_cmp expect actual &&
3600 -
3601 - git hash-object y/c~HEAD >actual &&
3602 - git rev-parse B:x/c >expect &&
3603 - test_cmp expect actual
3604 - )
3605 -'
3606 -
3607 -# Testcase 11e, Avoid deleting not-up-to-date with dir rename/rename(1to2)/add
3608 -# Commit O: z/{a,b}, x/{c_1,d}
3609 -# Commit A: y/{a,b,c_2}, x/d, w/c_1, and y/c_2 has uncommitted mods
3610 -# Commit B: z/{a,b,c_1}, x/d
3611 -# Expected: Failed Merge; y/{a,b} + x/d +
3612 -# CONFLICT(rename/rename) x/c_1 -> w/c_1 vs y/c_1 +
3613 -# ERROR_MSG(Refusing to lose dirty file at y/c)
3614 -# y/c~B^0 has O:x/c_1 contents
3615 -# y/c~HEAD has A:y/c_2 contents
3616 -# y/c has dirty file from before merge
3617 -
3618 -test_expect_success '11e-setup: Avoid deleting not-uptodate with dir rename/rename(1to2)/add' '
3619 - test_create_repo 11e &&
3620 - (
3621 - cd 11e &&
3622 -
3623 - mkdir z x &&
3624 - echo a >z/a &&
3625 - echo b >z/b &&
3626 - echo c >x/c &&
3627 - echo d >x/d &&
3628 - git add z x &&
3629 - test_tick &&
3630 - git commit -m "O" &&
3631 -
3632 - git branch O &&
3633 - git branch A &&
3634 - git branch B &&
3635 -
3636 - git checkout A &&
3637 - git mv z/ y/ &&
3638 - echo different >y/c &&
3639 - mkdir w &&
3640 - git mv x/c w/ &&
3641 - git add y/c &&
3642 - test_tick &&
3643 - git commit -m "A" &&
3644 -
3645 - git checkout B &&
3646 - git mv x/c z/ &&
3647 - test_tick &&
3648 - git commit -m "B"
3649 - )
3650 -'
3651 -
3652 -test_expect_success '11e-check: Avoid deleting not-uptodate with dir rename/rename(1to2)/add' '
3653 - (
3654 - cd 11e &&
3655 -
3656 - git checkout A^0 &&
3657 - echo mods >>y/c &&
3658 -
3659 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3660 - test_i18ngrep "CONFLICT (rename/rename)" out &&
3661 - test_i18ngrep "Refusing to lose dirty file at y/c" out &&
3662 -
3663 - git ls-files -s >out &&
3664 - test_line_count = 7 out &&
3665 - git ls-files -u >out &&
3666 - test_line_count = 4 out &&
3667 - git ls-files -o >out &&
3668 - test_line_count = 4 out &&
3669 -
3670 - echo different >expected &&
3671 - echo mods >>expected &&
3672 - test_cmp expected y/c &&
3673 -
3674 - git rev-parse >actual \
3675 - :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&
3676 - git rev-parse >expect \
3677 - O:z/a O:z/b O:x/d O:x/c O:x/c A:y/c O:x/c &&
3678 - test_cmp expect actual &&
3679 -
3680 - git hash-object >actual \
3681 - y/c~B^0 y/c~HEAD &&
3682 - git rev-parse >expect \
3683 - O:x/c A:y/c &&
3684 - test_cmp expect actual
3685 - )
3686 -'
3687 -
3688 -# Testcase 11f, Avoid deleting not-up-to-date w/ dir rename/rename(2to1)
3689 -# Commit O: z/{a,b}, x/{c_1,d_2}
3690 -# Commit A: y/{a,b,wham_1}, x/d_2, except y/wham has uncommitted mods
3691 -# Commit B: z/{a,b,wham_2}, x/c_1
3692 -# Expected: Failed Merge; y/{a,b} + untracked y/{wham~B^0,wham~B^HEAD} +
3693 -# y/wham with dirty changes from before merge +
3694 -# CONFLICT(rename/rename) x/c vs x/d -> y/wham
3695 -# ERROR_MSG(Refusing to lose dirty file at y/wham)
3696 -
3697 -test_expect_success '11f-setup: Avoid deleting not-uptodate with dir rename/rename(2to1)' '
3698 - test_create_repo 11f &&
3699 - (
3700 - cd 11f &&
3701 -
3702 - mkdir z x &&
3703 - echo a >z/a &&
3704 - echo b >z/b &&
3705 - test_seq 1 10 >x/c &&
3706 - echo d >x/d &&
3707 - git add z x &&
3708 - test_tick &&
3709 - git commit -m "O" &&
3710 -
3711 - git branch O &&
3712 - git branch A &&
3713 - git branch B &&
3714 -
3715 - git checkout A &&
3716 - git mv z/ y/ &&
3717 - git mv x/c y/wham &&
3718 - test_tick &&
3719 - git commit -m "A" &&
3720 -
3721 - git checkout B &&
3722 - git mv x/d z/wham &&
3723 - test_tick &&
3724 - git commit -m "B"
3725 - )
3726 -'
3727 -
3728 -test_expect_success '11f-check: Avoid deleting not-uptodate with dir rename/rename(2to1)' '
3729 - (
3730 - cd 11f &&
3731 -
3732 - git checkout A^0 &&
3733 - echo important >>y/wham &&
3734 -
3735 - test_must_fail git merge -s recursive B^0 >out 2>err &&
3736 - test_i18ngrep "CONFLICT (rename/rename)" out &&
3737 - test_i18ngrep "Refusing to lose dirty file at y/wham" out &&
3738 -
3739 - git ls-files -s >out &&
3740 - test_line_count = 4 out &&
3741 - git ls-files -u >out &&
3742 - test_line_count = 2 out &&
3743 - git ls-files -o >out &&
3744 - test_line_count = 4 out &&
3745 -
3746 - test_seq 1 10 >expected &&
3747 - echo important >>expected &&
3748 - test_cmp expected y/wham &&
3749 -
3750 - test_must_fail git rev-parse :1:y/wham &&
3751 - git hash-object >actual \
3752 - y/wham~B^0 y/wham~HEAD &&
3753 - git rev-parse >expect \
3754 - O:x/d O:x/c &&
3755 - test_cmp expect actual &&
3756 -
3757 - git rev-parse >actual \
3758 - :0:y/a :0:y/b :2:y/wham :3:y/wham &&
3759 - git rev-parse >expect \
3760 - O:z/a O:z/b O:x/c O:x/d &&
3761 - test_cmp expect actual
3762 - )
3763 -'
3764 -
3765 -###########################################################################
3766 -# SECTION 12: Everything else
3767 -#
3768 -# Tests suggested by others. Tests added after implementation completed
3769 -# and submitted. Grab bag.
3770 -###########################################################################
3771 -
3772 -# Testcase 12a, Moving one directory hierarchy into another
3773 -# (Related to testcase 9a)
3774 -# Commit O: node1/{leaf1,leaf2}, node2/{leaf3,leaf4}
3775 -# Commit A: node1/{leaf1,leaf2,node2/{leaf3,leaf4}}
3776 -# Commit B: node1/{leaf1,leaf2,leaf5}, node2/{leaf3,leaf4,leaf6}
3777 -# Expected: node1/{leaf1,leaf2,leaf5,node2/{leaf3,leaf4,leaf6}}
3778 -
3779 -test_expect_success '12a-setup: Moving one directory hierarchy into another' '
3780 - test_create_repo 12a &&
3781 - (
3782 - cd 12a &&
3783 -
3784 - mkdir -p node1 node2 &&
3785 - echo leaf1 >node1/leaf1 &&
3786 - echo leaf2 >node1/leaf2 &&
3787 - echo leaf3 >node2/leaf3 &&
3788 - echo leaf4 >node2/leaf4 &&
3789 - git add node1 node2 &&
3790 - test_tick &&
3791 - git commit -m "O" &&
3792 -
3793 - git branch O &&
3794 - git branch A &&
3795 - git branch B &&
3796 -
3797 - git checkout A &&
3798 - git mv node2/ node1/ &&
3799 - test_tick &&
3800 - git commit -m "A" &&
3801 -
3802 - git checkout B &&
3803 - echo leaf5 >node1/leaf5 &&
3804 - echo leaf6 >node2/leaf6 &&
3805 - git add node1 node2 &&
3806 - test_tick &&
3807 - git commit -m "B"
3808 - )
3809 -'
3810 -
3811 -test_expect_success '12a-check: Moving one directory hierarchy into another' '
3812 - (
3813 - cd 12a &&
3814 -
3815 - git checkout A^0 &&
3816 -
3817 - git merge -s recursive B^0 &&
3818 -
3819 - git ls-files -s >out &&
3820 - test_line_count = 6 out &&
3821 -
3822 - git rev-parse >actual \
3823 - HEAD:node1/leaf1 HEAD:node1/leaf2 HEAD:node1/leaf5 \
3824 - HEAD:node1/node2/leaf3 \
3825 - HEAD:node1/node2/leaf4 \
3826 - HEAD:node1/node2/leaf6 &&
3827 - git rev-parse >expect \
3828 - O:node1/leaf1 O:node1/leaf2 B:node1/leaf5 \
3829 - O:node2/leaf3 \
3830 - O:node2/leaf4 \
3831 - B:node2/leaf6 &&
3832 - test_cmp expect actual
3833 - )
3834 -'
3835 -
3836 -# Testcase 12b, Moving two directory hierarchies into each other
3837 -# (Related to testcases 1c and 12c)
3838 -# Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
3839 -# Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}}
3840 -# Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}}
3841 -# Expected: node1/node2/node1/{leaf1, leaf2},
3842 -# node2/node1/node2/{leaf3, leaf4}
3843 -# NOTE: Without directory renames, we would expect
3844 -# node2/node1/{leaf1, leaf2},
3845 -# node1/node2/{leaf3, leaf4}
3846 -# with directory rename detection, we note that
3847 -# commit A renames node2/ -> node1/node2/
3848 -# commit B renames node1/ -> node2/node1/
3849 -# therefore, applying those directory renames to the initial result
3850 -# (making all four paths experience a transitive renaming), yields
3851 -# the expected result.
3852 -#
3853 -# You may ask, is it weird to have two directories rename each other?
3854 -# To which, I can do no more than shrug my shoulders and say that
3855 -# even simple rules give weird results when given weird inputs.
3856 -
3857 -test_expect_success '12b-setup: Moving one directory hierarchy into another' '
3858 - test_create_repo 12b &&
3859 - (
3860 - cd 12b &&
3861 -
3862 - mkdir -p node1 node2 &&
3863 - echo leaf1 >node1/leaf1 &&
3864 - echo leaf2 >node1/leaf2 &&
3865 - echo leaf3 >node2/leaf3 &&
3866 - echo leaf4 >node2/leaf4 &&
3867 - git add node1 node2 &&
3868 - test_tick &&
3869 - git commit -m "O" &&
3870 -
3871 - git branch O &&
3872 - git branch A &&
3873 - git branch B &&
3874 -
3875 - git checkout A &&
3876 - git mv node2/ node1/ &&
3877 - test_tick &&
3878 - git commit -m "A" &&
3879 -
3880 - git checkout B &&
3881 - git mv node1/ node2/ &&
3882 - test_tick &&
3883 - git commit -m "B"
3884 - )
3885 -'
3886 -
3887 -test_expect_success '12b-check: Moving one directory hierarchy into another' '
3888 - (
3889 - cd 12b &&
3890 -
3891 - git checkout A^0 &&
3892 -
3893 - git merge -s recursive B^0 &&
3894 -
3895 - git ls-files -s >out &&
3896 - test_line_count = 4 out &&
3897 -
3898 - git rev-parse >actual \
3899 - HEAD:node1/node2/node1/leaf1 \
3900 - HEAD:node1/node2/node1/leaf2 \
3901 - HEAD:node2/node1/node2/leaf3 \
3902 - HEAD:node2/node1/node2/leaf4 &&
3903 - git rev-parse >expect \
3904 - O:node1/leaf1 \
3905 - O:node1/leaf2 \
3906 - O:node2/leaf3 \
3907 - O:node2/leaf4 &&
3908 - test_cmp expect actual
3909 - )
3910 -'
3911 -
3912 -# Testcase 12c, Moving two directory hierarchies into each other w/ content merge
3913 -# (Related to testcase 12b)
3914 -# Commit O: node1/{ leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
3915 -# Commit A: node1/{ leaf1_2, leaf2_2, node2/{leaf3_2, leaf4_2}}
3916 -# Commit B: node2/{node1/{leaf1_3, leaf2_3}, leaf3_3, leaf4_3}
3917 -# Expected: Content merge conflicts for each of:
3918 -# node1/node2/node1/{leaf1, leaf2},
3919 -# node2/node1/node2/{leaf3, leaf4}
3920 -# NOTE: This is *exactly* like 12c, except that every path is modified on
3921 -# each side of the merge.
3922 -
3923 -test_expect_success '12c-setup: Moving one directory hierarchy into another w/ content merge' '
3924 - test_create_repo 12c &&
3925 - (
3926 - cd 12c &&
3927 -
3928 - mkdir -p node1 node2 &&
3929 - printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
3930 - printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&
3931 - printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&
3932 - printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&
3933 - git add node1 node2 &&
3934 - test_tick &&
3935 - git commit -m "O" &&
3936 -
3937 - git branch O &&
3938 - git branch A &&
3939 - git branch B &&
3940 -
3941 - git checkout A &&
3942 - git mv node2/ node1/ &&
3943 - for i in `git ls-files`; do echo side A >>$i; done &&
3944 - git add -u &&
3945 - test_tick &&
3946 - git commit -m "A" &&
3947 -
3948 - git checkout B &&
3949 - git mv node1/ node2/ &&
3950 - for i in `git ls-files`; do echo side B >>$i; done &&
3951 - git add -u &&
3952 - test_tick &&
3953 - git commit -m "B"
3954 - )
3955 -'
3956 -
3957 -test_expect_success '12c-check: Moving one directory hierarchy into another w/ content merge' '
3958 - (
3959 - cd 12c &&
3960 -
3961 - git checkout A^0 &&
3962 -
3963 - test_must_fail git merge -s recursive B^0 &&
3964 -
3965 - git ls-files -u >out &&
3966 - test_line_count = 12 out &&
3967 -
3968 - git rev-parse >actual \
3969 - :1:node1/node2/node1/leaf1 \
3970 - :1:node1/node2/node1/leaf2 \
3971 - :1:node2/node1/node2/leaf3 \
3972 - :1:node2/node1/node2/leaf4 \
3973 - :2:node1/node2/node1/leaf1 \
3974 - :2:node1/node2/node1/leaf2 \
3975 - :2:node2/node1/node2/leaf3 \
3976 - :2:node2/node1/node2/leaf4 \
3977 - :3:node1/node2/node1/leaf1 \
3978 - :3:node1/node2/node1/leaf2 \
3979 - :3:node2/node1/node2/leaf3 \
3980 - :3:node2/node1/node2/leaf4 &&
3981 - git rev-parse >expect \
3982 - O:node1/leaf1 \
3983 - O:node1/leaf2 \
3984 - O:node2/leaf3 \
3985 - O:node2/leaf4 \
3986 - A:node1/leaf1 \
3987 - A:node1/leaf2 \
3988 - A:node1/node2/leaf3 \
3989 - A:node1/node2/leaf4 \
3990 - B:node2/node1/leaf1 \
3991 - B:node2/node1/leaf2 \
3992 - B:node2/leaf3 \
3993 - B:node2/leaf4 &&
3994 - test_cmp expect actual
3995 - )
3996 -'
3997 -
3998 -test_done
t/t7607-merge-overwrite.sh
+1 -1
@@ -92,7 +92,7 @@ test_expect_success 'will not overwrite removed file with staged changes' '
92 test_cmp important c1.c
93 '
94
95 -test_expect_success 'will not overwrite unstaged changes in renamed file' '
95 +test_expect_failure 'will not overwrite unstaged changes in renamed file' '
96 git reset --hard c1 &&
97 git mv c1.c other.c &&
98 git commit -m rename &&
unpack-trees.c
+2 -2
@@ -1509,8 +1509,8 @@ static int verify_uptodate_1(const struct cache_entry *ce,
1509 add_rejected_path(o, error_type, ce->name);
1510 }
1511
1512 -int verify_uptodate(const struct cache_entry *ce,
1513 - struct unpack_trees_options *o)
1512 +static int verify_uptodate(const struct cache_entry *ce,
1513 + struct unpack_trees_options *o)
1514 {
1515 if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
1516 return 0;
unpack-trees.h
-4
@@ -1,7 +1,6 @@
1 #ifndef UNPACK_TREES_H
2 #define UNPACK_TREES_H
3
4 -#include "tree-walk.h"
4 #include "string-list.h"
5
6 #define MAX_UNPACK_TREES 8
@@ -79,9 +78,6 @@ struct unpack_trees_options {
78 extern int unpack_trees(unsigned n, struct tree_desc *t,
79 struct unpack_trees_options *options);
80
82 -int verify_uptodate(const struct cache_entry *ce,
83 - struct unpack_trees_options *o);
84 -
81 int threeway_merge(const struct cache_entry * const *stages,
82 struct unpack_trees_options *o);
83 int twoway_merge(const struct cache_entry * const *src,