Git fork
at reftables-rust 1195 lines 32 kB view raw
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}