diff options
-rw-r--r-- | merge-recursive.c | 48 | ||||
-rwxr-xr-x | t/t6022-merge-rename.sh | 2 | ||||
-rwxr-xr-x | t/t6043-merge-rename-directories.sh | 2 | ||||
-rwxr-xr-x | t/t6046-merge-skip-unneeded-updates.sh | 10 |
4 files changed, 39 insertions, 23 deletions
diff --git a/merge-recursive.c b/merge-recursive.c index f9021dd650..13b4762971 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -780,6 +780,25 @@ static int dir_in_way(const char *path, int check_working_copy, int empty_ok) } /* + * Returns whether path was tracked in the index before the merge started, + * and its oid and mode match the specified values + */ +static int was_tracked_and_matches(struct merge_options *o, const char *path, + const struct object_id *oid, unsigned mode) +{ + int pos = index_name_pos(&o->orig_index, path, strlen(path)); + struct cache_entry *ce; + + if (0 > pos) + /* we were not tracking this path before the merge */ + return 0; + + /* See if the file we were tracking before matches */ + ce = o->orig_index.cache[pos]; + return (oid_eq(&ce->oid, oid) && ce->ce_mode == mode); +} + +/* * Returns whether path was tracked in the index before the merge started */ static int was_tracked(struct merge_options *o, const char *path) @@ -2821,23 +2840,20 @@ static int merge_content(struct merge_options *o, o->branch2, path2, &mfi)) return -1; - if (mfi.clean && !df_conflict_remains && - oid_eq(&mfi.oid, a_oid) && mfi.mode == a_mode) { - int path_renamed_outside_HEAD; + /* + * We can skip updating the working tree file iff: + * a) The merge is clean + * b) The merge matches what was in HEAD (content, mode, pathname) + * c) The target path is usable (i.e. not involved in D/F conflict) + */ + if (mfi.clean && + was_tracked_and_matches(o, path, &mfi.oid, mfi.mode) && + !df_conflict_remains) { output(o, 3, _("Skipped %s (merged same as existing)"), path); - /* - * The content merge resulted in the same file contents we - * already had. We can return early if those file contents - * are recorded at the correct path (which may not be true - * if the merge involves a rename). - */ - path_renamed_outside_HEAD = !path2 || !strcmp(path, path2); - if (!path_renamed_outside_HEAD) { - if (add_cacheinfo(o, mfi.mode, &mfi.oid, path, - 0, (!o->call_depth && !is_dirty), 0)) - return -1; - return mfi.clean; - } + if (add_cacheinfo(o, mfi.mode, &mfi.oid, path, + 0, (!o->call_depth && !is_dirty), 0)) + return -1; + return mfi.clean; } if (!mfi.clean) { diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index a1fad6980b..6df2650c03 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -247,7 +247,7 @@ test_expect_success 'merge of identical changes in a renamed file' ' git reset --hard HEAD^ && git checkout change && GIT_MERGE_VERBOSITY=3 git merge change+rename >out && - test_i18ngrep "^Skipped B" out + test_i18ngrep ! "^Skipped B" out ' test_expect_success 'setup for rename + d/f conflicts' ' diff --git a/t/t6043-merge-rename-directories.sh b/t/t6043-merge-rename-directories.sh index 45f620633f..2e28f2908d 100755 --- a/t/t6043-merge-rename-directories.sh +++ b/t/t6043-merge-rename-directories.sh @@ -3884,7 +3884,7 @@ test_expect_success '12b-setup: Moving one directory hierarchy into another' ' ) ' -test_expect_failure '12b-check: Moving one directory hierarchy into another' ' +test_expect_success '12b-check: Moving one directory hierarchy into another' ' ( cd 12b && diff --git a/t/t6046-merge-skip-unneeded-updates.sh b/t/t6046-merge-skip-unneeded-updates.sh index a0f482e232..fcefffcaec 100755 --- a/t/t6046-merge-skip-unneeded-updates.sh +++ b/t/t6046-merge-skip-unneeded-updates.sh @@ -64,7 +64,7 @@ test_expect_success '1a-setup: Modify(A)/Modify(B), change on B subset of A' ' ) ' -test_expect_failure '1a-check-L: Modify(A)/Modify(B), change on B subset of A' ' +test_expect_success '1a-check-L: Modify(A)/Modify(B), change on B subset of A' ' test_when_finished "git -C 1a reset --hard" && test_when_finished "git -C 1a clean -fd" && ( @@ -160,7 +160,7 @@ test_expect_success '2a-setup: Modify(A)/rename(B)' ' ) ' -test_expect_failure '2a-check-L: Modify/rename, merge into modify side' ' +test_expect_success '2a-check-L: Modify/rename, merge into modify side' ' test_when_finished "git -C 2a reset --hard" && test_when_finished "git -C 2a clean -fd" && ( @@ -360,7 +360,7 @@ test_expect_success '2c-setup: Modify b & add c VS rename b->c' ' ) ' -test_expect_failure '2c-check: Modify b & add c VS rename b->c' ' +test_expect_success '2c-check: Modify b & add c VS rename b->c' ' ( cd 2c && @@ -456,7 +456,7 @@ test_expect_success '3a-setup: bq_1->foo/bq_2 on A, foo/->bar/ on B' ' ) ' -test_expect_failure '3a-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' ' +test_expect_success '3a-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' ' test_when_finished "git -C 3a reset --hard" && test_when_finished "git -C 3a clean -fd" && ( @@ -579,7 +579,7 @@ test_expect_success '3b-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' ' ) ' -test_expect_failure '3b-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' ' +test_expect_success '3b-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' ' test_when_finished "git -C 3b reset --hard" && test_when_finished "git -C 3b clean -fd" && ( |