171
};
172
const char **source, **destination, **dest_path, **submodule_gitfile;
173
const char *dst_w_slash;
174
- enum update_mode *modes;
174
+ enum update_mode *modes, dst_mode = 0;
175
struct stat st;
176
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
177
struct lock_file lock_file = LOCK_INIT;
178
struct cache_entry *ce;
179
struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
180
+ struct string_list dirty_paths = STRING_LIST_INIT_NODUP;
181
182
git_config(git_default_config, NULL);
183
214
if (!path_in_sparse_checkout(dst_w_slash, &the_index) &&
215
empty_dir_has_sparse_contents(dst_w_slash)) {
216
destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
217
+ dst_mode = SKIP_WORKTREE_DIR;
218
} else if (argc != 1) {
219
die(_("destination '%s' is not a directory"), dest_path[0]);
220
} else {
221
destination = dest_path;
222
+ /*
223
+ * <destination> is a file outside of sparse-checkout
224
+ * cone. Insist on cone mode here for backward
225
+ * compatibility. We don't want dst_mode to be assigned
226
+ * for a file when the repo is using no-cone mode (which
227
+ * is deprecated at this point) sparse-checkout. As
228
+ * SPARSE here is only considering cone-mode situation.
229
+ */
230
+ if (!path_in_cone_mode_sparse_checkout(destination[0], &the_index))
231
+ dst_mode = SPARSE;
232
}
233
}
234
if (dst_w_slash != dest_path[0]) {
422
const char *src = source[i], *dst = destination[i];
423
enum update_mode mode = modes[i];
424
int pos;
425
+ int sparse_and_dirty = 0;
426
struct checkout state = CHECKOUT_INIT;
427
state.istate = &the_index;
428
433
if (show_only)
434
continue;
435
if (!(mode & (INDEX | SPARSE | SKIP_WORKTREE_DIR)) &&
436
+ !(dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
437
rename(src, dst) < 0) {
438
if (ignore_errors)
439
continue;
453
454
pos = cache_name_pos(src, strlen(src));
455
assert(pos >= 0);
456
+ if (!(mode & SPARSE) && !lstat(src, &st))
457
+ sparse_and_dirty = ce_modified(active_cache[pos], &st, 0);
458
rename_cache_entry_at(pos, dst);
459
444
- if ((mode & SPARSE) &&
445
- (path_in_sparse_checkout(dst, &the_index))) {
446
- int dst_pos;
460
+ if (ignore_sparse &&
461
+ core_apply_sparse_checkout &&
462
+ core_sparse_checkout_cone) {
463
+ /*
464
+ * NEEDSWORK: we are *not* paying attention to
465
+ * "out-to-out" move (<source> is out-of-cone and
466
+ * <destination> is out-of-cone) at this point. It
467
+ * should be added in a future patch.
468
+ */
469
+ if ((mode & SPARSE) &&
470
+ path_in_sparse_checkout(dst, &the_index)) {
471
+ /* from out-of-cone to in-cone */
472
+ int dst_pos = cache_name_pos(dst, strlen(dst));
473
+ struct cache_entry *dst_ce = active_cache[dst_pos];
474
+
475
+ dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
476
+
477
+ if (checkout_entry(dst_ce, &state, NULL, NULL))
478
+ die(_("cannot checkout %s"), dst_ce->name);
479
+ } else if ((dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
480
+ !(mode & SPARSE) &&
481
+ !path_in_sparse_checkout(dst, &the_index)) {
482
+ /* from in-cone to out-of-cone */
483
+ int dst_pos = cache_name_pos(dst, strlen(dst));
484
+ struct cache_entry *dst_ce = active_cache[dst_pos];
485
448
- dst_pos = cache_name_pos(dst, strlen(dst));
449
- active_cache[dst_pos]->ce_flags &= ~CE_SKIP_WORKTREE;
450
-
451
- if (checkout_entry(active_cache[dst_pos], &state, NULL, NULL))
452
- die(_("cannot checkout %s"), active_cache[dst_pos]->name);
486
+ /*
487
+ * if src is clean, it will suffice to remove it
488
+ */
489
+ if (!sparse_and_dirty) {
490
+ dst_ce->ce_flags |= CE_SKIP_WORKTREE;
491
+ unlink_or_warn(src);
492
+ } else {
493
+ /*
494
+ * if src is dirty, move it to the
495
+ * destination and create leading
496
+ * dirs if necessary
497
+ */
498
+ char *dst_dup = xstrdup(dst);
499
+ string_list_append(&dirty_paths, dst);
500
+ safe_create_leading_directories(dst_dup);
501
+ FREE_AND_NULL(dst_dup);
502
+ rename(src, dst);
503
+ }
504
+ }
505
}
506
}
507
513
die(_("Unable to write new index file"));
514
515
string_list_clear(&src_for_dst, 0);
516
+ string_list_clear(&dirty_paths, 0);
517
UNLEAK(source);
518
UNLEAK(dest_path);
519
free(submodule_gitfile);