]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/add.c
Merge branch 'js/update-index-ignore-removal-for-skip-worktree'
[thirdparty/git.git] / builtin / add.c
CommitLineData
0d781539
LT
1/*
2 * "git add" builtin command
3 *
4 * Copyright (C) 2006 Linus Torvalds
5 */
f8adbec9 6#define USE_THE_INDEX_COMPATIBILITY_MACROS
0d781539 7#include "cache.h"
b2141fc1 8#include "config.h"
0d781539 9#include "builtin.h"
697cc8ef 10#include "lockfile.h"
0d781539 11#include "dir.h"
6f525e71 12#include "pathspec.h"
d807c4a0 13#include "exec-cmd.h"
93872e07 14#include "cache-tree.h"
58680165 15#include "run-command.h"
5c46f754 16#include "parse-options.h"
c59cb03a 17#include "diff.h"
fb7d3f32 18#include "diffcore.h"
c59cb03a 19#include "revision.h"
568508e7 20#include "bulk-checkin.h"
c45a18e8 21#include "argv-array.h"
bdab9721 22#include "submodule.h"
0d781539 23
5c46f754 24static const char * const builtin_add_usage[] = {
9c9b4f2f 25 N_("git add [<options>] [--] <pathspec>..."),
5c46f754
KH
26 NULL
27};
c59cb03a 28static int patch_interactive, add_interactive, edit_interactive;
93c44d49 29static int take_worktree_changes;
9472935d 30static int add_renormalize;
896bdfa2 31
9cba13ca 32struct update_callback_data {
610d55af 33 int flags;
fb7d3f32
LT
34 int add_errors;
35};
36
1e22a991 37static void chmod_pathspec(struct pathspec *pathspec, char flip)
610d55af
TG
38{
39 int i;
40
41 for (i = 0; i < active_nr; i++) {
42 struct cache_entry *ce = active_cache[i];
43
6d2df284 44 if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
610d55af
TG
45 continue;
46
1e22a991
RJ
47 if (chmod_cache_entry(ce, flip) < 0)
48 fprintf(stderr, "cannot chmod %cx '%s'\n", flip, ce->name);
610d55af
TG
49 }
50}
51
75973b2c
JH
52static int fix_unmerged_status(struct diff_filepair *p,
53 struct update_callback_data *data)
54{
55 if (p->status != DIFF_STATUS_UNMERGED)
56 return p->status;
57 if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
58 /*
59 * This is not an explicit add request, and the
60 * path is missing from the working tree (deleted)
61 */
62 return DIFF_STATUS_DELETED;
63 else
64 /*
65 * Either an explicit add request, or path exists
66 * in the working tree. An attempt to explicitly
67 * add a path that does not exist in the working tree
68 * will be caught as an error by the caller immediately.
69 */
70 return DIFF_STATUS_MODIFIED;
71}
72
fb7d3f32
LT
73static void update_callback(struct diff_queue_struct *q,
74 struct diff_options *opt, void *cbdata)
75{
76 int i;
77 struct update_callback_data *data = cbdata;
78
79 for (i = 0; i < q->nr; i++) {
80 struct diff_filepair *p = q->queue[i];
81 const char *path = p->one->path;
75973b2c 82 switch (fix_unmerged_status(p, data)) {
fb7d3f32 83 default:
990ac4be 84 die(_("unexpected diff status %c"), p->status);
fb7d3f32
LT
85 case DIFF_STATUS_MODIFIED:
86 case DIFF_STATUS_TYPE_CHANGED:
610d55af 87 if (add_file_to_index(&the_index, path, data->flags)) {
fb7d3f32 88 if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
990ac4be 89 die(_("updating files failed"));
fb7d3f32
LT
90 data->add_errors++;
91 }
92 break;
93 case DIFF_STATUS_DELETED:
94 if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
95 break;
96 if (!(data->flags & ADD_CACHE_PRETEND))
97 remove_file_from_index(&the_index, path);
98 if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
475c73eb 99 printf(_("remove '%s'\n"), path);
fb7d3f32
LT
100 break;
101 }
102 }
103}
104
610d55af
TG
105int add_files_to_cache(const char *prefix,
106 const struct pathspec *pathspec, int flags)
fb7d3f32 107{
160c4b18 108 struct update_callback_data data;
fb7d3f32 109 struct rev_info rev;
71c7b053 110
160c4b18
JH
111 memset(&data, 0, sizeof(data));
112 data.flags = flags;
113
2abf3503 114 repo_init_revisions(the_repository, &rev, prefix);
fb7d3f32 115 setup_revisions(0, NULL, &rev, NULL);
3efe8e43
NTND
116 if (pathspec)
117 copy_pathspec(&rev.prune_data, pathspec);
fb7d3f32
LT
118 rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
119 rev.diffopt.format_callback = update_callback;
160c4b18 120 rev.diffopt.format_callback_data = &data;
0d1e0e78 121 rev.diffopt.flags.override_submodule_config = 1;
75973b2c 122 rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
fb7d3f32 123 run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
fe6a01af 124 clear_pathspec(&rev.prune_data);
fb7d3f32
LT
125 return !!data.add_errors;
126}
127
9472935d
TB
128static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
129{
130 int i, retval = 0;
131
132 for (i = 0; i < active_nr; i++) {
133 struct cache_entry *ce = active_cache[i];
134
135 if (ce_stage(ce))
136 continue; /* do not touch unmerged paths */
137 if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
138 continue; /* do not touch non blobs */
6d2df284 139 if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
9472935d 140 continue;
9e5da3d0 141 retval |= add_file_to_cache(ce->name, flags | ADD_CACHE_RENORMALIZE);
9472935d
TB
142 }
143
144 return retval;
145}
146
053a6b18 147static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)
0d781539 148{
f2593398 149 char *seen;
84b8b5d1 150 int i;
0d781539
LT
151 struct dir_entry **src, **dst;
152
84b8b5d1 153 seen = xcalloc(pathspec->nr, 1);
f2593398 154
0d781539
LT
155 src = dst = dir->entries;
156 i = dir->nr;
157 while (--i >= 0) {
158 struct dir_entry *entry = *src++;
6d2df284 159 if (dir_path_match(&the_index, entry, pathspec, prefix, seen))
4d06f8ac 160 *dst++ = entry;
0d781539
LT
161 }
162 dir->nr = dst - dir->entries;
08de9151 163 add_pathspec_matches_against_index(pathspec, &the_index, seen);
81f45e7d 164 return seen;
0d781539
LT
165}
166
9b2d6149 167static void refresh(int verbose, const struct pathspec *pathspec)
d616813d
AJ
168{
169 char *seen;
9b2d6149 170 int i;
d616813d 171
9b2d6149 172 seen = xcalloc(pathspec->nr, 1);
43673fdd 173 refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
ed2a808d 174 pathspec, seen, _("Unstaged changes after refreshing the index:"));
9b2d6149 175 for (i = 0; i < pathspec->nr; i++) {
d616813d 176 if (!seen[i])
9b2d6149
NTND
177 die(_("pathspec '%s' did not match any files"),
178 pathspec->items[i].match);
d616813d 179 }
ec36c42a 180 free(seen);
d616813d
AJ
181}
182
46b5139c 183int run_add_interactive(const char *revision, const char *patch_mode,
480ca644 184 const struct pathspec *pathspec)
58680165 185{
c45a18e8
FR
186 int status, i;
187 struct argv_array argv = ARGV_ARRAY_INIT;
3f061887 188
c45a18e8 189 argv_array_push(&argv, "add--interactive");
46b5139c 190 if (patch_mode)
c45a18e8 191 argv_array_push(&argv, patch_mode);
46b5139c 192 if (revision)
c45a18e8
FR
193 argv_array_push(&argv, revision);
194 argv_array_push(&argv, "--");
480ca644
NTND
195 for (i = 0; i < pathspec->nr; i++)
196 /* pass original pathspec, to be re-parsed */
c45a18e8 197 argv_array_push(&argv, pathspec->items[i].original);
7c0ab445 198
c45a18e8
FR
199 status = run_command_v_opt(argv.argv, RUN_GIT_CMD);
200 argv_array_clear(&argv);
7c0ab445 201 return status;
58680165
KH
202}
203
b4bd4668 204int interactive_add(int argc, const char **argv, const char *prefix, int patch)
46b5139c 205{
5a76aff1 206 struct pathspec pathspec;
46b5139c 207
625c3304 208 parse_pathspec(&pathspec, 0,
5a76aff1 209 PATHSPEC_PREFER_FULL |
480ca644
NTND
210 PATHSPEC_SYMLINK_LEADING_PATH |
211 PATHSPEC_PREFIX_ORIGIN,
5a76aff1 212 prefix, argv);
46b5139c
TR
213
214 return run_add_interactive(NULL,
b4bd4668 215 patch ? "--patch" : NULL,
480ca644 216 &pathspec);
46b5139c
TR
217}
218
2af202be 219static int edit_patch(int argc, const char **argv, const char *prefix)
c59cb03a 220{
d292bfaf 221 char *file = git_pathdup("ADD_EDIT.patch");
c59cb03a 222 const char *apply_argv[] = { "apply", "--recount", "--cached",
66dbfd55 223 NULL, NULL };
d3180279 224 struct child_process child = CHILD_PROCESS_INIT;
c59cb03a
JS
225 struct rev_info rev;
226 int out;
227 struct stat st;
228
66dbfd55
GV
229 apply_argv[3] = file;
230
c59cb03a
JS
231 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
232
233 if (read_cache() < 0)
d521abf8 234 die(_("Could not read the index"));
c59cb03a 235
2abf3503 236 repo_init_revisions(the_repository, &rev, prefix);
c59cb03a
JS
237 rev.diffopt.context = 7;
238
239 argc = setup_revisions(argc, argv, &rev, NULL);
240 rev.diffopt.output_format = DIFF_FORMAT_PATCH;
7f3b8c62 241 rev.diffopt.use_color = 0;
0d1e0e78 242 rev.diffopt.flags.ignore_dirty_submodules = 1;
fa6f225e 243 out = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
c59cb03a 244 if (out < 0)
d521abf8 245 die(_("Could not open '%s' for writing."), file);
41698375 246 rev.diffopt.file = xfdopen(out, "w");
c59cb03a
JS
247 rev.diffopt.close_file = 1;
248 if (run_diff_files(&rev, 0))
d521abf8 249 die(_("Could not write patch"));
c59cb03a 250
cb64800d
JK
251 if (launch_editor(file, NULL, NULL))
252 die(_("editing patch failed"));
c59cb03a
JS
253
254 if (stat(file, &st))
990ac4be 255 die_errno(_("Could not stat '%s'"), file);
c59cb03a 256 if (!st.st_size)
990ac4be 257 die(_("Empty patch. Aborted."));
c59cb03a 258
c59cb03a
JS
259 child.git_cmd = 1;
260 child.argv = apply_argv;
261 if (run_command(&child))
d521abf8 262 die(_("Could not apply '%s'"), file);
c59cb03a
JS
263
264 unlink(file);
d292bfaf 265 free(file);
c59cb03a
JS
266 return 0;
267}
268
b39c53e6 269static const char ignore_error[] =
439fb829 270N_("The following paths are ignored by one of your .gitignore files:\n");
6a1ad325 271
300c0a22 272static int verbose, show_only, ignored_too, refresh_only;
45c45e30 273static int ignore_add_errors, intent_to_add, ignore_missing;
53213994 274static int warn_on_embedded_repo = 1;
45c45e30 275
fdc97abd 276#define ADDREMOVE_DEFAULT 1
45c45e30
JH
277static int addremove = ADDREMOVE_DEFAULT;
278static int addremove_explicit = -1; /* unspecified */
5c46f754 279
4e55ed32
ET
280static char *chmod_arg;
281
9f60f49b
JH
282static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
283{
284 /* if we are told to ignore, we are not adding removals */
285 *(int *)opt->value = !unset ? 0 : 1;
286 return 0;
287}
288
5c46f754 289static struct option builtin_add_options[] = {
1b56024c
NTND
290 OPT__DRY_RUN(&show_only, N_("dry run")),
291 OPT__VERBOSE(&verbose, N_("be verbose")),
5c46f754 292 OPT_GROUP(""),
300c0a22
JH
293 OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
294 OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
295 OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
1224781d 296 OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0),
300c0a22 297 OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
9472935d 298 OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")),
300c0a22 299 OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
45c45e30 300 OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
9f60f49b
JH
301 { OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
302 NULL /* takes no arguments */,
303 N_("ignore paths removed in the working tree (same as --no-all)"),
304 PARSE_OPT_NOARG, ignore_removal_cb },
300c0a22
JH
305 OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
306 OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
307 OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
5f0df44c
RS
308 OPT_STRING(0, "chmod", &chmod_arg, "(+|-)x",
309 N_("override the executable bit of the listed files")),
53213994
JK
310 OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
311 N_("warn when adding an embedded repository")),
5c46f754
KH
312 OPT_END(),
313};
314
9bd81e42 315static int add_config(const char *var, const char *value, void *cb)
dad25e4a 316{
8c2be75f
JN
317 if (!strcmp(var, "add.ignoreerrors") ||
318 !strcmp(var, "add.ignore-errors")) {
dad25e4a
AR
319 ignore_add_errors = git_config_bool(var, value);
320 return 0;
321 }
9bd81e42 322 return git_default_config(var, value, cb);
dad25e4a
AR
323}
324
53213994
JK
325static const char embedded_advice[] = N_(
326"You've added another git repository inside your current repository.\n"
327"Clones of the outer repository will not contain the contents of\n"
328"the embedded repository and will not know how to obtain it.\n"
329"If you meant to add a submodule, use:\n"
330"\n"
331" git submodule add <url> %s\n"
332"\n"
333"If you added this path by mistake, you can remove it from the\n"
334"index with:\n"
335"\n"
336" git rm --cached %s\n"
337"\n"
338"See \"git help submodule\" for more information."
339);
340
341static void check_embedded_repo(const char *path)
342{
343 struct strbuf name = STRBUF_INIT;
344
345 if (!warn_on_embedded_repo)
346 return;
347 if (!ends_with(path, "/"))
348 return;
349
350 /* Drop trailing slash for aesthetics */
351 strbuf_addstr(&name, path);
352 strbuf_strip_suffix(&name, "/");
353
354 warning(_("adding embedded git repository: %s"), name.buf);
355 if (advice_add_embedded_repo) {
356 advise(embedded_advice, name.buf, name.buf);
357 /* there may be multiple entries; advise only once */
358 advice_add_embedded_repo = 0;
359 }
360
361 strbuf_release(&name);
362}
363
610d55af 364static int add_files(struct dir_struct *dir, int flags)
c972ec04
JH
365{
366 int i, exit_status = 0;
367
368 if (dir->ignored_nr) {
439fb829 369 fprintf(stderr, _(ignore_error));
c972ec04
JH
370 for (i = 0; i < dir->ignored_nr; i++)
371 fprintf(stderr, "%s\n", dir->ignored[i]->name);
439fb829 372 fprintf(stderr, _("Use -f if you really want to add them.\n"));
1d31e5a2 373 exit_status = 1;
c972ec04
JH
374 }
375
53213994 376 for (i = 0; i < dir->nr; i++) {
610d55af 377 if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
c972ec04 378 if (!ignore_add_errors)
990ac4be 379 die(_("adding files failed"));
c972ec04 380 exit_status = 1;
f937bc2f
KM
381 } else {
382 check_embedded_repo(dir->entries[i]->name);
c972ec04 383 }
53213994 384 }
c972ec04
JH
385 return exit_status;
386}
387
a633fca0 388int cmd_add(int argc, const char **argv, const char *prefix)
0d781539 389{
7ae02a30 390 int exit_status = 0;
5a76aff1 391 struct pathspec pathspec;
0d781539 392 struct dir_struct dir;
610d55af 393 int flags;
c972ec04
JH
394 int add_new_files;
395 int require_pathspec;
81f45e7d 396 char *seen = NULL;
0fa5a2ed 397 struct lock_file lock_file = LOCK_INIT;
5cde71d6 398
ed342fde
SB
399 git_config(add_config, NULL);
400
37782920 401 argc = parse_options(argc, argv, prefix, builtin_add_options,
c59cb03a 402 builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
b63e9950
WC
403 if (patch_interactive)
404 add_interactive = 1;
7c0ab445 405 if (add_interactive)
b4bd4668 406 exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
0d781539 407
c59cb03a
JS
408 if (edit_interactive)
409 return(edit_patch(argc, argv, prefix));
410 argc--;
411 argv++;
412
45c45e30
JH
413 if (0 <= addremove_explicit)
414 addremove = addremove_explicit;
415 else if (take_worktree_changes && ADDREMOVE_DEFAULT)
416 addremove = 0; /* "-u" was given but not "-A" */
417
3ba1f114 418 if (addremove && take_worktree_changes)
990ac4be 419 die(_("-A and -u are mutually incompatible"));
45c45e30 420
45c45e30 421 if (!take_worktree_changes && addremove_explicit < 0 && argc)
fdc97abd
JH
422 /* Turn "git add pathspec..." to "git add -A pathspec..." */
423 addremove = 1;
45c45e30 424
108da0db 425 if (!show_only && ignore_missing)
990ac4be 426 die(_("Option --ignore-missing can only be used together with --dry-run"));
808d3d71 427
610d55af
TG
428 if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') ||
429 chmod_arg[1] != 'x' || chmod_arg[2]))
4e55ed32
ET
430 die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
431
9472935d 432 add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
29abb339 433 require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
c972ec04 434
b3e83cc7 435 hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
0d781539 436
205ffa94 437 flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
01665924 438 (show_only ? ADD_CACHE_PRETEND : 0) |
39425819 439 (intent_to_add ? ADD_CACHE_INTENT : 0) |
1e5f764c
JH
440 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
441 (!(addremove || take_worktree_changes)
808d3d71 442 ? ADD_CACHE_IGNORE_REMOVAL : 0));
205ffa94 443
c972ec04 444 if (require_pathspec && argc == 0) {
990ac4be
ÆAB
445 fprintf(stderr, _("Nothing specified, nothing added.\n"));
446 fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
93b0d86a
JH
447 return 0;
448 }
0d781539 449
5a76aff1
NTND
450 /*
451 * Check the "pathspec '%s' did not match any files" block
452 * below before enabling new magic.
453 */
84d938b7 454 parse_pathspec(&pathspec, PATHSPEC_ATTR,
5a76aff1 455 PATHSPEC_PREFER_FULL |
c08397e3 456 PATHSPEC_SYMLINK_LEADING_PATH,
5a76aff1 457 prefix, argv);
366bfcb6 458
d1664e73
BP
459 if (read_cache_preload(&pathspec) < 0)
460 die(_("index file corrupt"));
461
462 die_in_unpopulated_submodule(&the_index, prefix);
c08397e3
BW
463 die_path_inside_submodule(&the_index, &pathspec);
464
1d8842d9
LT
465 if (add_new_files) {
466 int baselen;
467
468 /* Set up the default git porcelain excludes */
469 memset(&dir, 0, sizeof(dir));
470 if (!ignored_too) {
471 dir.flags |= DIR_COLLECT_IGNORED;
472 setup_standard_excludes(&dir);
473 }
474
1e5f764c 475 /* This picks up the paths that are not tracked */
0d32c183 476 baselen = fill_directory(&dir, &the_index, &pathspec);
5a76aff1 477 if (pathspec.nr)
053a6b18 478 seen = prune_directory(&dir, &pathspec, baselen);
1d8842d9 479 }
1e5f764c 480
c972ec04 481 if (refresh_only) {
9b2d6149 482 refresh(verbose, &pathspec);
c972ec04 483 goto finish;
6a1ad325
JH
484 }
485
5a76aff1 486 if (pathspec.nr) {
81f45e7d 487 int i;
eb69934b 488
81f45e7d 489 if (!seen)
08de9151 490 seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
5a76aff1
NTND
491
492 /*
493 * file_exists() assumes exact match
494 */
bd30c2e4
NTND
495 GUARD_PATHSPEC(&pathspec,
496 PATHSPEC_FROMTOP |
497 PATHSPEC_LITERAL |
93d93537 498 PATHSPEC_GLOB |
ef79b1f8
NTND
499 PATHSPEC_ICASE |
500 PATHSPEC_EXCLUDE);
5a76aff1 501
84b8b5d1
NTND
502 for (i = 0; i < pathspec.nr; i++) {
503 const char *path = pathspec.items[i].match;
ef79b1f8
NTND
504 if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
505 continue;
64ed07ce 506 if (!seen[i] && path[0] &&
93d93537
NTND
507 ((pathspec.items[i].magic &
508 (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
bd30c2e4 509 !file_exists(path))) {
108da0db 510 if (ignore_missing) {
0188f6b3 511 int dtype = DT_UNKNOWN;
a0bba65b 512 if (is_excluded(&dir, &the_index, path, &dtype))
9e58beca
BW
513 dir_add_ignored(&dir, &the_index,
514 path, pathspec.items[i].len);
108da0db 515 } else
48168851 516 die(_("pathspec '%s' did not match any files"),
84b8b5d1 517 pathspec.items[i].original);
108da0db 518 }
81f45e7d
JH
519 }
520 free(seen);
521 }
522
568508e7
JH
523 plug_bulk_checkin();
524
9472935d
TB
525 if (add_renormalize)
526 exit_status |= renormalize_tracked_files(&pathspec, flags);
527 else
528 exit_status |= add_files_to_cache(prefix, &pathspec, flags);
c972ec04
JH
529
530 if (add_new_files)
610d55af 531 exit_status |= add_files(&dir, flags);
0d781539 532
610d55af
TG
533 if (chmod_arg && pathspec.nr)
534 chmod_pathspec(&pathspec, chmod_arg[0]);
568508e7
JH
535 unplug_bulk_checkin();
536
d521abf8 537finish:
61000814
538 if (write_locked_index(&the_index, &lock_file,
539 COMMIT_LOCK | SKIP_IF_UNCHANGED))
540 die(_("Unable to write new index file"));
0d781539 541
0e5bba53
JK
542 UNLEAK(pathspec);
543 UNLEAK(dir);
7ae02a30 544 return exit_status;
0d781539 545}