merge-ort: implement CE_SKIP_WORKTREE handling with conflicted entries
When merge conflicts occur in paths removed by a sparse-checkout, we need to unsparsify those paths (clear the SKIP_WORKTREE bit), and write out the conflicted file to the working copy. In the very unlikely case that someone manually put a file into the working copy at the location of the SKIP_WORKTREE file, we need to avoid overwriting whatever edits they have made and move that file to a different location first. Signed-off-by: Elijah Newren <newren@gmail.com> Reviewed-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elijah Newren committed
Mar 20, 2021 at 00:03 UTC
66b209b86ad3b79728d3f0f22e1bdef6b17a12c1
2 files changed
+32
-15
merge-ort.c
+30
-13
@@ -3369,23 +3369,27 @@ static int checkout(struct merge_options *opt,
3369
return ret;
3370
}
3371
3372
-static int record_conflicted_index_entries(struct merge_options *opt,
3373
- struct index_state *index,
3374
- struct strmap *paths,
3375
- struct strmap *conflicted)
3372
+static int record_conflicted_index_entries(struct merge_options *opt)
3373
{
3374
struct hashmap_iter iter;
3375
struct strmap_entry *e;
3376
+ struct index_state *index = opt->repo->index;
3377
+ struct checkout state = CHECKOUT_INIT;
3378
int errs = 0;
3379
int original_cache_nr;
3380
3382
- if (strmap_empty(conflicted))
3381
+ if (strmap_empty(&opt->priv->conflicted))
3382
return 0;
3383
3384
+ /* If any entries have skip_worktree set, we'll have to check 'em out */
3385
+ state.force = 1;
3386
+ state.quiet = 1;
3387
+ state.refresh_cache = 1;
3388
+ state.istate = index;
3389
original_cache_nr = index->cache_nr;
3390
3391
/* Put every entry from paths into plist, then sort */
3388
- strmap_for_each_entry(conflicted, &iter, e) {
3392
+ strmap_for_each_entry(&opt->priv->conflicted, &iter, e) {
3393
const char *path = e->key;
3394
struct conflict_info *ci = e->value;
3395
int pos;
@@ -3426,9 +3430,23 @@ static int record_conflicted_index_entries(struct merge_options *opt,
3430
* the higher order stages. Thus, we need override
3431
* the CE_SKIP_WORKTREE bit and manually write those
3432
* files to the working disk here.
3429
- *
3430
- * TODO: Implement this CE_SKIP_WORKTREE fixup.
3433
*/
3434
+ if (ce_skip_worktree(ce)) {
3435
+ struct stat st;
3436
+
3437
+ if (!lstat(path, &st)) {
3438
+ char *new_name = unique_path(&opt->priv->paths,
3439
+ path,
3440
+ "cruft");
3441
+
3442
+ path_msg(opt, path, 1,
3443
+ _("Note: %s not up to date and in way of checking out conflicted version; old copy renamed to %s"),
3444
+ path, new_name);
3445
+ errs |= rename(path, new_name);
3446
+ free(new_name);
3447
+ }
3448
+ errs |= checkout_entry(ce, &state, NULL, NULL);
3449
+ }
3450
3451
/*
3452
* Mark this cache entry for removal and instead add
@@ -3478,8 +3496,6 @@ void merge_switch_to_result(struct merge_options *opt,
3496
{
3497
assert(opt->priv == NULL);
3498
if (result->clean >= 0 && update_worktree_and_index) {
3481
- struct merge_options_internal *opti = result->priv;
3482
-
3499
trace2_region_enter("merge", "checkout", opt->repo);
3500
if (checkout(opt, head, result->tree)) {
3501
/* failure to function */
@@ -3489,13 +3505,14 @@ void merge_switch_to_result(struct merge_options *opt,
3505
trace2_region_leave("merge", "checkout", opt->repo);
3506
3507
trace2_region_enter("merge", "record_conflicted", opt->repo);
3492
- if (record_conflicted_index_entries(opt, opt->repo->index,
3493
- &opti->paths,
3494
- &opti->conflicted)) {
3508
+ opt->priv = result->priv;
3509
+ if (record_conflicted_index_entries(opt)) {
3510
/* failure to function */
3511
+ opt->priv = NULL;
3512
result->clean = -1;
3513
return;
3514
}
3515
+ opt->priv = NULL;
3516
trace2_region_leave("merge", "record_conflicted", opt->repo);
3517
}
3518
t/t6428-merge-conflicts-sparse.sh
+2
-2
@@ -76,7 +76,7 @@ test_setup_numerals () {
76
)
77
}
78
79
-test_expect_merge_algorithm success failure 'conflicting entries written to worktree even if sparse' '
79
+test_expect_success 'conflicting entries written to worktree even if sparse' '
80
test_setup_numerals plain &&
81
(
82
cd numerals_plain &&
@@ -112,7 +112,7 @@ test_expect_merge_algorithm success failure 'conflicting entries written to work
112
)
113
'
114
115
-test_expect_merge_algorithm failure failure 'present-despite-SKIP_WORKTREE handled reasonably' '
115
+test_expect_merge_algorithm failure success 'present-despite-SKIP_WORKTREE handled reasonably' '
116
test_setup_numerals in_the_way &&
117
(
118
cd numerals_in_the_way &&