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