Git fork
1#define USE_THE_REPOSITORY_VARIABLE
2#define DISABLE_SIGN_COMPARE_WARNINGS
3
4#include "builtin.h"
5#include "abspath.h"
6#include "config.h"
7#include "dir.h"
8#include "environment.h"
9#include "gettext.h"
10#include "object-file.h"
11#include "object-name.h"
12#include "parse-options.h"
13#include "path.h"
14#include "pathspec.h"
15#include "strbuf.h"
16#include "string-list.h"
17#include "lockfile.h"
18#include "unpack-trees.h"
19#include "quote.h"
20#include "setup.h"
21#include "sparse-index.h"
22#include "worktree.h"
23
24static const char *empty_base = "";
25
26static char const * const builtin_sparse_checkout_usage[] = {
27 N_("git sparse-checkout (init | list | set | add | reapply | disable | check-rules | clean) [<options>]"),
28 NULL
29};
30
31static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
32{
33 int i;
34
35 for (i = 0; i < pl->nr; i++) {
36 struct path_pattern *p = pl->patterns[i];
37
38 if (p->flags & PATTERN_FLAG_NEGATIVE)
39 fprintf(fp, "!");
40
41 fprintf(fp, "%s", p->pattern);
42
43 if (p->flags & PATTERN_FLAG_MUSTBEDIR)
44 fprintf(fp, "/");
45
46 fprintf(fp, "\n");
47 }
48}
49
50static char const * const builtin_sparse_checkout_list_usage[] = {
51 "git sparse-checkout list",
52 NULL
53};
54
55static int sparse_checkout_list(int argc, const char **argv, const char *prefix,
56 struct repository *repo UNUSED)
57{
58 static struct option builtin_sparse_checkout_list_options[] = {
59 OPT_END(),
60 };
61 struct pattern_list pl;
62 char *sparse_filename;
63 int res;
64
65 setup_work_tree();
66 if (!core_apply_sparse_checkout)
67 die(_("this worktree is not sparse"));
68
69 argc = parse_options(argc, argv, prefix,
70 builtin_sparse_checkout_list_options,
71 builtin_sparse_checkout_list_usage, 0);
72
73 memset(&pl, 0, sizeof(pl));
74
75 pl.use_cone_patterns = core_sparse_checkout_cone;
76
77 sparse_filename = get_sparse_checkout_filename();
78 res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
79 free(sparse_filename);
80
81 if (res < 0) {
82 warning(_("this worktree is not sparse (sparse-checkout file may not exist)"));
83 return 0;
84 }
85
86 if (pl.use_cone_patterns) {
87 int i;
88 struct pattern_entry *pe;
89 struct hashmap_iter iter;
90 struct string_list sl = STRING_LIST_INIT_DUP;
91
92 hashmap_for_each_entry(&pl.recursive_hashmap, &iter, pe, ent) {
93 /* pe->pattern starts with "/", skip it */
94 string_list_insert(&sl, pe->pattern + 1);
95 }
96
97 string_list_sort(&sl);
98
99 for (i = 0; i < sl.nr; i++) {
100 quote_c_style(sl.items[i].string, NULL, stdout, 0);
101 printf("\n");
102 }
103
104 string_list_clear(&sl, 0);
105 } else {
106 write_patterns_to_file(stdout, &pl);
107 }
108
109 clear_pattern_list(&pl);
110
111 return 0;
112}
113
114static void clean_tracked_sparse_directories(struct repository *r)
115{
116 int i, was_full = 0;
117 struct strbuf path = STRBUF_INIT;
118 size_t pathlen;
119 struct string_list_item *item;
120 struct string_list sparse_dirs = STRING_LIST_INIT_DUP;
121
122 /*
123 * If we are not using cone mode patterns, then we cannot
124 * delete directories outside of the sparse cone.
125 */
126 if (!r || !r->index || !r->worktree)
127 return;
128 if (init_sparse_checkout_patterns(r->index) ||
129 !r->index->sparse_checkout_patterns->use_cone_patterns)
130 return;
131
132 /*
133 * Use the sparse index as a data structure to assist finding
134 * directories that are safe to delete. This conversion to a
135 * sparse index will not delete directories that contain
136 * conflicted entries or submodules.
137 */
138 if (r->index->sparse_index == INDEX_EXPANDED) {
139 /*
140 * If something, such as a merge conflict or other concern,
141 * prevents us from converting to a sparse index, then do
142 * not try deleting files.
143 */
144 if (convert_to_sparse(r->index, SPARSE_INDEX_MEMORY_ONLY))
145 return;
146 was_full = 1;
147 }
148
149 strbuf_addstr(&path, r->worktree);
150 strbuf_complete(&path, '/');
151 pathlen = path.len;
152
153 /*
154 * Collect directories that have gone out of scope but also
155 * exist on disk, so there is some work to be done. We need to
156 * store the entries in a list before exploring, since that might
157 * expand the sparse-index again.
158 */
159 for (i = 0; i < r->index->cache_nr; i++) {
160 struct cache_entry *ce = r->index->cache[i];
161
162 if (S_ISSPARSEDIR(ce->ce_mode) &&
163 repo_file_exists(r, ce->name))
164 string_list_append(&sparse_dirs, ce->name);
165 }
166
167 for_each_string_list_item(item, &sparse_dirs) {
168 struct dir_struct dir = DIR_INIT;
169 struct pathspec p = { 0 };
170 struct strvec s = STRVEC_INIT;
171
172 strbuf_setlen(&path, pathlen);
173 strbuf_addstr(&path, item->string);
174
175 dir.flags |= DIR_SHOW_IGNORED_TOO;
176
177 setup_standard_excludes(&dir);
178 strvec_push(&s, path.buf);
179
180 parse_pathspec(&p, PATHSPEC_GLOB, 0, NULL, s.v);
181 fill_directory(&dir, r->index, &p);
182
183 if (dir.nr) {
184 warning(_("directory '%s' contains untracked files,"
185 " but is not in the sparse-checkout cone"),
186 item->string);
187 } else if (remove_dir_recursively(&path, 0)) {
188 /*
189 * Removal is "best effort". If something blocks
190 * the deletion, then continue with a warning.
191 */
192 warning(_("failed to remove directory '%s'"),
193 item->string);
194 }
195
196 strvec_clear(&s);
197 clear_pathspec(&p);
198 dir_clear(&dir);
199 }
200
201 string_list_clear(&sparse_dirs, 0);
202 strbuf_release(&path);
203
204 if (was_full)
205 ensure_full_index(r->index);
206}
207
208static int update_working_directory(struct repository *r,
209 struct pattern_list *pl)
210{
211 enum update_sparsity_result result;
212 struct unpack_trees_options o;
213 struct lock_file lock_file = LOCK_INIT;
214 struct pattern_list *old_pl;
215
216 /* If no branch has been checked out, there are no updates to make. */
217 if (is_index_unborn(r->index))
218 return UPDATE_SPARSITY_SUCCESS;
219
220 old_pl = r->index->sparse_checkout_patterns;
221 r->index->sparse_checkout_patterns = pl;
222
223 memset(&o, 0, sizeof(o));
224 o.verbose_update = isatty(2);
225 o.update = 1;
226 o.head_idx = -1;
227 o.src_index = r->index;
228 o.dst_index = r->index;
229 o.skip_sparse_checkout = 0;
230
231 setup_work_tree();
232
233 repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
234
235 setup_unpack_trees_porcelain(&o, "sparse-checkout");
236 result = update_sparsity(&o, pl);
237 clear_unpack_trees_porcelain(&o);
238
239 if (result == UPDATE_SPARSITY_WARNINGS)
240 /*
241 * We don't do any special handling of warnings from untracked
242 * files in the way or dirty entries that can't be removed.
243 */
244 result = UPDATE_SPARSITY_SUCCESS;
245 if (result == UPDATE_SPARSITY_SUCCESS)
246 write_locked_index(r->index, &lock_file, COMMIT_LOCK);
247 else
248 rollback_lock_file(&lock_file);
249
250 clean_tracked_sparse_directories(r);
251
252 if (r->index->sparse_checkout_patterns != pl) {
253 clear_pattern_list(r->index->sparse_checkout_patterns);
254 FREE_AND_NULL(r->index->sparse_checkout_patterns);
255 }
256 r->index->sparse_checkout_patterns = old_pl;
257
258 return result;
259}
260
261static char *escaped_pattern(char *pattern)
262{
263 char *p = pattern;
264 struct strbuf final = STRBUF_INIT;
265
266 while (*p) {
267 if (is_glob_special(*p))
268 strbuf_addch(&final, '\\');
269
270 strbuf_addch(&final, *p);
271 p++;
272 }
273
274 return strbuf_detach(&final, NULL);
275}
276
277static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
278{
279 int i;
280 struct pattern_entry *pe;
281 struct hashmap_iter iter;
282 struct string_list sl = STRING_LIST_INIT_DUP;
283 struct strbuf parent_pattern = STRBUF_INIT;
284
285 hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
286 if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
287 continue;
288
289 if (!hashmap_contains_parent(&pl->recursive_hashmap,
290 pe->pattern,
291 &parent_pattern))
292 string_list_insert(&sl, pe->pattern);
293 }
294
295 string_list_sort(&sl);
296 string_list_remove_duplicates(&sl, 0);
297
298 fprintf(fp, "/*\n!/*/\n");
299
300 for (i = 0; i < sl.nr; i++) {
301 char *pattern = escaped_pattern(sl.items[i].string);
302
303 if (strlen(pattern))
304 fprintf(fp, "%s/\n!%s/*/\n", pattern, pattern);
305 free(pattern);
306 }
307
308 string_list_clear(&sl, 0);
309
310 hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
311 if (!hashmap_contains_parent(&pl->recursive_hashmap,
312 pe->pattern,
313 &parent_pattern))
314 string_list_insert(&sl, pe->pattern);
315 }
316
317 strbuf_release(&parent_pattern);
318
319 string_list_sort(&sl);
320 string_list_remove_duplicates(&sl, 0);
321
322 for (i = 0; i < sl.nr; i++) {
323 char *pattern = escaped_pattern(sl.items[i].string);
324 fprintf(fp, "%s/\n", pattern);
325 free(pattern);
326 }
327
328 string_list_clear(&sl, 0);
329}
330
331static int write_patterns_and_update(struct repository *repo,
332 struct pattern_list *pl)
333{
334 char *sparse_filename;
335 FILE *fp;
336 struct lock_file lk = LOCK_INIT;
337 int result;
338
339 sparse_filename = get_sparse_checkout_filename();
340
341 if (safe_create_leading_directories(repo, sparse_filename))
342 die(_("failed to create directory for sparse-checkout file"));
343
344 hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
345
346 result = update_working_directory(repo, pl);
347 if (result) {
348 rollback_lock_file(&lk);
349 update_working_directory(repo, NULL);
350 goto out;
351 }
352
353 fp = fdopen_lock_file(&lk, "w");
354 if (!fp)
355 die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk));
356
357 if (core_sparse_checkout_cone)
358 write_cone_to_file(fp, pl);
359 else
360 write_patterns_to_file(fp, pl);
361
362 if (commit_lock_file(&lk))
363 die_errno(_("unable to write %s"), sparse_filename);
364
365out:
366 clear_pattern_list(pl);
367 free(sparse_filename);
368 return result;
369}
370
371enum sparse_checkout_mode {
372 MODE_NO_PATTERNS = 0,
373 MODE_ALL_PATTERNS = 1,
374 MODE_CONE_PATTERNS = 2,
375};
376
377static int set_config(struct repository *repo,
378 enum sparse_checkout_mode mode)
379{
380 /* Update to use worktree config, if not already. */
381 if (init_worktree_config(repo)) {
382 error(_("failed to initialize worktree config"));
383 return 1;
384 }
385
386 if (repo_config_set_worktree_gently(repo,
387 "core.sparseCheckout",
388 mode ? "true" : "false") ||
389 repo_config_set_worktree_gently(repo,
390 "core.sparseCheckoutCone",
391 mode == MODE_CONE_PATTERNS ?
392 "true" : "false"))
393 return 1;
394
395 if (mode == MODE_NO_PATTERNS)
396 return set_sparse_index_config(repo, 0);
397
398 return 0;
399}
400
401static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {
402 /* If not specified, use previous definition of cone mode */
403 if (*cone_mode == -1 && core_apply_sparse_checkout)
404 *cone_mode = core_sparse_checkout_cone;
405
406 /* Set cone/non-cone mode appropriately */
407 core_apply_sparse_checkout = 1;
408 if (*cone_mode == 1 || *cone_mode == -1) {
409 core_sparse_checkout_cone = 1;
410 return MODE_CONE_PATTERNS;
411 }
412 core_sparse_checkout_cone = 0;
413 return MODE_ALL_PATTERNS;
414}
415
416static int update_modes(struct repository *repo, int *cone_mode, int *sparse_index)
417{
418 int mode, record_mode;
419
420 /* Determine if we need to record the mode; ensure sparse checkout on */
421 record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
422
423 mode = update_cone_mode(cone_mode);
424 if (record_mode && set_config(repo, mode))
425 return 1;
426
427 /* Set sparse-index/non-sparse-index mode if specified */
428 if (*sparse_index >= 0) {
429 if (set_sparse_index_config(repo, *sparse_index) < 0)
430 die(_("failed to modify sparse-index config"));
431
432 /* force an index rewrite */
433 repo_read_index(repo);
434 repo->index->updated_workdir = 1;
435
436 if (!*sparse_index)
437 ensure_full_index(repo->index);
438 }
439
440 return 0;
441}
442
443static char const * const builtin_sparse_checkout_init_usage[] = {
444 "git sparse-checkout init [--cone] [--[no-]sparse-index]",
445 NULL
446};
447
448static struct sparse_checkout_init_opts {
449 int cone_mode;
450 int sparse_index;
451} init_opts;
452
453static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
454 struct repository *repo)
455{
456 struct pattern_list pl;
457 char *sparse_filename;
458 int res;
459 struct object_id oid;
460
461 static struct option builtin_sparse_checkout_init_options[] = {
462 OPT_BOOL(0, "cone", &init_opts.cone_mode,
463 N_("initialize the sparse-checkout in cone mode")),
464 OPT_BOOL(0, "sparse-index", &init_opts.sparse_index,
465 N_("toggle the use of a sparse index")),
466 OPT_END(),
467 };
468
469 setup_work_tree();
470 repo_read_index(repo);
471
472 init_opts.cone_mode = -1;
473 init_opts.sparse_index = -1;
474
475 argc = parse_options(argc, argv, prefix,
476 builtin_sparse_checkout_init_options,
477 builtin_sparse_checkout_init_usage, 0);
478
479 if (update_modes(repo, &init_opts.cone_mode, &init_opts.sparse_index))
480 return 1;
481
482 memset(&pl, 0, sizeof(pl));
483
484 sparse_filename = get_sparse_checkout_filename();
485 res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
486
487 /* If we already have a sparse-checkout file, use it. */
488 if (res >= 0) {
489 free(sparse_filename);
490 clear_pattern_list(&pl);
491 return update_working_directory(repo, NULL);
492 }
493
494 if (repo_get_oid(repo, "HEAD", &oid)) {
495 FILE *fp;
496
497 /* assume we are in a fresh repo, but update the sparse-checkout file */
498 if (safe_create_leading_directories(repo, sparse_filename))
499 die(_("unable to create leading directories of %s"),
500 sparse_filename);
501 fp = xfopen(sparse_filename, "w");
502 if (!fp)
503 die(_("failed to open '%s'"), sparse_filename);
504
505 free(sparse_filename);
506 fprintf(fp, "/*\n!/*/\n");
507 fclose(fp);
508 return 0;
509 }
510
511 free(sparse_filename);
512
513 add_pattern("/*", empty_base, 0, &pl, 0);
514 add_pattern("!/*/", empty_base, 0, &pl, 0);
515 pl.use_cone_patterns = init_opts.cone_mode;
516
517 return write_patterns_and_update(repo, &pl);
518}
519
520static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
521{
522 struct pattern_entry *e = xmalloc(sizeof(*e));
523 e->patternlen = path->len;
524 e->pattern = strbuf_detach(path, NULL);
525 hashmap_entry_init(&e->ent, fspathhash(e->pattern));
526
527 hashmap_add(&pl->recursive_hashmap, &e->ent);
528
529 while (e->patternlen) {
530 char *slash = strrchr(e->pattern, '/');
531 char *oldpattern = e->pattern;
532 size_t newlen;
533 struct pattern_entry *dup;
534
535 if (!slash || slash == e->pattern)
536 break;
537
538 newlen = slash - e->pattern;
539 e = xmalloc(sizeof(struct pattern_entry));
540 e->patternlen = newlen;
541 e->pattern = xstrndup(oldpattern, newlen);
542 hashmap_entry_init(&e->ent, fspathhash(e->pattern));
543
544 dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
545 if (!dup) {
546 hashmap_add(&pl->parent_hashmap, &e->ent);
547 } else {
548 free(e->pattern);
549 free(e);
550 e = dup;
551 }
552 }
553}
554
555static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
556{
557 strbuf_trim(line);
558
559 strbuf_trim_trailing_dir_sep(line);
560
561 if (strbuf_normalize_path(line))
562 die(_("could not normalize path %s"), line->buf);
563
564 if (!line->len)
565 return;
566
567 if (line->buf[0] != '/')
568 strbuf_insertstr(line, 0, "/");
569
570 insert_recursive_pattern(pl, line);
571}
572
573static void add_patterns_from_input(struct pattern_list *pl,
574 int argc, const char **argv,
575 FILE *file)
576{
577 int i;
578 if (core_sparse_checkout_cone) {
579 struct strbuf line = STRBUF_INIT;
580
581 hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
582 hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
583 pl->use_cone_patterns = 1;
584
585 if (file) {
586 struct strbuf unquoted = STRBUF_INIT;
587 while (!strbuf_getline(&line, file)) {
588 if (line.buf[0] == '"') {
589 strbuf_reset(&unquoted);
590 if (unquote_c_style(&unquoted, line.buf, NULL))
591 die(_("unable to unquote C-style string '%s'"),
592 line.buf);
593
594 strbuf_swap(&unquoted, &line);
595 }
596
597 strbuf_to_cone_pattern(&line, pl);
598 }
599
600 strbuf_release(&unquoted);
601 } else {
602 for (i = 0; i < argc; i++) {
603 strbuf_setlen(&line, 0);
604 strbuf_addstr(&line, argv[i]);
605 strbuf_to_cone_pattern(&line, pl);
606 }
607 }
608 strbuf_release(&line);
609 } else {
610 if (file) {
611 struct strbuf line = STRBUF_INIT;
612
613 while (!strbuf_getline(&line, file))
614 add_pattern(line.buf, empty_base, 0, pl, 0);
615
616 strbuf_release(&line);
617 } else {
618 for (i = 0; i < argc; i++)
619 add_pattern(argv[i], empty_base, 0, pl, 0);
620 }
621 }
622}
623
624enum modify_type {
625 REPLACE,
626 ADD,
627};
628
629static void add_patterns_cone_mode(int argc, const char **argv,
630 struct pattern_list *pl,
631 int use_stdin)
632{
633 struct strbuf buffer = STRBUF_INIT;
634 struct pattern_entry *pe;
635 struct hashmap_iter iter;
636 struct pattern_list existing;
637 char *sparse_filename = get_sparse_checkout_filename();
638
639 add_patterns_from_input(pl, argc, argv,
640 use_stdin ? stdin : NULL);
641
642 memset(&existing, 0, sizeof(existing));
643 existing.use_cone_patterns = core_sparse_checkout_cone;
644
645 if (add_patterns_from_file_to_list(sparse_filename, "", 0,
646 &existing, NULL, 0))
647 die(_("unable to load existing sparse-checkout patterns"));
648 free(sparse_filename);
649
650 if (!existing.use_cone_patterns)
651 die(_("existing sparse-checkout patterns do not use cone mode"));
652
653 hashmap_for_each_entry(&existing.recursive_hashmap, &iter, pe, ent) {
654 if (!hashmap_contains_parent(&pl->recursive_hashmap,
655 pe->pattern, &buffer) ||
656 !hashmap_contains_parent(&pl->parent_hashmap,
657 pe->pattern, &buffer)) {
658 strbuf_reset(&buffer);
659 strbuf_addstr(&buffer, pe->pattern);
660 insert_recursive_pattern(pl, &buffer);
661 }
662 }
663
664 clear_pattern_list(&existing);
665 strbuf_release(&buffer);
666}
667
668static void add_patterns_literal(int argc, const char **argv,
669 struct pattern_list *pl,
670 int use_stdin)
671{
672 char *sparse_filename = get_sparse_checkout_filename();
673 if (add_patterns_from_file_to_list(sparse_filename, "", 0,
674 pl, NULL, 0))
675 die(_("unable to load existing sparse-checkout patterns"));
676 free(sparse_filename);
677 add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
678}
679
680static int modify_pattern_list(struct repository *repo,
681 struct strvec *args, int use_stdin,
682 enum modify_type m)
683{
684 int result;
685 int changed_config = 0;
686 struct pattern_list *pl = xcalloc(1, sizeof(*pl));
687
688 switch (m) {
689 case ADD:
690 if (core_sparse_checkout_cone)
691 add_patterns_cone_mode(args->nr, args->v, pl, use_stdin);
692 else
693 add_patterns_literal(args->nr, args->v, pl, use_stdin);
694 break;
695
696 case REPLACE:
697 add_patterns_from_input(pl, args->nr, args->v,
698 use_stdin ? stdin : NULL);
699 break;
700 }
701
702 if (!core_apply_sparse_checkout) {
703 set_config(repo, MODE_ALL_PATTERNS);
704 core_apply_sparse_checkout = 1;
705 changed_config = 1;
706 }
707
708 result = write_patterns_and_update(repo, pl);
709
710 if (result && changed_config)
711 set_config(repo, MODE_NO_PATTERNS);
712
713 clear_pattern_list(pl);
714 free(pl);
715 return result;
716}
717
718static void sanitize_paths(struct repository *repo,
719 struct strvec *args,
720 const char *prefix, int skip_checks)
721{
722 int i;
723
724 if (!args->nr)
725 return;
726
727 if (prefix && *prefix && core_sparse_checkout_cone) {
728 /*
729 * The args are not pathspecs, so unfortunately we
730 * cannot imitate how cmd_add() uses parse_pathspec().
731 */
732 int prefix_len = strlen(prefix);
733
734 for (i = 0; i < args->nr; i++) {
735 char *prefixed_path = prefix_path(prefix, prefix_len, args->v[i]);
736 strvec_replace(args, i, prefixed_path);
737 free(prefixed_path);
738 }
739 }
740
741 if (skip_checks)
742 return;
743
744 if (prefix && *prefix && !core_sparse_checkout_cone)
745 die(_("please run from the toplevel directory in non-cone mode"));
746
747 if (core_sparse_checkout_cone) {
748 for (i = 0; i < args->nr; i++) {
749 if (args->v[i][0] == '/')
750 die(_("specify directories rather than patterns (no leading slash)"));
751 if (args->v[i][0] == '!')
752 die(_("specify directories rather than patterns. If your directory starts with a '!', pass --skip-checks"));
753 if (strpbrk(args->v[i], "*?[]"))
754 die(_("specify directories rather than patterns. If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
755 }
756 }
757
758 for (i = 0; i < args->nr; i++) {
759 struct cache_entry *ce;
760 struct index_state *index = repo->index;
761 int pos = index_name_pos(index, args->v[i], strlen(args->v[i]));
762
763 if (pos < 0)
764 continue;
765 ce = index->cache[pos];
766 if (S_ISSPARSEDIR(ce->ce_mode))
767 continue;
768
769 if (core_sparse_checkout_cone)
770 die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]);
771 else
772 warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), args->v[i]);
773 }
774}
775
776static char const * const builtin_sparse_checkout_add_usage[] = {
777 N_("git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"),
778 NULL
779};
780
781static struct sparse_checkout_add_opts {
782 int skip_checks;
783 int use_stdin;
784} add_opts;
785
786static int sparse_checkout_add(int argc, const char **argv, const char *prefix,
787 struct repository *repo)
788{
789 static struct option builtin_sparse_checkout_add_options[] = {
790 OPT_BOOL_F(0, "skip-checks", &add_opts.skip_checks,
791 N_("skip some sanity checks on the given paths that might give false positives"),
792 PARSE_OPT_NONEG),
793 OPT_BOOL(0, "stdin", &add_opts.use_stdin,
794 N_("read patterns from standard in")),
795 OPT_END(),
796 };
797 struct strvec patterns = STRVEC_INIT;
798 int ret;
799
800 setup_work_tree();
801 if (!core_apply_sparse_checkout)
802 die(_("no sparse-checkout to add to"));
803
804 repo_read_index(repo);
805
806 argc = parse_options(argc, argv, prefix,
807 builtin_sparse_checkout_add_options,
808 builtin_sparse_checkout_add_usage, 0);
809
810 for (int i = 0; i < argc; i++)
811 strvec_push(&patterns, argv[i]);
812 sanitize_paths(repo, &patterns, prefix, add_opts.skip_checks);
813
814 ret = modify_pattern_list(repo, &patterns, add_opts.use_stdin, ADD);
815
816 strvec_clear(&patterns);
817 return ret;
818}
819
820static char const * const builtin_sparse_checkout_set_usage[] = {
821 N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] (--stdin | <patterns>)"),
822 NULL
823};
824
825static struct sparse_checkout_set_opts {
826 int cone_mode;
827 int sparse_index;
828 int skip_checks;
829 int use_stdin;
830} set_opts;
831
832static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
833 struct repository *repo)
834{
835 int default_patterns_nr = 2;
836 const char *default_patterns[] = {"/*", "!/*/", NULL};
837
838 static struct option builtin_sparse_checkout_set_options[] = {
839 OPT_BOOL(0, "cone", &set_opts.cone_mode,
840 N_("initialize the sparse-checkout in cone mode")),
841 OPT_BOOL(0, "sparse-index", &set_opts.sparse_index,
842 N_("toggle the use of a sparse index")),
843 OPT_BOOL_F(0, "skip-checks", &set_opts.skip_checks,
844 N_("skip some sanity checks on the given paths that might give false positives"),
845 PARSE_OPT_NONEG),
846 OPT_BOOL_F(0, "stdin", &set_opts.use_stdin,
847 N_("read patterns from standard in"),
848 PARSE_OPT_NONEG),
849 OPT_END(),
850 };
851 struct strvec patterns = STRVEC_INIT;
852 int ret;
853
854 setup_work_tree();
855 repo_read_index(repo);
856
857 set_opts.cone_mode = -1;
858 set_opts.sparse_index = -1;
859
860 argc = parse_options(argc, argv, prefix,
861 builtin_sparse_checkout_set_options,
862 builtin_sparse_checkout_set_usage, 0);
863
864 if (update_modes(repo, &set_opts.cone_mode, &set_opts.sparse_index))
865 return 1;
866
867 /*
868 * Cone mode automatically specifies the toplevel directory. For
869 * non-cone mode, if nothing is specified, manually select just the
870 * top-level directory (much as 'init' would do).
871 */
872 if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
873 for (int i = 0; i < default_patterns_nr; i++)
874 strvec_push(&patterns, default_patterns[i]);
875 } else {
876 for (int i = 0; i < argc; i++)
877 strvec_push(&patterns, argv[i]);
878 sanitize_paths(repo, &patterns, prefix, set_opts.skip_checks);
879 }
880
881 ret = modify_pattern_list(repo, &patterns, set_opts.use_stdin, REPLACE);
882
883 strvec_clear(&patterns);
884 return ret;
885}
886
887static char const * const builtin_sparse_checkout_reapply_usage[] = {
888 "git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]",
889 NULL
890};
891
892static struct sparse_checkout_reapply_opts {
893 int cone_mode;
894 int sparse_index;
895} reapply_opts;
896
897static int sparse_checkout_reapply(int argc, const char **argv,
898 const char *prefix,
899 struct repository *repo)
900{
901 static struct option builtin_sparse_checkout_reapply_options[] = {
902 OPT_BOOL(0, "cone", &reapply_opts.cone_mode,
903 N_("initialize the sparse-checkout in cone mode")),
904 OPT_BOOL(0, "sparse-index", &reapply_opts.sparse_index,
905 N_("toggle the use of a sparse index")),
906 OPT_END(),
907 };
908
909 setup_work_tree();
910 if (!core_apply_sparse_checkout)
911 die(_("must be in a sparse-checkout to reapply sparsity patterns"));
912
913 reapply_opts.cone_mode = -1;
914 reapply_opts.sparse_index = -1;
915
916 argc = parse_options(argc, argv, prefix,
917 builtin_sparse_checkout_reapply_options,
918 builtin_sparse_checkout_reapply_usage, 0);
919
920 repo_read_index(repo);
921
922 if (update_modes(repo, &reapply_opts.cone_mode, &reapply_opts.sparse_index))
923 return 1;
924
925 return update_working_directory(repo, NULL);
926}
927
928static char const * const builtin_sparse_checkout_clean_usage[] = {
929 "git sparse-checkout clean [-n|--dry-run]",
930 NULL
931};
932
933static int list_file_iterator(const char *path, const void *data)
934{
935 const char *msg = data;
936
937 printf(msg, path);
938 return 0;
939}
940
941static void list_every_file_in_dir(const char *msg,
942 const char *directory)
943{
944 struct strbuf path = STRBUF_INIT;
945
946 strbuf_addstr(&path, directory);
947 for_each_file_in_dir(&path, list_file_iterator, msg);
948 strbuf_release(&path);
949}
950
951static const char *msg_remove = N_("Removing %s\n");
952static const char *msg_would_remove = N_("Would remove %s\n");
953
954static int sparse_checkout_clean(int argc, const char **argv,
955 const char *prefix,
956 struct repository *repo)
957{
958 struct strbuf full_path = STRBUF_INIT;
959 const char *msg = msg_remove;
960 size_t worktree_len;
961 int force = 0, dry_run = 0, verbose = 0;
962 int require_force = 1;
963
964 struct option builtin_sparse_checkout_clean_options[] = {
965 OPT__DRY_RUN(&dry_run, N_("dry run")),
966 OPT__FORCE(&force, N_("force"), PARSE_OPT_NOCOMPLETE),
967 OPT__VERBOSE(&verbose, N_("report each affected file, not just directories")),
968 OPT_END(),
969 };
970
971 setup_work_tree();
972 if (!core_apply_sparse_checkout)
973 die(_("must be in a sparse-checkout to clean directories"));
974 if (!core_sparse_checkout_cone)
975 die(_("must be in a cone-mode sparse-checkout to clean directories"));
976
977 argc = parse_options(argc, argv, prefix,
978 builtin_sparse_checkout_clean_options,
979 builtin_sparse_checkout_clean_usage, 0);
980
981 repo_config_get_bool(repo, "clean.requireforce", &require_force);
982 if (require_force && !force && !dry_run)
983 die(_("for safety, refusing to clean without one of --force or --dry-run"));
984
985 if (dry_run)
986 msg = msg_would_remove;
987
988 if (repo_read_index(repo) < 0)
989 die(_("failed to read index"));
990
991 if (convert_to_sparse(repo->index, SPARSE_INDEX_MEMORY_ONLY) ||
992 repo->index->sparse_index == INDEX_EXPANDED)
993 die(_("failed to convert index to a sparse index; resolve merge conflicts and try again"));
994
995 strbuf_addstr(&full_path, repo->worktree);
996 strbuf_addch(&full_path, '/');
997 worktree_len = full_path.len;
998
999 for (size_t i = 0; i < repo->index->cache_nr; i++) {
1000 struct cache_entry *ce = repo->index->cache[i];
1001 if (!S_ISSPARSEDIR(ce->ce_mode))
1002 continue;
1003 strbuf_setlen(&full_path, worktree_len);
1004 strbuf_add(&full_path, ce->name, ce->ce_namelen);
1005
1006 if (!is_directory(full_path.buf))
1007 continue;
1008
1009 if (verbose)
1010 list_every_file_in_dir(msg, ce->name);
1011 else
1012 printf(msg, ce->name);
1013
1014 if (dry_run <= 0 &&
1015 remove_dir_recursively(&full_path, 0))
1016 warning_errno(_("failed to remove '%s'"), ce->name);
1017 }
1018
1019 strbuf_release(&full_path);
1020 return 0;
1021}
1022
1023static char const * const builtin_sparse_checkout_disable_usage[] = {
1024 "git sparse-checkout disable",
1025 NULL
1026};
1027
1028static int sparse_checkout_disable(int argc, const char **argv,
1029 const char *prefix,
1030 struct repository *repo)
1031{
1032 static struct option builtin_sparse_checkout_disable_options[] = {
1033 OPT_END(),
1034 };
1035 struct pattern_list pl;
1036
1037 /*
1038 * We do not exit early if !core_apply_sparse_checkout; due to the
1039 * ability for users to manually muck things up between
1040 * direct editing of .git/info/sparse-checkout
1041 * running read-tree -m u HEAD or update-index --skip-worktree
1042 * direct toggling of config options
1043 * users might end up with an index with SKIP_WORKTREE bit set on
1044 * some files and not know how to undo it. So, here we just
1045 * forcibly return to a dense checkout regardless of initial state.
1046 */
1047
1048 setup_work_tree();
1049 argc = parse_options(argc, argv, prefix,
1050 builtin_sparse_checkout_disable_options,
1051 builtin_sparse_checkout_disable_usage, 0);
1052
1053 /*
1054 * Disable the advice message for expanding a sparse index, as we
1055 * are expecting to do that when disabling sparse-checkout.
1056 */
1057 give_advice_on_expansion = 0;
1058 repo_read_index(repo);
1059
1060 memset(&pl, 0, sizeof(pl));
1061 hashmap_init(&pl.recursive_hashmap, pl_hashmap_cmp, NULL, 0);
1062 hashmap_init(&pl.parent_hashmap, pl_hashmap_cmp, NULL, 0);
1063 pl.use_cone_patterns = 0;
1064 core_apply_sparse_checkout = 1;
1065
1066 add_pattern("/*", empty_base, 0, &pl, 0);
1067
1068 prepare_repo_settings(the_repository);
1069 repo->settings.sparse_index = 0;
1070
1071 if (update_working_directory(repo, &pl))
1072 die(_("error while refreshing working directory"));
1073
1074 clear_pattern_list(&pl);
1075 return set_config(repo, MODE_NO_PATTERNS);
1076}
1077
1078static char const * const builtin_sparse_checkout_check_rules_usage[] = {
1079 N_("git sparse-checkout check-rules [-z] [--skip-checks]"
1080 "[--[no-]cone] [--rules-file <file>]"),
1081 NULL
1082};
1083
1084static struct sparse_checkout_check_rules_opts {
1085 int cone_mode;
1086 int null_termination;
1087 char *rules_file;
1088} check_rules_opts;
1089
1090static int check_rules(struct repository *repo,
1091 struct pattern_list *pl,
1092 int null_terminated)
1093{
1094 struct strbuf line = STRBUF_INIT;
1095 struct strbuf unquoted = STRBUF_INIT;
1096 char *path;
1097 int line_terminator = null_terminated ? 0 : '\n';
1098 strbuf_getline_fn getline_fn = null_terminated ? strbuf_getline_nul
1099 : strbuf_getline;
1100 repo->index->sparse_checkout_patterns = pl;
1101 while (!getline_fn(&line, stdin)) {
1102 path = line.buf;
1103 if (!null_terminated && line.buf[0] == '"') {
1104 strbuf_reset(&unquoted);
1105 if (unquote_c_style(&unquoted, line.buf, NULL))
1106 die(_("unable to unquote C-style string '%s'"),
1107 line.buf);
1108
1109 path = unquoted.buf;
1110 }
1111
1112 if (path_in_sparse_checkout(path, repo->index))
1113 write_name_quoted(path, stdout, line_terminator);
1114 }
1115 strbuf_release(&line);
1116 strbuf_release(&unquoted);
1117
1118 return 0;
1119}
1120
1121static int sparse_checkout_check_rules(int argc, const char **argv, const char *prefix,
1122 struct repository *repo)
1123{
1124 static struct option builtin_sparse_checkout_check_rules_options[] = {
1125 OPT_BOOL('z', NULL, &check_rules_opts.null_termination,
1126 N_("terminate input and output files by a NUL character")),
1127 OPT_BOOL(0, "cone", &check_rules_opts.cone_mode,
1128 N_("when used with --rules-file interpret patterns as cone mode patterns")),
1129 OPT_FILENAME(0, "rules-file", &check_rules_opts.rules_file,
1130 N_("use patterns in <file> instead of the current ones.")),
1131 OPT_END(),
1132 };
1133
1134 FILE *fp;
1135 int ret;
1136 struct pattern_list pl = {0};
1137 char *sparse_filename;
1138 check_rules_opts.cone_mode = -1;
1139
1140 argc = parse_options(argc, argv, prefix,
1141 builtin_sparse_checkout_check_rules_options,
1142 builtin_sparse_checkout_check_rules_usage, 0);
1143
1144 if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
1145 check_rules_opts.cone_mode = 1;
1146
1147 update_cone_mode(&check_rules_opts.cone_mode);
1148 pl.use_cone_patterns = core_sparse_checkout_cone;
1149 if (check_rules_opts.rules_file) {
1150 fp = xfopen(check_rules_opts.rules_file, "r");
1151 add_patterns_from_input(&pl, argc, argv, fp);
1152 fclose(fp);
1153 } else {
1154 sparse_filename = get_sparse_checkout_filename();
1155 if (add_patterns_from_file_to_list(sparse_filename, "", 0, &pl,
1156 NULL, 0))
1157 die(_("unable to load existing sparse-checkout patterns"));
1158 free(sparse_filename);
1159 }
1160
1161 ret = check_rules(repo, &pl, check_rules_opts.null_termination);
1162 clear_pattern_list(&pl);
1163 free(check_rules_opts.rules_file);
1164 return ret;
1165}
1166
1167int cmd_sparse_checkout(int argc,
1168 const char **argv,
1169 const char *prefix,
1170 struct repository *repo)
1171{
1172 parse_opt_subcommand_fn *fn = NULL;
1173 struct option builtin_sparse_checkout_options[] = {
1174 OPT_SUBCOMMAND("list", &fn, sparse_checkout_list),
1175 OPT_SUBCOMMAND("init", &fn, sparse_checkout_init),
1176 OPT_SUBCOMMAND("set", &fn, sparse_checkout_set),
1177 OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
1178 OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
1179 OPT_SUBCOMMAND("clean", &fn, sparse_checkout_clean),
1180 OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
1181 OPT_SUBCOMMAND("check-rules", &fn, sparse_checkout_check_rules),
1182 OPT_END(),
1183 };
1184
1185 argc = parse_options(argc, argv, prefix,
1186 builtin_sparse_checkout_options,
1187 builtin_sparse_checkout_usage, 0);
1188
1189 repo_config(the_repository, git_default_config, NULL);
1190
1191 prepare_repo_settings(repo);
1192 repo->settings.command_requires_full_index = 0;
1193
1194 return fn(argc, argv, prefix, repo);
1195}