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