From f15652d90c37ca56db08d325c871f2cc8f7d509e Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Fri, 9 Jul 2010 07:10:51 -0600 Subject: Add additional testcases for D/F conflicts Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t6035-merge-dir-to-symlink.sh | 64 ++++++++++++++++++++++++++++++++++++++--- t/t9350-fast-export.sh | 24 ++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh index 3202e1de6..761ad9d15 100755 --- a/t/t6035-merge-dir-to-symlink.sh +++ b/t/t6035-merge-dir-to-symlink.sh @@ -48,7 +48,7 @@ test_expect_success 'setup for merge test' ' git tag baseline ' -test_expect_success 'do not lose a/b-2/c/d in merge (resolve)' ' +test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (resolve)' ' git reset --hard && git checkout baseline^0 && git merge -s resolve master && @@ -56,7 +56,7 @@ test_expect_success 'do not lose a/b-2/c/d in merge (resolve)' ' test -f a/b-2/c/d ' -test_expect_failure 'do not lose a/b-2/c/d in merge (recursive)' ' +test_expect_failure 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recursive)' ' git reset --hard && git checkout baseline^0 && git merge -s recursive master && @@ -64,6 +64,54 @@ test_expect_failure 'do not lose a/b-2/c/d in merge (recursive)' ' test -f a/b-2/c/d ' +test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (resolve)' ' + git reset --hard && + git checkout master^0 && + git merge -s resolve baseline^0 && + test -h a/b && + test -f a/b-2/c/d +' + +test_expect_failure 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recursive)' ' + git reset --hard && + git checkout master^0 && + git merge -s recursive baseline^0 && + test -h a/b && + test -f a/b-2/c/d +' + +test_expect_failure 'do not lose untracked in merge (resolve)' ' + git reset --hard && + git checkout baseline^0 && + >a/b/c/e && + test_must_fail git merge -s resolve master && + test -f a/b/c/e && + test -f a/b-2/c/d +' + +test_expect_success 'do not lose untracked in merge (recursive)' ' + git reset --hard && + git checkout baseline^0 && + >a/b/c/e && + test_must_fail git merge -s recursive master && + test -f a/b/c/e && + test -f a/b-2/c/d +' + +test_expect_success 'do not lose modifications in merge (resolve)' ' + git reset --hard && + git checkout baseline^0 && + echo more content >>a/b/c/d && + test_must_fail git merge -s resolve master +' + +test_expect_success 'do not lose modifications in merge (recursive)' ' + git reset --hard && + git checkout baseline^0 && + echo more content >>a/b/c/d && + test_must_fail git merge -s recursive master +' + test_expect_success 'setup a merge where dir a/b-2 changed to symlink' ' git reset --hard && git checkout start^0 && @@ -74,7 +122,7 @@ test_expect_success 'setup a merge where dir a/b-2 changed to symlink' ' git tag test2 ' -test_expect_success 'merge should not have conflicts (resolve)' ' +test_expect_success 'merge should not have D/F conflicts (resolve)' ' git reset --hard && git checkout baseline^0 && git merge -s resolve test2 && @@ -82,7 +130,7 @@ test_expect_success 'merge should not have conflicts (resolve)' ' test -f a/b/c/d ' -test_expect_failure 'merge should not have conflicts (recursive)' ' +test_expect_failure 'merge should not have D/F conflicts (recursive)' ' git reset --hard && git checkout baseline^0 && git merge -s recursive test2 && @@ -90,4 +138,12 @@ test_expect_failure 'merge should not have conflicts (recursive)' ' test -f a/b/c/d ' +test_expect_failure 'merge should not have F/D conflicts (recursive)' ' + git reset --hard && + git checkout -b foo test2 && + git merge -s recursive baseline^0 && + test -h a/b-2 && + test -f a/b/c/d +' + test_done diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index d43f37cca..69179c612 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -376,4 +376,28 @@ test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj' test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag' test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' +test_expect_failure 'directory becomes symlink' ' + git init dirtosymlink && + git init result && + ( + cd dirtosymlink && + mkdir foo && + mkdir bar && + echo hello > foo/world && + echo hello > bar/world && + git add foo/world bar/world && + git commit -q -mone && + git rm -r foo && + ln -s bar foo && + git add foo && + git commit -q -mtwo + ) && + ( + cd dirtosymlink && + git fast-export master -- foo | + (cd ../result && git fast-import --quiet) + ) && + (cd result && git show master:foo) +' + test_done -- cgit v1.2.1 From f433f70547ebf038a862ca72565ae42e50d4adfa Mon Sep 17 00:00:00 2001 From: Alexander Gladysh Date: Fri, 9 Jul 2010 07:10:52 -0600 Subject: Add a rename + D/F conflict testcase This is a simple testcase where both sides of the rename are paths involved in (separate) D/F merge conflicts Signed-off-by: Alexander Gladysh Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t3509-cherry-pick-merge-df.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 t/t3509-cherry-pick-merge-df.sh diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh new file mode 100755 index 000000000..7c05e1684 --- /dev/null +++ b/t/t3509-cherry-pick-merge-df.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +test_description='Test cherry-pick with directory/file conflicts' +. ./test-lib.sh + +test_expect_success 'Setup rename across paths each below D/F conflicts' ' + mkdir a && + >a/f && + git add a && + git commit -m a && + + mkdir b && + ln -s ../a b/a && + git add b && + git commit -m b && + + git checkout -b branch && + rm b/a && + mv a b/a && + ln -s b/a a && + git add . && + git commit -m swap && + + >f1 && + git add f1 && + git commit -m f1 +' + +test_expect_failure 'Cherry-pick succeeds with rename across D/F conflicts' ' + git reset --hard && + git checkout master^0 && + git cherry-pick branch +' + +test_done -- cgit v1.2.1 From 37348937ff391f01981e8af10b2f615268fd2509 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Fri, 9 Jul 2010 07:10:53 -0600 Subject: merge-recursive: Fix D/F conflicts The D/F conflicts that can be automatically resolved (file or directory unmodified on one side of history), have the nice property that process_entry() can correctly handle all subpaths of the D/F conflict. In the case of D->F conversions, it will correctly delete all non-conflicting files below the relevant directory and the directory itself (note that both untracked and conflicting files below the directory will prevent its removal). So if we handle D/F conflicts after all other conflicts, they become fairly simple to handle -- we just need to check for whether or not a path (file/directory) is in the way of creating the new content. We do this by having process_entry() defer handling such entries to a subsequent process_df_entry() step. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- merge-recursive.c | 93 ++++++++++++++++++++++++++++++++++------- t/t6035-merge-dir-to-symlink.sh | 6 +-- 2 files changed, 80 insertions(+), 19 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 917397ca7..c8d536219 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1072,6 +1072,7 @@ static int process_entry(struct merge_options *o, unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode); unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode); + entry->processed = 1; if (o_sha && (!a_sha || !b_sha)) { /* Case A: Deleted in one */ if ((!a_sha && !b_sha) || @@ -1104,33 +1105,28 @@ static int process_entry(struct merge_options *o, } else if ((!o_sha && a_sha && !b_sha) || (!o_sha && !a_sha && b_sha)) { /* Case B: Added in one. */ - const char *add_branch; - const char *other_branch; unsigned mode; const unsigned char *sha; - const char *conf; if (a_sha) { - add_branch = o->branch1; - other_branch = o->branch2; mode = a_mode; sha = a_sha; - conf = "file/directory"; } else { - add_branch = o->branch2; - other_branch = o->branch1; mode = b_mode; sha = b_sha; - conf = "directory/file"; } if (string_list_has_string(&o->current_directory_set, path)) { - const char *new_path = unique_path(o, path, add_branch); - clean_merge = 0; - output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " - "Adding %s as %s", - conf, path, other_branch, path, new_path); - remove_file(o, 0, path, 0); - update_file(o, 0, sha, mode, new_path); + /* Handle D->F conflicts after all subfiles */ + entry->processed = 0; + /* But get any file out of the way now, so conflicted + * entries below the directory of the same name can + * be put in the working directory. + */ + if (a_sha) + output(o, 2, "Removing %s", path); + /* do not touch working file if it did not exist */ + remove_file(o, 0, path, !a_sha); + return 1; /* Assume clean till processed */ } else { output(o, 2, "Adding %s", path); update_file(o, 1, sha, mode, path); @@ -1178,6 +1174,64 @@ static int process_entry(struct merge_options *o, return clean_merge; } +/* + * Per entry merge function for D/F conflicts, to be called only after + * all files below dir have been processed. We do this because in the + * cases we can cleanly resolve D/F conflicts, process_entry() can clean + * out all the files below the directory for us. + */ +static int process_df_entry(struct merge_options *o, + const char *path, struct stage_data *entry) +{ + int clean_merge = 1; + unsigned o_mode = entry->stages[1].mode; + unsigned a_mode = entry->stages[2].mode; + unsigned b_mode = entry->stages[3].mode; + unsigned char *o_sha = stage_sha(entry->stages[1].sha, o_mode); + unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode); + unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode); + const char *add_branch; + const char *other_branch; + unsigned mode; + const unsigned char *sha; + const char *conf; + struct stat st; + + /* We currently only handle D->F cases */ + assert((!o_sha && a_sha && !b_sha) || + (!o_sha && !a_sha && b_sha)); + + entry->processed = 1; + + if (a_sha) { + add_branch = o->branch1; + other_branch = o->branch2; + mode = a_mode; + sha = a_sha; + conf = "file/directory"; + } else { + add_branch = o->branch2; + other_branch = o->branch1; + mode = b_mode; + sha = b_sha; + conf = "directory/file"; + } + if (lstat(path, &st) == 0 && S_ISDIR(st.st_mode)) { + const char *new_path = unique_path(o, path, add_branch); + clean_merge = 0; + output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " + "Adding %s as %s", + conf, path, other_branch, path, new_path); + remove_file(o, 0, path, 0); + update_file(o, 0, sha, mode, new_path); + } else { + output(o, 2, "Adding %s", path); + update_file(o, 1, sha, mode, path); + } + + return clean_merge; +} + struct unpack_trees_error_msgs get_porcelain_error_msgs(void) { struct unpack_trees_error_msgs msgs = { @@ -1249,6 +1303,13 @@ int merge_trees(struct merge_options *o, && !process_entry(o, path, e)) clean = 0; } + for (i = 0; i < entries->nr; i++) { + const char *path = entries->items[i].string; + struct stage_data *e = entries->items[i].util; + if (!e->processed + && !process_df_entry(o, path, e)) + clean = 0; + } string_list_clear(re_merge, 0); string_list_clear(re_head, 0); diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh index 761ad9d15..f6972bed0 100755 --- a/t/t6035-merge-dir-to-symlink.sh +++ b/t/t6035-merge-dir-to-symlink.sh @@ -56,7 +56,7 @@ test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (resolv test -f a/b-2/c/d ' -test_expect_failure 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recursive)' ' +test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recursive)' ' git reset --hard && git checkout baseline^0 && git merge -s recursive master && @@ -130,7 +130,7 @@ test_expect_success 'merge should not have D/F conflicts (resolve)' ' test -f a/b/c/d ' -test_expect_failure 'merge should not have D/F conflicts (recursive)' ' +test_expect_success 'merge should not have D/F conflicts (recursive)' ' git reset --hard && git checkout baseline^0 && git merge -s recursive test2 && @@ -138,7 +138,7 @@ test_expect_failure 'merge should not have D/F conflicts (recursive)' ' test -f a/b/c/d ' -test_expect_failure 'merge should not have F/D conflicts (recursive)' ' +test_expect_success 'merge should not have F/D conflicts (recursive)' ' git reset --hard && git checkout -b foo test2 && git merge -s recursive baseline^0 && -- cgit v1.2.1 From 5a2580d62f9aaa30f0acd10df9dbe7a581dd77d9 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Fri, 9 Jul 2010 07:10:54 -0600 Subject: merge_recursive: Fix renames across paths below D/F conflicts The rename logic in process_renames() handles renames and merging of file contents and then marks files as processed. However, there may be higher stage entries left in the index for other reasons (e.g., due to D/F conflicts). By checking for such cases and marking the entry as not processed, it allows process_entry() later to look at it and handle those higher stages. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- merge-recursive.c | 15 +++++++++++++-- t/t3509-cherry-pick-merge-df.sh | 2 +- t/t6020-merge-df.sh | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index c8d536219..b0f055ecd 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1019,14 +1019,25 @@ static int process_renames(struct merge_options *o, if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && - mfi.mode == ren1->pair->two->mode) + mfi.mode == ren1->pair->two->mode) { /* * This messaged is part of * t6022 test. If you change * it update the test too. */ output(o, 3, "Skipped %s (merged same as existing)", ren1_dst); - else { + + /* There may be higher stage entries left + * in the index (e.g. due to a D/F + * conflict) that need to be resolved. + */ + for (i = 1; i <= 3; i++) { + if (!ren1->dst_entry->stages[i].mode) + continue; + ren1->dst_entry->processed = 0; + break; + } + } else { if (mfi.merge || !mfi.clean) output(o, 1, "Renaming %s => %s", ren1_src, ren1_dst); if (mfi.merge) diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh index 7c05e1684..6e7ef8483 100755 --- a/t/t3509-cherry-pick-merge-df.sh +++ b/t/t3509-cherry-pick-merge-df.sh @@ -26,7 +26,7 @@ test_expect_success 'Setup rename across paths each below D/F conflicts' ' git commit -m f1 ' -test_expect_failure 'Cherry-pick succeeds with rename across D/F conflicts' ' +test_expect_success 'Cherry-pick succeeds with rename across D/F conflicts' ' git reset --hard && git checkout master^0 && git cherry-pick branch diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh index e71c687f2..490d39711 100755 --- a/t/t6020-merge-df.sh +++ b/t/t6020-merge-df.sh @@ -22,7 +22,7 @@ git commit -m "File: dir"' test_expect_code 1 'Merge with d/f conflicts' 'git merge "merge msg" B master' -test_expect_failure 'F/D conflict' ' +test_expect_success 'F/D conflict' ' git reset --hard && git checkout master && rm .git/index && -- cgit v1.2.1 From 060df624228187c77ca53a437ae0e9896076f045 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Fri, 9 Jul 2010 07:10:55 -0600 Subject: fast-export: Fix output order of D/F changes The fast-import stream format requires incremental changes which take place immediately, meaning that for D->F conversions all files below the relevant directory must be deleted before the resulting file of the same name is created. Reversing the order can result in fast-import silently deleting the file right after creating it, resulting in the file missing from the resulting repository. We correct this by first sorting the diff_queue_struct in depth-first order. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/fast-export.c | 29 +++++++++++++++++++++++++++++ t/t9350-fast-export.sh | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/builtin/fast-export.c b/builtin/fast-export.c index c6dd71a7b..965e90e5e 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -147,10 +147,39 @@ static void handle_object(const unsigned char *sha1) free(buf); } +static int depth_first(const void *a_, const void *b_) +{ + const struct diff_filepair *a = *((const struct diff_filepair **)a_); + const struct diff_filepair *b = *((const struct diff_filepair **)b_); + const char *name_a, *name_b; + int len_a, len_b, len; + int cmp; + + name_a = a->one ? a->one->path : a->two->path; + name_b = b->one ? b->one->path : b->two->path; + + len_a = strlen(name_a); + len_b = strlen(name_b); + len = (len_a < len_b) ? len_a : len_b; + + /* strcmp will sort 'd' before 'd/e', we want 'd/e' before 'd' */ + cmp = memcmp(name_a, name_b, len); + if (cmp) + return cmp; + return (len_b - len_a); +} + static void show_filemodify(struct diff_queue_struct *q, struct diff_options *options, void *data) { int i; + + /* + * Handle files below a directory first, in case they are all deleted + * and the directory changes to a file or symlink. + */ + qsort(q->queue, q->nr, sizeof(q->queue[0]), depth_first); + for (i = 0; i < q->nr; i++) { struct diff_filespec *ospec = q->queue[i]->one; struct diff_filespec *spec = q->queue[i]->two; diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 69179c612..1ee1461c9 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -376,7 +376,7 @@ test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj' test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag' test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' -test_expect_failure 'directory becomes symlink' ' +test_expect_success 'directory becomes symlink' ' git init dirtosymlink && git init result && ( -- cgit v1.2.1 From 253fb5f8897d988d93ce276f8147c2964da3eefb Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Fri, 9 Jul 2010 07:10:56 -0600 Subject: fast-import: Improve robustness when D->F changes provided in wrong order When older versions of fast-export came across a directory changing to a symlink (or regular file), it would output the changes in the form M 120000 :239821 dir-changing-to-symlink D dir-changing-to-symlink/filename1 When fast-import sees the first line, it deletes the directory named dir-changing-to-symlink (and any files below it) and creates a symlink in its place. When fast-import came across the second line, it was previously trying to remove the file and relevant leading directories in tree_content_remove(), and as a side effect it would delete the symlink that was just created. This resulted in the symlink silently missing from the resulting repository. To improve robustness, we ignore file deletions underneath directory names that correspond to non-directories. This can also be viewed as a minor optimization: since there cannot be a file and a directory with the same name in the same directory, the file clearly can't exist so nothing needs to be done to delete it. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- fast-import.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fast-import.c b/fast-import.c index 309f2c58a..75ed738b7 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1528,6 +1528,14 @@ static int tree_content_remove( for (i = 0; i < t->entry_count; i++) { e = t->entries[i]; if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) { + if (slash1 && !S_ISDIR(e->versions[1].mode)) + /* + * If p names a file in some subdirectory, and a + * file or symlink matching the name of the + * parent directory of p exists, then p cannot + * exist and need not be deleted. + */ + return 1; if (!slash1 || !S_ISDIR(e->versions[1].mode)) goto del_entry; if (!e->tree) -- cgit v1.2.1 From 2fd1ea14056cb630bbf99588b78d7d68f51907ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Tue, 27 Jul 2010 16:54:58 +0000 Subject: t/t6035-merge-dir-to-symlink.sh: Remove TODO on passing test Various merge-recursive cases were fixed in "merge-recursive: Fix D/F conflicts" by Elijah Newren. Some tests were changed from test_expect_failure to test_expect_success, but one fell through the cracks. Change that test to use test_expect_success. Signed-off-by: Junio C Hamano --- t/t6035-merge-dir-to-symlink.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh index f6972bed0..40c4f4a9b 100755 --- a/t/t6035-merge-dir-to-symlink.sh +++ b/t/t6035-merge-dir-to-symlink.sh @@ -72,7 +72,7 @@ test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (resolv test -f a/b-2/c/d ' -test_expect_failure 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recursive)' ' +test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recursive)' ' git reset --hard && git checkout master^0 && git merge -s recursive baseline^0 && -- cgit v1.2.1 From dd5685818bca9b0cadc61a87c6470fa7df227302 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 12 Aug 2010 20:09:12 -0600 Subject: Mark tests that use symlinks as needing SYMLINKS prerequisite Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t3509-cherry-pick-merge-df.sh | 4 ++-- t/t9350-fast-export.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh index 6e7ef8483..a5ccdbf8f 100755 --- a/t/t3509-cherry-pick-merge-df.sh +++ b/t/t3509-cherry-pick-merge-df.sh @@ -3,7 +3,7 @@ test_description='Test cherry-pick with directory/file conflicts' . ./test-lib.sh -test_expect_success 'Setup rename across paths each below D/F conflicts' ' +test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' ' mkdir a && >a/f && git add a && @@ -26,7 +26,7 @@ test_expect_success 'Setup rename across paths each below D/F conflicts' ' git commit -m f1 ' -test_expect_success 'Cherry-pick succeeds with rename across D/F conflicts' ' +test_expect_success SYMLINKS 'Cherry-pick succeeds with rename across D/F conflicts' ' git reset --hard && git checkout master^0 && git cherry-pick branch diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 1ee1461c9..27aea5c16 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -376,7 +376,7 @@ test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj' test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag' test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' -test_expect_success 'directory becomes symlink' ' +test_expect_success SYMLINKS 'directory becomes symlink' ' git init dirtosymlink && git init result && ( -- cgit v1.2.1 From a3e413675478585206966bdbb7fd7bf24b9d1ea7 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 17 Aug 2010 17:52:27 -0600 Subject: merge-recursive: Fix typo Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- merge-recursive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/merge-recursive.c b/merge-recursive.c index b0f055ecd..52936c35a 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1021,7 +1021,7 @@ static int process_renames(struct merge_options *o, sha_eq(mfi.sha, ren1->pair->two->sha1) && mfi.mode == ren1->pair->two->mode) { /* - * This messaged is part of + * This message is part of * t6022 test. If you change * it update the test too. */ -- cgit v1.2.1 From 5601ba6574cfbd1249a6d38b72159a7d3ccf8315 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 17 Aug 2010 17:53:18 -0600 Subject: t6031: Add a testcase covering multiple renames across a D/F conflict Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t6031-merge-recursive.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index 8a3304fb0..c50ee295a 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -57,4 +57,35 @@ test_expect_success FILEMODE 'verify executable bit on file' ' test -x file2 ' +test_expect_failure 'merging with triple rename across D/F conflict' ' + git reset --hard HEAD && + git checkout -b main && + git rm -rf . && + + echo "just a file" >sub1 && + mkdir -p sub2 && + echo content1 >sub2/file1 && + echo content2 >sub2/file2 && + echo content3 >sub2/file3 && + mkdir simple && + echo base >simple/bar && + git add -A && + test_tick && + git commit -m base && + + git checkout -b other && + echo more >>simple/bar && + test_tick && + git commit -a -m changesimplefile && + + git checkout main && + git rm sub1 && + git mv sub2 sub1 && + test_tick && + git commit -m changefiletodir && + + test_tick && + git merge other +' + test_done -- cgit v1.2.1 From ae745487ad7a4ceca0e903da6df21be2c1ebfc29 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 17 Aug 2010 17:53:19 -0600 Subject: merge-recursive: Fix multiple file rename across D/F conflict In 5a2580d (merge_recursive: Fix renames across paths below D/F conflicts 2010-07-09), detection was added for renames across paths involved in a directory<->file conflict. However, the change accidentally involved reusing an outer loop index ('i') in an inner loop, changing its values and causing a slightly different type of breakage for cases where there are multiple renames across the D/F conflict. Fix by creating a new temporary variable 'i'. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- merge-recursive.c | 1 + t/t6031-merge-recursive.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/merge-recursive.c b/merge-recursive.c index 52936c35a..250e14035 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1020,6 +1020,7 @@ static int process_renames(struct merge_options *o, if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && mfi.mode == ren1->pair->two->mode) { + int i; /* * This message is part of * t6022 test. If you change diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index c50ee295a..bd75e0e64 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -57,7 +57,7 @@ test_expect_success FILEMODE 'verify executable bit on file' ' test -x file2 ' -test_expect_failure 'merging with triple rename across D/F conflict' ' +test_expect_success 'merging with triple rename across D/F conflict' ' git reset --hard HEAD && git checkout -b main && git rm -rf . && -- cgit v1.2.1 From 96ecac677aa84639a0b8e0aa0d781b197a2d16fe Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Fri, 20 Aug 2010 06:55:40 -0600 Subject: merge-recursive: Avoid excessive output for and reprocessing of renames In 5a2580d (merge_recursive: Fix renames across paths below D/F conflicts 2010-07-09) and ae74548 (merge-recursive: Fix multiple file rename across D/F conflict 2010-08-17), renames across D/F conflicts were fixed by making process_renames() consider as unprocessed renames whose dst_entry "still" had higher stage entries. The assumption was that those higher stage entries would have been cleared out of dst_entry by that point in cases where the conflict could be resolved (normal renames with no D/F conflicts). That is not the case -- higher stage entries will remain in all cases. Fix this by checking for higher stage entries corresponding to D/F conflicts, namely that stages 2 and 3 have exactly one nonzero mode between them. The nonzero mode stage corresponds to a file at the path, while the stage with a zero mode will correspond to a directory at that path (since rename/delete conflicts will have already been handled before this codepath is reached.) Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- merge-recursive.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 250e14035..a576f9b10 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1020,7 +1020,6 @@ static int process_renames(struct merge_options *o, if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && mfi.mode == ren1->pair->two->mode) { - int i; /* * This message is part of * t6022 test. If you change @@ -1032,12 +1031,9 @@ static int process_renames(struct merge_options *o, * in the index (e.g. due to a D/F * conflict) that need to be resolved. */ - for (i = 1; i <= 3; i++) { - if (!ren1->dst_entry->stages[i].mode) - continue; + if (!ren1->dst_entry->stages[2].mode != + !ren1->dst_entry->stages[3].mode) ren1->dst_entry->processed = 0; - break; - } } else { if (mfi.merge || !mfi.clean) output(o, 1, "Renaming %s => %s", ren1_src, ren1_dst); -- cgit v1.2.1