summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--merge-recursive.c48
-rwxr-xr-xt/t6022-merge-rename.sh2
-rwxr-xr-xt/t6043-merge-rename-directories.sh2
-rwxr-xr-xt/t6046-merge-skip-unneeded-updates.sh10
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" &&
(