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