diff options
-rw-r--r-- | merge-recursive.c | 24 | ||||
-rwxr-xr-x | t/t6022-merge-rename.sh | 63 |
2 files changed, 81 insertions, 6 deletions
diff --git a/merge-recursive.c b/merge-recursive.c index af131508ec..7c12673553 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -344,10 +344,11 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, * make room for the corresponding directory. Such paths will * later be processed in process_df_entry() at the end. If * the corresponding directory ends up being removed by the - * merge, then the file will be reinstated at that time; - * otherwise, if the file is not supposed to be removed by the - * merge, the contents of the file will be placed in another - * unique filename. + * merge, then the file will be reinstated at that time + * (albeit with a different timestamp!); otherwise, if the + * file is not supposed to be removed by the merge, the + * contents of the file will be placed in another unique + * filename. * * NOTE: This function relies on the fact that entries for a * D/F conflict will appear adjacent in the index, with the @@ -358,6 +359,13 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o, int last_len = 0; int i; + /* + * Do not do any of this crazyness during the recursive; we don't + * even write anything to the working tree! + */ + if (o->call_depth) + return; + for (i = 0; i < entries->nr; i++) { const char *path = entries->items[i].string; int len = strlen(path); @@ -1260,9 +1268,13 @@ static int merge_content(struct merge_options *o, } if (mfi.clean && !df_conflict_remains && - sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode) + sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode && + !o->call_depth && !lstat(path, &st)) { output(o, 3, "Skipped %s (merged same as existing)", path); - else + add_cacheinfo(mfi.mode, mfi.sha, path, + 0 /*stage*/, 1 /*refresh*/, 0 /*options*/); + return mfi.clean; + } else output(o, 2, "Auto-merging %s", path); if (!mfi.clean) { diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index 1ed259d864..5f3b604fd9 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -609,4 +609,67 @@ test_expect_success 'check handling of differently renamed file with D/F conflic ! test -f original ' +test_expect_success 'setup avoid unnecessary update, normal rename' ' + git reset --hard && + git checkout --orphan avoid-unnecessary-update-1 && + git rm -rf . && + git clean -fdqx && + + printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original && + git add -A && + git commit -m "Common commmit" && + + git mv original rename && + echo 11 >>rename && + git add -u && + git commit -m "Renamed and modified" && + + git checkout -b merge-branch-1 HEAD~1 && + echo "random content" >random-file && + git add -A && + git commit -m "Random, unrelated changes" +' + +test_expect_success 'avoid unnecessary update, normal rename' ' + git checkout -q avoid-unnecessary-update-1^0 && + test-chmtime =1000000000 rename && + test-chmtime -v +0 rename >expect && + git merge merge-branch-1 && + test-chmtime -v +0 rename >actual && + test_cmp expect actual # "rename" should have stayed intact +' + +test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' ' + git reset --hard && + git checkout --orphan avoid-unnecessary-update-2 && + git rm -rf . && + git clean -fdqx && + + mkdir df && + printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file && + git add -A && + git commit -m "Common commmit" && + + git mv df/file temp && + rm -rf df && + git mv temp df && + echo 11 >>df && + git add -u && + git commit -m "Renamed and modified" && + + git checkout -b merge-branch-2 HEAD~1 && + >unrelated-change && + git add unrelated-change && + git commit -m "Only unrelated changes" +' + +test_expect_failure 'avoid unnecessary update, with D/F conflict' ' + git checkout -q avoid-unnecessary-update-2^0 && + test-chmtime =1000000000 df && + test-chmtime -v +0 df >expect && + git merge merge-branch-2 && + test-chmtime -v +0 df >actual && + test_cmp expect actual # "df" should have stayed intact +' + test_done |