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