merge-recursive: preserve skip_worktree bit when necessary

merge-recursive takes any files marked as unmerged by unpack_trees, tries to figure out whether they can be resolved (e.g. using renames or a file-level merge), and then if they can be it will delete the old cache entries and writes new ones. This means that any ce_flags for those cache entries are essentially cleared when merging. Unfortunately, if a file was marked as skip_worktree and it needs a file-level merge but the merge results in the same version of the file that was found in HEAD, we skip updating the worktree (because the file was unchanged) but clear the skip_worktree bit (because of the delete-cache-entry-and-write-new-one). This makes git treat the file as having a local change in the working copy, namely a delete, when it should appear as unchanged despite not being present. Avoid this problem by copying the skip_worktree flag in this case. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Jul 27, 2018 at 12:59 UTC 2b75fb601c05a789988cf0e1b3c1375ee62d3c3e
2 files changed +17 -1
merge-recursive.c
+16
@@ -3043,10 +3043,26 @@ static int merge_content(struct merge_options *o,
3043 if (mfi.clean &&
3044 was_tracked_and_matches(o, path, &mfi.oid, mfi.mode) &&
3045 !df_conflict_remains) {
3046 + int pos;
3047 + struct cache_entry *ce;
3048 +
3049 output(o, 3, _("Skipped %s (merged same as existing)"), path);
3050 if (add_cacheinfo(o, mfi.mode, &mfi.oid, path,
3051 0, (!o->call_depth && !is_dirty), 0))
3052 return -1;
3053 + /*
3054 + * However, add_cacheinfo() will delete the old cache entry
3055 + * and add a new one. We need to copy over any skip_worktree
3056 + * flag to avoid making the file appear as if it were
3057 + * deleted by the user.
3058 + */
3059 + pos = index_name_pos(&o->orig_index, path, strlen(path));
3060 + ce = o->orig_index.cache[pos];
3061 + if (ce_skip_worktree(ce)) {
3062 + pos = index_name_pos(&the_index, path, strlen(path));
3063 + ce = the_index.cache[pos];
3064 + ce->ce_flags |= CE_SKIP_WORKTREE;
3065 + }
3066 return mfi.clean;
3067 }
3068
t/t3507-cherry-pick-conflict.sh
+1 -1
@@ -392,7 +392,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
392 test_cmp expect actual
393 '
394
395 -test_expect_failure 'cherry-pick preserves sparse-checkout' '
395 +test_expect_success 'cherry-pick preserves sparse-checkout' '
396 pristine_detach initial &&
397 test_config core.sparseCheckout true &&
398 test_when_finished "