Git fork
at reftables-rust 609 lines 18 kB view raw
1/* 2 * "git add" builtin command 3 * 4 * Copyright (C) 2006 Linus Torvalds 5 */ 6 7#include "builtin.h" 8#include "advice.h" 9#include "config.h" 10#include "environment.h" 11#include "lockfile.h" 12#include "editor.h" 13#include "dir.h" 14#include "gettext.h" 15#include "pathspec.h" 16#include "run-command.h" 17#include "object-file.h" 18#include "odb.h" 19#include "parse-options.h" 20#include "path.h" 21#include "preload-index.h" 22#include "diff.h" 23#include "read-cache.h" 24#include "revision.h" 25#include "strvec.h" 26#include "submodule.h" 27#include "add-interactive.h" 28 29static const char * const builtin_add_usage[] = { 30 N_("git add [<options>] [--] <pathspec>..."), 31 NULL 32}; 33static int patch_interactive, add_interactive, edit_interactive; 34static struct add_p_opt add_p_opt = ADD_P_OPT_INIT; 35static int take_worktree_changes; 36static int add_renormalize; 37static int pathspec_file_nul; 38static int include_sparse; 39static const char *pathspec_from_file; 40 41static int chmod_pathspec(struct repository *repo, 42 struct pathspec *pathspec, 43 char flip, 44 int show_only) 45{ 46 int ret = 0; 47 48 for (size_t i = 0; i < repo->index->cache_nr; i++) { 49 struct cache_entry *ce = repo->index->cache[i]; 50 int err; 51 52 if (!include_sparse && 53 (ce_skip_worktree(ce) || 54 !path_in_sparse_checkout(ce->name, repo->index))) 55 continue; 56 57 if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL)) 58 continue; 59 60 if (!show_only) 61 err = chmod_index_entry(repo->index, ce, flip); 62 else 63 err = S_ISREG(ce->ce_mode) ? 0 : -1; 64 65 if (err < 0) 66 ret = error(_("cannot chmod %cx '%s'"), flip, ce->name); 67 } 68 69 return ret; 70} 71 72static int renormalize_tracked_files(struct repository *repo, 73 const struct pathspec *pathspec, 74 int flags) 75{ 76 int retval = 0; 77 78 for (size_t i = 0; i < repo->index->cache_nr; i++) { 79 struct cache_entry *ce = repo->index->cache[i]; 80 81 if (!include_sparse && 82 (ce_skip_worktree(ce) || 83 !path_in_sparse_checkout(ce->name, repo->index))) 84 continue; 85 if (ce_stage(ce)) 86 continue; /* do not touch unmerged paths */ 87 if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode)) 88 continue; /* do not touch non blobs */ 89 if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL)) 90 continue; 91 retval |= add_file_to_index(repo->index, ce->name, 92 flags | ADD_CACHE_RENORMALIZE); 93 } 94 95 return retval; 96} 97 98static char *prune_directory(struct repository *repo, 99 struct dir_struct *dir, 100 struct pathspec *pathspec, 101 int prefix) 102{ 103 char *seen; 104 int i; 105 struct dir_entry **src, **dst; 106 107 seen = xcalloc(pathspec->nr, 1); 108 109 src = dst = dir->entries; 110 i = dir->nr; 111 while (--i >= 0) { 112 struct dir_entry *entry = *src++; 113 if (dir_path_match(repo->index, entry, pathspec, prefix, seen)) 114 *dst++ = entry; 115 } 116 dir->nr = dst - dir->entries; 117 add_pathspec_matches_against_index(pathspec, repo->index, seen, 118 PS_IGNORE_SKIP_WORKTREE); 119 return seen; 120} 121 122static int refresh(struct repository *repo, int verbose, const struct pathspec *pathspec) 123{ 124 char *seen; 125 int i, ret = 0; 126 char *skip_worktree_seen = NULL; 127 struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP; 128 unsigned int flags = REFRESH_IGNORE_SKIP_WORKTREE | 129 (verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET); 130 131 seen = xcalloc(pathspec->nr, 1); 132 refresh_index(repo->index, flags, pathspec, seen, 133 _("Unstaged changes after refreshing the index:")); 134 for (i = 0; i < pathspec->nr; i++) { 135 if (!seen[i]) { 136 const char *path = pathspec->items[i].original; 137 138 if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) || 139 !path_in_sparse_checkout(path, repo->index)) { 140 string_list_append(&only_match_skip_worktree, 141 pathspec->items[i].original); 142 } else { 143 die(_("pathspec '%s' did not match any files"), 144 pathspec->items[i].original); 145 } 146 } 147 } 148 149 if (only_match_skip_worktree.nr) { 150 advise_on_updating_sparse_paths(&only_match_skip_worktree); 151 ret = 1; 152 } 153 154 free(seen); 155 free(skip_worktree_seen); 156 string_list_clear(&only_match_skip_worktree, 0); 157 return ret; 158} 159 160int interactive_add(struct repository *repo, 161 const char **argv, 162 const char *prefix, 163 int patch, struct add_p_opt *add_p_opt) 164{ 165 struct pathspec pathspec; 166 int ret; 167 168 parse_pathspec(&pathspec, 0, 169 PATHSPEC_PREFER_FULL | 170 PATHSPEC_SYMLINK_LEADING_PATH | 171 PATHSPEC_PREFIX_ORIGIN, 172 prefix, argv); 173 174 if (patch) 175 ret = !!run_add_p(repo, ADD_P_ADD, add_p_opt, NULL, &pathspec); 176 else 177 ret = !!run_add_i(repo, &pathspec, add_p_opt); 178 179 clear_pathspec(&pathspec); 180 return ret; 181} 182 183static int edit_patch(struct repository *repo, 184 int argc, 185 const char **argv, 186 const char *prefix) 187{ 188 char *file = repo_git_path(repo, "ADD_EDIT.patch"); 189 struct child_process child = CHILD_PROCESS_INIT; 190 struct rev_info rev; 191 int out; 192 struct stat st; 193 194 repo_config(repo, git_diff_basic_config, NULL); 195 196 if (repo_read_index(repo) < 0) 197 die(_("could not read the index")); 198 199 repo_init_revisions(repo, &rev, prefix); 200 rev.diffopt.context = 7; 201 202 argc = setup_revisions(argc, argv, &rev, NULL); 203 rev.diffopt.output_format = DIFF_FORMAT_PATCH; 204 rev.diffopt.use_color = GIT_COLOR_NEVER; 205 rev.diffopt.flags.ignore_dirty_submodules = 1; 206 out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666); 207 rev.diffopt.file = xfdopen(out, "w"); 208 rev.diffopt.close_file = 1; 209 run_diff_files(&rev, 0); 210 211 if (launch_editor(file, NULL, NULL)) 212 die(_("editing patch failed")); 213 214 if (stat(file, &st)) 215 die_errno(_("could not stat '%s'"), file); 216 if (!st.st_size) 217 die(_("empty patch. aborted")); 218 219 child.git_cmd = 1; 220 strvec_pushl(&child.args, "apply", "--recount", "--cached", file, 221 NULL); 222 if (run_command(&child)) 223 die(_("could not apply '%s'"), file); 224 225 unlink(file); 226 free(file); 227 release_revisions(&rev); 228 return 0; 229} 230 231static const char ignore_error[] = 232N_("The following paths are ignored by one of your .gitignore files:\n"); 233 234static int verbose, show_only, ignored_too, refresh_only; 235static int ignore_add_errors, intent_to_add, ignore_missing; 236static int warn_on_embedded_repo = 1; 237 238#define ADDREMOVE_DEFAULT 1 239static int addremove = ADDREMOVE_DEFAULT; 240static int addremove_explicit = -1; /* unspecified */ 241 242static char *chmod_arg; 243 244static int ignore_removal_cb(const struct option *opt, const char *arg, int unset) 245{ 246 BUG_ON_OPT_ARG(arg); 247 248 /* if we are told to ignore, we are not adding removals */ 249 *(int *)opt->value = !unset ? 0 : 1; 250 return 0; 251} 252 253static struct option builtin_add_options[] = { 254 OPT__DRY_RUN(&show_only, N_("dry run")), 255 OPT__VERBOSE(&verbose, N_("be verbose")), 256 OPT_GROUP(""), 257 OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")), 258 OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")), 259 OPT_DIFF_UNIFIED(&add_p_opt.context), 260 OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), 261 OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")), 262 OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0), 263 OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")), 264 OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")), 265 OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")), 266 OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")), 267 OPT_CALLBACK_F(0, "ignore-removal", &addremove_explicit, 268 NULL /* takes no arguments */, 269 N_("ignore paths removed in the working tree (same as --no-all)"), 270 PARSE_OPT_NOARG, ignore_removal_cb), 271 OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")), 272 OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")), 273 OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")), 274 OPT_BOOL(0, "sparse", &include_sparse, N_("allow updating entries outside of the sparse-checkout cone")), 275 OPT_STRING(0, "chmod", &chmod_arg, "(+|-)x", 276 N_("override the executable bit of the listed files")), 277 OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo, 278 N_("warn when adding an embedded repository")), 279 OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), 280 OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul), 281 OPT_END(), 282}; 283 284static int add_config(const char *var, const char *value, 285 const struct config_context *ctx, void *cb) 286{ 287 if (!strcmp(var, "add.ignoreerrors") || 288 !strcmp(var, "add.ignore-errors")) { 289 ignore_add_errors = git_config_bool(var, value); 290 return 0; 291 } 292 293 if (git_color_config(var, value, cb) < 0) 294 return -1; 295 296 return git_default_config(var, value, ctx, cb); 297} 298 299static const char embedded_advice[] = N_( 300"You've added another git repository inside your current repository.\n" 301"Clones of the outer repository will not contain the contents of\n" 302"the embedded repository and will not know how to obtain it.\n" 303"If you meant to add a submodule, use:\n" 304"\n" 305" git submodule add <url> %s\n" 306"\n" 307"If you added this path by mistake, you can remove it from the\n" 308"index with:\n" 309"\n" 310" git rm --cached %s\n" 311"\n" 312"See \"git help submodule\" for more information." 313); 314 315static void check_embedded_repo(const char *path) 316{ 317 struct strbuf name = STRBUF_INIT; 318 static int adviced_on_embedded_repo = 0; 319 320 if (!warn_on_embedded_repo) 321 return; 322 if (!ends_with(path, "/")) 323 return; 324 325 /* Drop trailing slash for aesthetics */ 326 strbuf_addstr(&name, path); 327 strbuf_strip_suffix(&name, "/"); 328 329 warning(_("adding embedded git repository: %s"), name.buf); 330 if (!adviced_on_embedded_repo) { 331 advise_if_enabled(ADVICE_ADD_EMBEDDED_REPO, 332 embedded_advice, name.buf, name.buf); 333 adviced_on_embedded_repo = 1; 334 } 335 336 strbuf_release(&name); 337} 338 339static int add_files(struct repository *repo, struct dir_struct *dir, int flags) 340{ 341 int i, exit_status = 0; 342 struct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP; 343 344 if (dir->ignored_nr) { 345 fprintf(stderr, _(ignore_error)); 346 for (i = 0; i < dir->ignored_nr; i++) 347 fprintf(stderr, "%s\n", dir->ignored[i]->name); 348 advise_if_enabled(ADVICE_ADD_IGNORED_FILE, 349 _("Use -f if you really want to add them.")); 350 exit_status = 1; 351 } 352 353 for (i = 0; i < dir->nr; i++) { 354 if (!include_sparse && 355 !path_in_sparse_checkout(dir->entries[i]->name, repo->index)) { 356 string_list_append(&matched_sparse_paths, 357 dir->entries[i]->name); 358 continue; 359 } 360 if (add_file_to_index(repo->index, dir->entries[i]->name, flags)) { 361 if (!ignore_add_errors) 362 die(_("adding files failed")); 363 exit_status = 1; 364 } else { 365 check_embedded_repo(dir->entries[i]->name); 366 } 367 } 368 369 if (matched_sparse_paths.nr) { 370 advise_on_updating_sparse_paths(&matched_sparse_paths); 371 exit_status = 1; 372 } 373 374 string_list_clear(&matched_sparse_paths, 0); 375 376 return exit_status; 377} 378 379int cmd_add(int argc, 380 const char **argv, 381 const char *prefix, 382 struct repository *repo) 383{ 384 int exit_status = 0; 385 struct pathspec pathspec; 386 struct dir_struct dir = DIR_INIT; 387 int flags; 388 int add_new_files; 389 int require_pathspec; 390 char *seen = NULL; 391 char *ps_matched = NULL; 392 struct lock_file lock_file = LOCK_INIT; 393 struct odb_transaction *transaction; 394 395 repo_config(repo, add_config, NULL); 396 397 argc = parse_options(argc, argv, prefix, builtin_add_options, 398 builtin_add_usage, PARSE_OPT_KEEP_ARGV0); 399 400 prepare_repo_settings(repo); 401 repo->settings.command_requires_full_index = 0; 402 403 if (add_p_opt.context < -1) 404 die(_("'%s' cannot be negative"), "--unified"); 405 if (add_p_opt.interhunkcontext < -1) 406 die(_("'%s' cannot be negative"), "--inter-hunk-context"); 407 408 if (patch_interactive) 409 add_interactive = 1; 410 if (add_interactive) { 411 if (show_only) 412 die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch"); 413 if (pathspec_from_file) 414 die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch"); 415 exit(interactive_add(repo, argv + 1, prefix, patch_interactive, &add_p_opt)); 416 } else { 417 if (add_p_opt.context != -1) 418 die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch"); 419 if (add_p_opt.interhunkcontext != -1) 420 die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch"); 421 } 422 423 if (edit_interactive) { 424 if (pathspec_from_file) 425 die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--edit"); 426 return(edit_patch(repo, argc, argv, prefix)); 427 } 428 argc--; 429 argv++; 430 431 if (0 <= addremove_explicit) 432 addremove = addremove_explicit; 433 else if (take_worktree_changes && ADDREMOVE_DEFAULT) 434 addremove = 0; /* "-u" was given but not "-A" */ 435 436 if (addremove && take_worktree_changes) 437 die(_("options '%s' and '%s' cannot be used together"), "-A", "-u"); 438 439 if (!show_only && ignore_missing) 440 die(_("the option '%s' requires '%s'"), "--ignore-missing", "--dry-run"); 441 442 if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') || 443 chmod_arg[1] != 'x' || chmod_arg[2])) 444 die(_("--chmod param '%s' must be either -x or +x"), chmod_arg); 445 446 add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize; 447 require_pathspec = !(take_worktree_changes || (0 < addremove_explicit)); 448 449 repo_hold_locked_index(repo, &lock_file, LOCK_DIE_ON_ERROR); 450 451 /* 452 * Check the "pathspec '%s' did not match any files" block 453 * below before enabling new magic. 454 */ 455 parse_pathspec(&pathspec, 0, 456 PATHSPEC_PREFER_FULL | 457 PATHSPEC_SYMLINK_LEADING_PATH, 458 prefix, argv); 459 460 if (pathspec_from_file) { 461 if (pathspec.nr) 462 die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file"); 463 464 parse_pathspec_file(&pathspec, 0, 465 PATHSPEC_PREFER_FULL | 466 PATHSPEC_SYMLINK_LEADING_PATH, 467 prefix, pathspec_from_file, pathspec_file_nul); 468 } else if (pathspec_file_nul) { 469 die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file"); 470 } 471 472 if (require_pathspec && pathspec.nr == 0) { 473 fprintf(stderr, _("Nothing specified, nothing added.\n")); 474 advise_if_enabled(ADVICE_ADD_EMPTY_PATHSPEC, 475 _("Maybe you wanted to say 'git add .'?")); 476 return 0; 477 } 478 479 if (!take_worktree_changes && addremove_explicit < 0 && pathspec.nr) 480 /* Turn "git add pathspec..." to "git add -A pathspec..." */ 481 addremove = 1; 482 483 flags = ((verbose ? ADD_CACHE_VERBOSE : 0) | 484 (show_only ? ADD_CACHE_PRETEND : 0) | 485 (intent_to_add ? ADD_CACHE_INTENT : 0) | 486 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) | 487 (!(addremove || take_worktree_changes) 488 ? ADD_CACHE_IGNORE_REMOVAL : 0)); 489 490 if (repo_read_index_preload(repo, &pathspec, 0) < 0) 491 die(_("index file corrupt")); 492 493 die_in_unpopulated_submodule(repo->index, prefix); 494 die_path_inside_submodule(repo->index, &pathspec); 495 496 if (add_new_files) { 497 int baselen; 498 499 /* Set up the default git porcelain excludes */ 500 if (!ignored_too) { 501 dir.flags |= DIR_COLLECT_IGNORED; 502 setup_standard_excludes(&dir); 503 } 504 505 /* This picks up the paths that are not tracked */ 506 baselen = fill_directory(&dir, repo->index, &pathspec); 507 if (pathspec.nr) 508 seen = prune_directory(repo, &dir, &pathspec, baselen); 509 } 510 511 if (refresh_only) { 512 exit_status |= refresh(repo, verbose, &pathspec); 513 goto finish; 514 } 515 516 if (pathspec.nr) { 517 int i; 518 char *skip_worktree_seen = NULL; 519 struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP; 520 521 if (!seen) 522 seen = find_pathspecs_matching_against_index(&pathspec, 523 repo->index, PS_IGNORE_SKIP_WORKTREE); 524 525 /* 526 * file_exists() assumes exact match 527 */ 528 GUARD_PATHSPEC(&pathspec, 529 PATHSPEC_FROMTOP | 530 PATHSPEC_LITERAL | 531 PATHSPEC_GLOB | 532 PATHSPEC_ICASE | 533 PATHSPEC_EXCLUDE | 534 PATHSPEC_ATTR); 535 536 for (i = 0; i < pathspec.nr; i++) { 537 const char *path = pathspec.items[i].match; 538 539 if (pathspec.items[i].magic & PATHSPEC_EXCLUDE) 540 continue; 541 if (seen[i]) 542 continue; 543 544 if (!include_sparse && 545 matches_skip_worktree(&pathspec, i, &skip_worktree_seen)) { 546 string_list_append(&only_match_skip_worktree, 547 pathspec.items[i].original); 548 continue; 549 } 550 551 /* Don't complain at 'git add .' on empty repo */ 552 if (!path[0]) 553 continue; 554 555 if ((pathspec.items[i].magic & (PATHSPEC_GLOB | PATHSPEC_ICASE)) || 556 !file_exists(path)) { 557 if (ignore_missing) { 558 int dtype = DT_UNKNOWN; 559 if (is_excluded(&dir, repo->index, path, &dtype)) 560 dir_add_ignored(&dir, repo->index, 561 path, pathspec.items[i].len); 562 } else 563 die(_("pathspec '%s' did not match any files"), 564 pathspec.items[i].original); 565 } 566 } 567 568 569 if (only_match_skip_worktree.nr) { 570 advise_on_updating_sparse_paths(&only_match_skip_worktree); 571 exit_status = 1; 572 } 573 574 free(seen); 575 free(skip_worktree_seen); 576 string_list_clear(&only_match_skip_worktree, 0); 577 } 578 579 transaction = odb_transaction_begin(repo->objects); 580 581 ps_matched = xcalloc(pathspec.nr, 1); 582 if (add_renormalize) 583 exit_status |= renormalize_tracked_files(repo, &pathspec, flags); 584 else 585 exit_status |= add_files_to_cache(repo, prefix, 586 &pathspec, ps_matched, 587 include_sparse, flags); 588 589 if (take_worktree_changes && !add_renormalize && !ignore_add_errors && 590 report_path_error(ps_matched, &pathspec)) 591 exit(128); 592 593 if (add_new_files) 594 exit_status |= add_files(repo, &dir, flags); 595 596 if (chmod_arg && pathspec.nr) 597 exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only); 598 odb_transaction_commit(transaction); 599 600finish: 601 if (write_locked_index(repo->index, &lock_file, 602 COMMIT_LOCK | SKIP_IF_UNCHANGED)) 603 die(_("unable to write new index file")); 604 605 free(ps_matched); 606 dir_clear(&dir); 607 clear_pathspec(&pathspec); 608 return exit_status; 609}