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