builtin / add.con commit git add <pathspec>... defaults to "-A" (fdc97ab)
   1/*
   2 * "git add" builtin command
   3 *
   4 * Copyright (C) 2006 Linus Torvalds
   5 */
   6#include "cache.h"
   7#include "builtin.h"
   8#include "dir.h"
   9#include "pathspec.h"
  10#include "exec_cmd.h"
  11#include "cache-tree.h"
  12#include "run-command.h"
  13#include "parse-options.h"
  14#include "diff.h"
  15#include "diffcore.h"
  16#include "revision.h"
  17#include "bulk-checkin.h"
  18
  19static const char * const builtin_add_usage[] = {
  20        N_("git add [options] [--] <pathspec>..."),
  21        NULL
  22};
  23static int patch_interactive, add_interactive, edit_interactive;
  24static int take_worktree_changes;
  25
  26struct update_callback_data {
  27        int flags;
  28        int add_errors;
  29        const char *implicit_dot;
  30        size_t implicit_dot_len;
  31};
  32
  33static const char *option_with_implicit_dot;
  34static const char *short_option_with_implicit_dot;
  35
  36static void warn_pathless_add(void)
  37{
  38        static int shown;
  39        assert(option_with_implicit_dot && short_option_with_implicit_dot);
  40
  41        if (shown)
  42                return;
  43        shown = 1;
  44
  45        /*
  46         * To be consistent with "git add -p" and most Git
  47         * commands, we should default to being tree-wide, but
  48         * this is not the original behavior and can't be
  49         * changed until users trained themselves not to type
  50         * "git add -u" or "git add -A". For now, we warn and
  51         * keep the old behavior. Later, the behavior can be changed
  52         * to tree-wide, keeping the warning for a while, and
  53         * eventually we can drop the warning.
  54         */
  55        warning(_("The behavior of 'git add %s (or %s)' with no path argument from a\n"
  56                  "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
  57                  "To add content for the whole tree, run:\n"
  58                  "\n"
  59                  "  git add %s :/\n"
  60                  "  (or git add %s :/)\n"
  61                  "\n"
  62                  "To restrict the command to the current directory, run:\n"
  63                  "\n"
  64                  "  git add %s .\n"
  65                  "  (or git add %s .)\n"
  66                  "\n"
  67                  "With the current Git version, the command is restricted to "
  68                  "the current directory.\n"
  69                  ""),
  70                option_with_implicit_dot, short_option_with_implicit_dot,
  71                option_with_implicit_dot, short_option_with_implicit_dot,
  72                option_with_implicit_dot, short_option_with_implicit_dot);
  73}
  74
  75static int fix_unmerged_status(struct diff_filepair *p,
  76                               struct update_callback_data *data)
  77{
  78        if (p->status != DIFF_STATUS_UNMERGED)
  79                return p->status;
  80        if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
  81                /*
  82                 * This is not an explicit add request, and the
  83                 * path is missing from the working tree (deleted)
  84                 */
  85                return DIFF_STATUS_DELETED;
  86        else
  87                /*
  88                 * Either an explicit add request, or path exists
  89                 * in the working tree.  An attempt to explicitly
  90                 * add a path that does not exist in the working tree
  91                 * will be caught as an error by the caller immediately.
  92                 */
  93                return DIFF_STATUS_MODIFIED;
  94}
  95
  96static void update_callback(struct diff_queue_struct *q,
  97                            struct diff_options *opt, void *cbdata)
  98{
  99        int i;
 100        struct update_callback_data *data = cbdata;
 101        const char *implicit_dot = data->implicit_dot;
 102        size_t implicit_dot_len = data->implicit_dot_len;
 103
 104        for (i = 0; i < q->nr; i++) {
 105                struct diff_filepair *p = q->queue[i];
 106                const char *path = p->one->path;
 107                /*
 108                 * Check if "git add -A" or "git add -u" was run from a
 109                 * subdirectory with a modified file outside that directory,
 110                 * and warn if so.
 111                 *
 112                 * "git add -u" will behave like "git add -u :/" instead of
 113                 * "git add -u ." in the future.  This warning prepares for
 114                 * that change.
 115                 */
 116                if (implicit_dot &&
 117                    strncmp_icase(path, implicit_dot, implicit_dot_len)) {
 118                        warn_pathless_add();
 119                        continue;
 120                }
 121                switch (fix_unmerged_status(p, data)) {
 122                default:
 123                        die(_("unexpected diff status %c"), p->status);
 124                case DIFF_STATUS_MODIFIED:
 125                case DIFF_STATUS_TYPE_CHANGED:
 126                        if (add_file_to_index(&the_index, path, data->flags)) {
 127                                if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
 128                                        die(_("updating files failed"));
 129                                data->add_errors++;
 130                        }
 131                        break;
 132                case DIFF_STATUS_DELETED:
 133                        if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
 134                                break;
 135                        if (!(data->flags & ADD_CACHE_PRETEND))
 136                                remove_file_from_index(&the_index, path);
 137                        if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
 138                                printf(_("remove '%s'\n"), path);
 139                        break;
 140                }
 141        }
 142}
 143
 144static void update_files_in_cache(const char *prefix, const char **pathspec,
 145                                  struct update_callback_data *data)
 146{
 147        struct rev_info rev;
 148
 149        init_revisions(&rev, prefix);
 150        setup_revisions(0, NULL, &rev, NULL);
 151        init_pathspec(&rev.prune_data, pathspec);
 152        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
 153        rev.diffopt.format_callback = update_callback;
 154        rev.diffopt.format_callback_data = data;
 155        rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
 156        run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
 157}
 158
 159int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
 160{
 161        struct update_callback_data data;
 162
 163        memset(&data, 0, sizeof(data));
 164        data.flags = flags;
 165        update_files_in_cache(prefix, pathspec, &data);
 166        return !!data.add_errors;
 167}
 168
 169#define WARN_IMPLICIT_DOT (1u << 0)
 170static char *prune_directory(struct dir_struct *dir, const char **pathspec,
 171                             int prefix, unsigned flag)
 172{
 173        char *seen;
 174        int i, specs;
 175        struct dir_entry **src, **dst;
 176
 177        for (specs = 0; pathspec[specs];  specs++)
 178                /* nothing */;
 179        seen = xcalloc(specs, 1);
 180
 181        src = dst = dir->entries;
 182        i = dir->nr;
 183        while (--i >= 0) {
 184                struct dir_entry *entry = *src++;
 185                if (match_pathspec(pathspec, entry->name, entry->len,
 186                                   prefix, seen))
 187                        *dst++ = entry;
 188                else if (flag & WARN_IMPLICIT_DOT)
 189                        /*
 190                         * "git add -A" was run from a subdirectory with a
 191                         * new file outside that directory.
 192                         *
 193                         * "git add -A" will behave like "git add -A :/"
 194                         * instead of "git add -A ." in the future.
 195                         * Warn about the coming behavior change.
 196                         */
 197                        warn_pathless_add();
 198        }
 199        dir->nr = dst - dir->entries;
 200        add_pathspec_matches_against_index(pathspec, seen, specs);
 201        return seen;
 202}
 203
 204/*
 205 * Checks the index to see whether any path in pathspec refers to
 206 * something inside a submodule.  If so, dies with an error message.
 207 */
 208static void treat_gitlinks(const char **pathspec)
 209{
 210        int i;
 211
 212        if (!pathspec || !*pathspec)
 213                return;
 214
 215        for (i = 0; pathspec[i]; i++)
 216                pathspec[i] = check_path_for_gitlink(pathspec[i]);
 217}
 218
 219static void refresh(int verbose, const char **pathspec)
 220{
 221        char *seen;
 222        int i, specs;
 223
 224        for (specs = 0; pathspec[specs];  specs++)
 225                /* nothing */;
 226        seen = xcalloc(specs, 1);
 227        refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
 228                      pathspec, seen, _("Unstaged changes after refreshing the index:"));
 229        for (i = 0; i < specs; i++) {
 230                if (!seen[i])
 231                        die(_("pathspec '%s' did not match any files"), pathspec[i]);
 232        }
 233        free(seen);
 234}
 235
 236/*
 237 * Normalizes argv relative to prefix, via get_pathspec(), and then
 238 * runs die_if_path_beyond_symlink() on each path in the normalized
 239 * list.
 240 */
 241static const char **validate_pathspec(const char **argv, const char *prefix)
 242{
 243        const char **pathspec = get_pathspec(prefix, argv);
 244
 245        if (pathspec) {
 246                const char **p;
 247                for (p = pathspec; *p; p++) {
 248                        die_if_path_beyond_symlink(*p, prefix);
 249                }
 250        }
 251
 252        return pathspec;
 253}
 254
 255int run_add_interactive(const char *revision, const char *patch_mode,
 256                        const char **pathspec)
 257{
 258        int status, ac, pc = 0;
 259        const char **args;
 260
 261        if (pathspec)
 262                while (pathspec[pc])
 263                        pc++;
 264
 265        args = xcalloc(sizeof(const char *), (pc + 5));
 266        ac = 0;
 267        args[ac++] = "add--interactive";
 268        if (patch_mode)
 269                args[ac++] = patch_mode;
 270        if (revision)
 271                args[ac++] = revision;
 272        args[ac++] = "--";
 273        if (pc) {
 274                memcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);
 275                ac += pc;
 276        }
 277        args[ac] = NULL;
 278
 279        status = run_command_v_opt(args, RUN_GIT_CMD);
 280        free(args);
 281        return status;
 282}
 283
 284int interactive_add(int argc, const char **argv, const char *prefix, int patch)
 285{
 286        const char **pathspec = NULL;
 287
 288        if (argc) {
 289                pathspec = validate_pathspec(argv, prefix);
 290                if (!pathspec)
 291                        return -1;
 292        }
 293
 294        return run_add_interactive(NULL,
 295                                   patch ? "--patch" : NULL,
 296                                   pathspec);
 297}
 298
 299static int edit_patch(int argc, const char **argv, const char *prefix)
 300{
 301        char *file = git_pathdup("ADD_EDIT.patch");
 302        const char *apply_argv[] = { "apply", "--recount", "--cached",
 303                NULL, NULL };
 304        struct child_process child;
 305        struct rev_info rev;
 306        int out;
 307        struct stat st;
 308
 309        apply_argv[3] = file;
 310
 311        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 312
 313        if (read_cache() < 0)
 314                die (_("Could not read the index"));
 315
 316        init_revisions(&rev, prefix);
 317        rev.diffopt.context = 7;
 318
 319        argc = setup_revisions(argc, argv, &rev, NULL);
 320        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 321        DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 322        out = open(file, O_CREAT | O_WRONLY, 0666);
 323        if (out < 0)
 324                die (_("Could not open '%s' for writing."), file);
 325        rev.diffopt.file = xfdopen(out, "w");
 326        rev.diffopt.close_file = 1;
 327        if (run_diff_files(&rev, 0))
 328                die (_("Could not write patch"));
 329
 330        launch_editor(file, NULL, NULL);
 331
 332        if (stat(file, &st))
 333                die_errno(_("Could not stat '%s'"), file);
 334        if (!st.st_size)
 335                die(_("Empty patch. Aborted."));
 336
 337        memset(&child, 0, sizeof(child));
 338        child.git_cmd = 1;
 339        child.argv = apply_argv;
 340        if (run_command(&child))
 341                die (_("Could not apply '%s'"), file);
 342
 343        unlink(file);
 344        free(file);
 345        return 0;
 346}
 347
 348static struct lock_file lock_file;
 349
 350static const char ignore_error[] =
 351N_("The following paths are ignored by one of your .gitignore files:\n");
 352
 353static int verbose, show_only, ignored_too, refresh_only;
 354static int ignore_add_errors, intent_to_add, ignore_missing;
 355
 356#define ADDREMOVE_DEFAULT 1
 357static int addremove = ADDREMOVE_DEFAULT;
 358static int addremove_explicit = -1; /* unspecified */
 359
 360static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
 361{
 362        /* if we are told to ignore, we are not adding removals */
 363        *(int *)opt->value = !unset ? 0 : 1;
 364        return 0;
 365}
 366
 367static struct option builtin_add_options[] = {
 368        OPT__DRY_RUN(&show_only, N_("dry run")),
 369        OPT__VERBOSE(&verbose, N_("be verbose")),
 370        OPT_GROUP(""),
 371        OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
 372        OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
 373        OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
 374        OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
 375        OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
 376        OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
 377        OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
 378        { OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
 379          NULL /* takes no arguments */,
 380          N_("ignore paths removed in the working tree (same as --no-all)"),
 381          PARSE_OPT_NOARG, ignore_removal_cb },
 382        OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
 383        OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
 384        OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
 385        OPT_END(),
 386};
 387
 388static int add_config(const char *var, const char *value, void *cb)
 389{
 390        if (!strcmp(var, "add.ignoreerrors") ||
 391            !strcmp(var, "add.ignore-errors")) {
 392                ignore_add_errors = git_config_bool(var, value);
 393                return 0;
 394        }
 395        return git_default_config(var, value, cb);
 396}
 397
 398static int add_files(struct dir_struct *dir, int flags)
 399{
 400        int i, exit_status = 0;
 401
 402        if (dir->ignored_nr) {
 403                fprintf(stderr, _(ignore_error));
 404                for (i = 0; i < dir->ignored_nr; i++)
 405                        fprintf(stderr, "%s\n", dir->ignored[i]->name);
 406                fprintf(stderr, _("Use -f if you really want to add them.\n"));
 407                die(_("no files added"));
 408        }
 409
 410        for (i = 0; i < dir->nr; i++)
 411                if (add_file_to_cache(dir->entries[i]->name, flags)) {
 412                        if (!ignore_add_errors)
 413                                die(_("adding files failed"));
 414                        exit_status = 1;
 415                }
 416        return exit_status;
 417}
 418
 419int cmd_add(int argc, const char **argv, const char *prefix)
 420{
 421        int exit_status = 0;
 422        int newfd;
 423        const char **pathspec;
 424        struct dir_struct dir;
 425        int flags;
 426        int add_new_files;
 427        int require_pathspec;
 428        char *seen = NULL;
 429        int implicit_dot = 0;
 430        struct update_callback_data update_data;
 431
 432        git_config(add_config, NULL);
 433
 434        argc = parse_options(argc, argv, prefix, builtin_add_options,
 435                          builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
 436        if (patch_interactive)
 437                add_interactive = 1;
 438        if (add_interactive)
 439                exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
 440
 441        if (edit_interactive)
 442                return(edit_patch(argc, argv, prefix));
 443        argc--;
 444        argv++;
 445
 446        if (0 <= addremove_explicit)
 447                addremove = addremove_explicit;
 448        else if (take_worktree_changes && ADDREMOVE_DEFAULT)
 449                addremove = 0; /* "-u" was given but not "-A" */
 450
 451        if (addremove && take_worktree_changes)
 452                die(_("-A and -u are mutually incompatible"));
 453
 454        if (!take_worktree_changes && addremove_explicit < 0 && argc)
 455                /* Turn "git add pathspec..." to "git add -A pathspec..." */
 456                addremove = 1;
 457
 458        if (!show_only && ignore_missing)
 459                die(_("Option --ignore-missing can only be used together with --dry-run"));
 460        if (addremove) {
 461                option_with_implicit_dot = "--all";
 462                short_option_with_implicit_dot = "-A";
 463        }
 464        if (take_worktree_changes) {
 465                option_with_implicit_dot = "--update";
 466                short_option_with_implicit_dot = "-u";
 467        }
 468        if (option_with_implicit_dot && !argc) {
 469                static const char *here[2] = { ".", NULL };
 470                argc = 1;
 471                argv = here;
 472                implicit_dot = 1;
 473        }
 474
 475        add_new_files = !take_worktree_changes && !refresh_only;
 476        require_pathspec = !take_worktree_changes;
 477
 478        newfd = hold_locked_index(&lock_file, 1);
 479
 480        flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
 481                 (show_only ? ADD_CACHE_PRETEND : 0) |
 482                 (intent_to_add ? ADD_CACHE_INTENT : 0) |
 483                 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
 484                 (!(addremove || take_worktree_changes)
 485                  ? ADD_CACHE_IGNORE_REMOVAL : 0)) |
 486                 (implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0);
 487
 488        if (require_pathspec && argc == 0) {
 489                fprintf(stderr, _("Nothing specified, nothing added.\n"));
 490                fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
 491                return 0;
 492        }
 493        pathspec = validate_pathspec(argv, prefix);
 494
 495        if (read_cache() < 0)
 496                die(_("index file corrupt"));
 497        treat_gitlinks(pathspec);
 498
 499        if (add_new_files) {
 500                int baselen;
 501
 502                /* Set up the default git porcelain excludes */
 503                memset(&dir, 0, sizeof(dir));
 504                if (!ignored_too) {
 505                        dir.flags |= DIR_COLLECT_IGNORED;
 506                        setup_standard_excludes(&dir);
 507                }
 508
 509                /* This picks up the paths that are not tracked */
 510                baselen = fill_directory(&dir, implicit_dot ? NULL : pathspec);
 511                if (pathspec)
 512                        seen = prune_directory(&dir, pathspec, baselen,
 513                                        implicit_dot ? WARN_IMPLICIT_DOT : 0);
 514        }
 515
 516        if (refresh_only) {
 517                refresh(verbose, pathspec);
 518                goto finish;
 519        }
 520
 521        if (pathspec) {
 522                int i;
 523                struct path_exclude_check check;
 524
 525                path_exclude_check_init(&check, &dir);
 526                if (!seen)
 527                        seen = find_pathspecs_matching_against_index(pathspec);
 528                for (i = 0; pathspec[i]; i++) {
 529                        if (!seen[i] && pathspec[i][0]
 530                            && !file_exists(pathspec[i])) {
 531                                if (ignore_missing) {
 532                                        int dtype = DT_UNKNOWN;
 533                                        if (is_path_excluded(&check, pathspec[i], -1, &dtype))
 534                                                dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
 535                                } else
 536                                        die(_("pathspec '%s' did not match any files"),
 537                                            pathspec[i]);
 538                        }
 539                }
 540                free(seen);
 541                path_exclude_check_clear(&check);
 542        }
 543
 544        plug_bulk_checkin();
 545
 546        memset(&update_data, 0, sizeof(update_data));
 547        if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
 548                /*
 549                 * Check for modified files throughout the worktree so
 550                 * update_callback has a chance to warn about changes
 551                 * outside the cwd.
 552                 */
 553                update_data.implicit_dot = prefix;
 554                update_data.implicit_dot_len = strlen(prefix);
 555                pathspec = NULL;
 556        }
 557        update_data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
 558        update_files_in_cache(prefix, pathspec, &update_data);
 559
 560        exit_status |= !!update_data.add_errors;
 561        if (add_new_files)
 562                exit_status |= add_files(&dir, flags);
 563
 564        unplug_bulk_checkin();
 565
 566 finish:
 567        if (active_cache_changed) {
 568                if (write_cache(newfd, active_cache, active_nr) ||
 569                    commit_locked_index(&lock_file))
 570                        die(_("Unable to write new index file"));
 571        }
 572
 573        return exit_status;
 574}