cocci: apply "pending" index-compatibility to some "builtin/*.c"
[git.git] / builtin / add.c
blob76277df326b4f47f594e4580f6f645ffa76455f3
1 /*
2 * "git add" builtin command
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"
25 static const char * const builtin_add_usage[] = {
26 N_("git add [<options>] [--] <pathspec>..."),
27 NULL
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;
36 struct update_callback_data {
37 int flags;
38 int add_errors;
41 static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
43 int i, ret = 0;
45 for (i = 0; i < the_index.cache_nr; i++) {
46 struct cache_entry *ce = the_index.cache[i];
47 int err;
49 if (!include_sparse &&
50 (ce_skip_worktree(ce) ||
51 !path_in_sparse_checkout(ce->name, &the_index)))
52 continue;
54 if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
55 continue;
57 if (!show_only)
58 err = chmod_index_entry(&the_index, ce, flip);
59 else
60 err = S_ISREG(ce->ce_mode) ? 0 : -1;
62 if (err < 0)
63 ret = error(_("cannot chmod %cx '%s'"), flip, ce->name);
66 return ret;
69 static int fix_unmerged_status(struct diff_filepair *p,
70 struct update_callback_data *data)
72 if (p->status != DIFF_STATUS_UNMERGED)
73 return p->status;
74 if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
76 * This is not an explicit add request, and the
77 * path is missing from the working tree (deleted)
79 return DIFF_STATUS_DELETED;
80 else
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.
87 return DIFF_STATUS_MODIFIED;
90 static void update_callback(struct diff_queue_struct *q,
91 struct diff_options *opt, void *cbdata)
93 int i;
94 struct update_callback_data *data = cbdata;
96 for (i = 0; i < q->nr; i++) {
97 struct diff_filepair *p = q->queue[i];
98 const char *path = p->one->path;
100 if (!include_sparse && !path_in_sparse_checkout(path, &the_index))
101 continue;
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++;
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;
126 int add_files_to_cache(const char *prefix,
127 const struct pathspec *pathspec, int flags)
129 struct update_callback_data data;
130 struct rev_info rev;
132 memset(&data, 0, sizeof(data));
133 data.flags = flags;
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 */
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.
150 begin_odb_transaction();
151 run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
152 end_odb_transaction();
154 release_revisions(&rev);
155 return !!data.add_errors;
158 static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
160 int i, retval = 0;
162 for (i = 0; i < the_index.cache_nr; i++) {
163 struct cache_entry *ce = the_index.cache[i];
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);
179 return retval;
182 static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)
184 char *seen;
185 int i;
186 struct dir_entry **src, **dst;
188 seen = xcalloc(pathspec->nr, 1);
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;
197 dir->nr = dst - dir->entries;
198 add_pathspec_matches_against_index(pathspec, &the_index, seen,
199 PS_IGNORE_SKIP_WORKTREE);
200 return seen;
203 static int refresh(int verbose, const struct pathspec *pathspec)
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);
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;
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);
230 if (only_match_skip_worktree.nr) {
231 advise_on_updating_sparse_paths(&only_match_skip_worktree);
232 ret = 1;
235 free(seen);
236 free(skip_worktree_seen);
237 string_list_clear(&only_match_skip_worktree, 0);
238 return ret;
241 int run_add_interactive(const char *revision, const char *patch_mode,
242 const struct pathspec *pathspec)
244 int i;
245 struct child_process cmd = CHILD_PROCESS_INIT;
246 int use_builtin_add_i =
247 git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
249 if (use_builtin_add_i < 0 &&
250 git_config_get_bool("add.interactive.usebuiltin",
251 &use_builtin_add_i))
252 use_builtin_add_i = 1;
254 if (use_builtin_add_i != 0) {
255 enum add_p_mode mode;
257 if (!patch_mode)
258 return !!run_add_i(the_repository, pathspec);
260 if (!strcmp(patch_mode, "--patch"))
261 mode = ADD_P_ADD;
262 else if (!strcmp(patch_mode, "--patch=stash"))
263 mode = ADD_P_STASH;
264 else if (!strcmp(patch_mode, "--patch=reset"))
265 mode = ADD_P_RESET;
266 else if (!strcmp(patch_mode, "--patch=checkout"))
267 mode = ADD_P_CHECKOUT;
268 else if (!strcmp(patch_mode, "--patch=worktree"))
269 mode = ADD_P_WORKTREE;
270 else
271 die("'%s' not supported", patch_mode);
273 return !!run_add_p(the_repository, mode, revision, pathspec);
276 strvec_push(&cmd.args, "add--interactive");
277 if (patch_mode)
278 strvec_push(&cmd.args, patch_mode);
279 if (revision)
280 strvec_push(&cmd.args, revision);
281 strvec_push(&cmd.args, "--");
282 for (i = 0; i < pathspec->nr; i++)
283 /* pass original pathspec, to be re-parsed */
284 strvec_push(&cmd.args, pathspec->items[i].original);
286 cmd.git_cmd = 1;
287 return run_command(&cmd);
290 int interactive_add(const char **argv, const char *prefix, int patch)
292 struct pathspec pathspec;
294 parse_pathspec(&pathspec, 0,
295 PATHSPEC_PREFER_FULL |
296 PATHSPEC_SYMLINK_LEADING_PATH |
297 PATHSPEC_PREFIX_ORIGIN,
298 prefix, argv);
300 return run_add_interactive(NULL,
301 patch ? "--patch" : NULL,
302 &pathspec);
305 static int edit_patch(int argc, const char **argv, const char *prefix)
307 char *file = git_pathdup("ADD_EDIT.patch");
308 struct child_process child = CHILD_PROCESS_INIT;
309 struct rev_info rev;
310 int out;
311 struct stat st;
313 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
315 if (repo_read_index(the_repository) < 0)
316 die(_("Could not read the index"));
318 repo_init_revisions(the_repository, &rev, prefix);
319 rev.diffopt.context = 7;
321 argc = setup_revisions(argc, argv, &rev, NULL);
322 rev.diffopt.output_format = DIFF_FORMAT_PATCH;
323 rev.diffopt.use_color = 0;
324 rev.diffopt.flags.ignore_dirty_submodules = 1;
325 out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
326 rev.diffopt.file = xfdopen(out, "w");
327 rev.diffopt.close_file = 1;
328 if (run_diff_files(&rev, 0))
329 die(_("Could not write patch"));
331 if (launch_editor(file, NULL, NULL))
332 die(_("editing patch failed"));
334 if (stat(file, &st))
335 die_errno(_("Could not stat '%s'"), file);
336 if (!st.st_size)
337 die(_("Empty patch. Aborted."));
339 child.git_cmd = 1;
340 strvec_pushl(&child.args, "apply", "--recount", "--cached", file,
341 NULL);
342 if (run_command(&child))
343 die(_("Could not apply '%s'"), file);
345 unlink(file);
346 free(file);
347 release_revisions(&rev);
348 return 0;
351 static const char ignore_error[] =
352 N_("The following paths are ignored by one of your .gitignore files:\n");
354 static int verbose, show_only, ignored_too, refresh_only;
355 static int ignore_add_errors, intent_to_add, ignore_missing;
356 static int warn_on_embedded_repo = 1;
358 #define ADDREMOVE_DEFAULT 1
359 static int addremove = ADDREMOVE_DEFAULT;
360 static int addremove_explicit = -1; /* unspecified */
362 static char *chmod_arg;
364 static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
366 /* if we are told to ignore, we are not adding removals */
367 *(int *)opt->value = !unset ? 0 : 1;
368 return 0;
371 static struct option builtin_add_options[] = {
372 OPT__DRY_RUN(&show_only, N_("dry run")),
373 OPT__VERBOSE(&verbose, N_("be verbose")),
374 OPT_GROUP(""),
375 OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
376 OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
377 OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
378 OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0),
379 OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
380 OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")),
381 OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
382 OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
383 OPT_CALLBACK_F(0, "ignore-removal", &addremove_explicit,
384 NULL /* takes no arguments */,
385 N_("ignore paths removed in the working tree (same as --no-all)"),
386 PARSE_OPT_NOARG, ignore_removal_cb),
387 OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
388 OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
389 OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
390 OPT_BOOL(0, "sparse", &include_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
391 OPT_STRING(0, "chmod", &chmod_arg, "(+|-)x",
392 N_("override the executable bit of the listed files")),
393 OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
394 N_("warn when adding an embedded repository")),
395 OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
396 OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
397 OPT_END(),
400 static int add_config(const char *var, const char *value, void *cb)
402 if (!strcmp(var, "add.ignoreerrors") ||
403 !strcmp(var, "add.ignore-errors")) {
404 ignore_add_errors = git_config_bool(var, value);
405 return 0;
408 return git_default_config(var, value, cb);
411 static const char embedded_advice[] = N_(
412 "You've added another git repository inside your current repository.\n"
413 "Clones of the outer repository will not contain the contents of\n"
414 "the embedded repository and will not know how to obtain it.\n"
415 "If you meant to add a submodule, use:\n"
416 "\n"
417 " git submodule add <url> %s\n"
418 "\n"
419 "If you added this path by mistake, you can remove it from the\n"
420 "index with:\n"
421 "\n"
422 " git rm --cached %s\n"
423 "\n"
424 "See \"git help submodule\" for more information."
427 static void check_embedded_repo(const char *path)
429 struct strbuf name = STRBUF_INIT;
430 static int adviced_on_embedded_repo = 0;
432 if (!warn_on_embedded_repo)
433 return;
434 if (!ends_with(path, "/"))
435 return;
437 /* Drop trailing slash for aesthetics */
438 strbuf_addstr(&name, path);
439 strbuf_strip_suffix(&name, "/");
441 warning(_("adding embedded git repository: %s"), name.buf);
442 if (!adviced_on_embedded_repo &&
443 advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {
444 advise(embedded_advice, name.buf, name.buf);
445 adviced_on_embedded_repo = 1;
448 strbuf_release(&name);
451 static int add_files(struct dir_struct *dir, int flags)
453 int i, exit_status = 0;
454 struct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP;
456 if (dir->ignored_nr) {
457 fprintf(stderr, _(ignore_error));
458 for (i = 0; i < dir->ignored_nr; i++)
459 fprintf(stderr, "%s\n", dir->ignored[i]->name);
460 if (advice_enabled(ADVICE_ADD_IGNORED_FILE))
461 advise(_("Use -f if you really want to add them.\n"
462 "Turn this message off by running\n"
463 "\"git config advice.addIgnoredFile false\""));
464 exit_status = 1;
467 for (i = 0; i < dir->nr; i++) {
468 if (!include_sparse &&
469 !path_in_sparse_checkout(dir->entries[i]->name, &the_index)) {
470 string_list_append(&matched_sparse_paths,
471 dir->entries[i]->name);
472 continue;
474 if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
475 if (!ignore_add_errors)
476 die(_("adding files failed"));
477 exit_status = 1;
478 } else {
479 check_embedded_repo(dir->entries[i]->name);
483 if (matched_sparse_paths.nr) {
484 advise_on_updating_sparse_paths(&matched_sparse_paths);
485 exit_status = 1;
488 string_list_clear(&matched_sparse_paths, 0);
490 return exit_status;
493 int cmd_add(int argc, const char **argv, const char *prefix)
495 int exit_status = 0;
496 struct pathspec pathspec;
497 struct dir_struct dir = DIR_INIT;
498 int flags;
499 int add_new_files;
500 int require_pathspec;
501 char *seen = NULL;
502 struct lock_file lock_file = LOCK_INIT;
504 git_config(add_config, NULL);
506 argc = parse_options(argc, argv, prefix, builtin_add_options,
507 builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
508 if (patch_interactive)
509 add_interactive = 1;
510 if (add_interactive) {
511 if (show_only)
512 die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch");
513 if (pathspec_from_file)
514 die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
515 exit(interactive_add(argv + 1, prefix, patch_interactive));
518 if (edit_interactive) {
519 if (pathspec_from_file)
520 die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--edit");
521 return(edit_patch(argc, argv, prefix));
523 argc--;
524 argv++;
526 if (0 <= addremove_explicit)
527 addremove = addremove_explicit;
528 else if (take_worktree_changes && ADDREMOVE_DEFAULT)
529 addremove = 0; /* "-u" was given but not "-A" */
531 if (addremove && take_worktree_changes)
532 die(_("options '%s' and '%s' cannot be used together"), "-A", "-u");
534 if (!show_only && ignore_missing)
535 die(_("the option '%s' requires '%s'"), "--ignore-missing", "--dry-run");
537 if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') ||
538 chmod_arg[1] != 'x' || chmod_arg[2]))
539 die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
541 add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
542 require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
544 prepare_repo_settings(the_repository);
545 the_repository->settings.command_requires_full_index = 0;
547 repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
550 * Check the "pathspec '%s' did not match any files" block
551 * below before enabling new magic.
553 parse_pathspec(&pathspec, PATHSPEC_ATTR,
554 PATHSPEC_PREFER_FULL |
555 PATHSPEC_SYMLINK_LEADING_PATH,
556 prefix, argv);
558 if (pathspec_from_file) {
559 if (pathspec.nr)
560 die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
562 parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
563 PATHSPEC_PREFER_FULL |
564 PATHSPEC_SYMLINK_LEADING_PATH,
565 prefix, pathspec_from_file, pathspec_file_nul);
566 } else if (pathspec_file_nul) {
567 die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
570 if (require_pathspec && pathspec.nr == 0) {
571 fprintf(stderr, _("Nothing specified, nothing added.\n"));
572 if (advice_enabled(ADVICE_ADD_EMPTY_PATHSPEC))
573 advise( _("Maybe you wanted to say 'git add .'?\n"
574 "Turn this message off by running\n"
575 "\"git config advice.addEmptyPathspec false\""));
576 return 0;
579 if (!take_worktree_changes && addremove_explicit < 0 && pathspec.nr)
580 /* Turn "git add pathspec..." to "git add -A pathspec..." */
581 addremove = 1;
583 flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
584 (show_only ? ADD_CACHE_PRETEND : 0) |
585 (intent_to_add ? ADD_CACHE_INTENT : 0) |
586 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
587 (!(addremove || take_worktree_changes)
588 ? ADD_CACHE_IGNORE_REMOVAL : 0));
590 if (repo_read_index_preload(the_repository, &pathspec, 0) < 0)
591 die(_("index file corrupt"));
593 die_in_unpopulated_submodule(&the_index, prefix);
594 die_path_inside_submodule(&the_index, &pathspec);
596 if (add_new_files) {
597 int baselen;
599 /* Set up the default git porcelain excludes */
600 if (!ignored_too) {
601 dir.flags |= DIR_COLLECT_IGNORED;
602 setup_standard_excludes(&dir);
605 /* This picks up the paths that are not tracked */
606 baselen = fill_directory(&dir, &the_index, &pathspec);
607 if (pathspec.nr)
608 seen = prune_directory(&dir, &pathspec, baselen);
611 if (refresh_only) {
612 exit_status |= refresh(verbose, &pathspec);
613 goto finish;
616 if (pathspec.nr) {
617 int i;
618 char *skip_worktree_seen = NULL;
619 struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
621 if (!seen)
622 seen = find_pathspecs_matching_against_index(&pathspec,
623 &the_index, PS_IGNORE_SKIP_WORKTREE);
626 * file_exists() assumes exact match
628 GUARD_PATHSPEC(&pathspec,
629 PATHSPEC_FROMTOP |
630 PATHSPEC_LITERAL |
631 PATHSPEC_GLOB |
632 PATHSPEC_ICASE |
633 PATHSPEC_EXCLUDE);
635 for (i = 0; i < pathspec.nr; i++) {
636 const char *path = pathspec.items[i].match;
638 if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
639 continue;
640 if (seen[i])
641 continue;
643 if (!include_sparse &&
644 matches_skip_worktree(&pathspec, i, &skip_worktree_seen)) {
645 string_list_append(&only_match_skip_worktree,
646 pathspec.items[i].original);
647 continue;
650 /* Don't complain at 'git add .' on empty repo */
651 if (!path[0])
652 continue;
654 if ((pathspec.items[i].magic & (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
655 !file_exists(path)) {
656 if (ignore_missing) {
657 int dtype = DT_UNKNOWN;
658 if (is_excluded(&dir, &the_index, path, &dtype))
659 dir_add_ignored(&dir, &the_index,
660 path, pathspec.items[i].len);
661 } else
662 die(_("pathspec '%s' did not match any files"),
663 pathspec.items[i].original);
668 if (only_match_skip_worktree.nr) {
669 advise_on_updating_sparse_paths(&only_match_skip_worktree);
670 exit_status = 1;
673 free(seen);
674 free(skip_worktree_seen);
675 string_list_clear(&only_match_skip_worktree, 0);
678 begin_odb_transaction();
680 if (add_renormalize)
681 exit_status |= renormalize_tracked_files(&pathspec, flags);
682 else
683 exit_status |= add_files_to_cache(prefix, &pathspec, flags);
685 if (add_new_files)
686 exit_status |= add_files(&dir, flags);
688 if (chmod_arg && pathspec.nr)
689 exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
690 end_odb_transaction();
692 finish:
693 if (write_locked_index(&the_index, &lock_file,
694 COMMIT_LOCK | SKIP_IF_UNCHANGED))
695 die(_("Unable to write new index file"));
697 dir_clear(&dir);
698 UNLEAK(pathspec);
699 return exit_status;