f5d6a33a6a4a9b0c8459bcfeafd8bf17d469db7e
   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 '--ignore-removal',\n"
 101"whose behaviour will change in Git 2.0 with respect to paths you removed.\n"
 102"Paths like '%s' that are\n"
 103"removed from your working tree are ignored with this version of Git.\n"
 104"\n"
 105"* 'git add --ignore-removal <pathspec>', which is the current default,\n"
 106"  ignores 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
 229static void refresh(int verbose, const struct pathspec *pathspec)
 230{
 231        char *seen;
 232        int i;
 233
 234        seen = xcalloc(pathspec->nr, 1);
 235        refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
 236                      pathspec, seen, _("Unstaged changes after refreshing the index:"));
 237        for (i = 0; i < pathspec->nr; i++) {
 238                if (!seen[i])
 239                        die(_("pathspec '%s' did not match any files"),
 240                            pathspec->items[i].match);
 241        }
 242        free(seen);
 243}
 244
 245int run_add_interactive(const char *revision, const char *patch_mode,
 246                        const struct pathspec *pathspec)
 247{
 248        int status, ac, i;
 249        const char **args;
 250
 251        args = xcalloc(sizeof(const char *), (pathspec->nr + 6));
 252        ac = 0;
 253        args[ac++] = "add--interactive";
 254        if (patch_mode)
 255                args[ac++] = patch_mode;
 256        if (revision)
 257                args[ac++] = revision;
 258        args[ac++] = "--";
 259        for (i = 0; i < pathspec->nr; i++)
 260                /* pass original pathspec, to be re-parsed */
 261                args[ac++] = pathspec->items[i].original;
 262
 263        status = run_command_v_opt(args, RUN_GIT_CMD);
 264        free(args);
 265        return status;
 266}
 267
 268int interactive_add(int argc, const char **argv, const char *prefix, int patch)
 269{
 270        struct pathspec pathspec;
 271
 272        /*
 273         * git-add--interactive itself does not parse pathspec. It
 274         * simply passes the pathspec to other builtin commands. Let's
 275         * hope all of them support all magic, or we'll need to limit
 276         * the magic here.
 277         */
 278        parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
 279                       PATHSPEC_PREFER_FULL |
 280                       PATHSPEC_SYMLINK_LEADING_PATH |
 281                       PATHSPEC_PREFIX_ORIGIN,
 282                       prefix, argv);
 283
 284        return run_add_interactive(NULL,
 285                                   patch ? "--patch" : NULL,
 286                                   &pathspec);
 287}
 288
 289static int edit_patch(int argc, const char **argv, const char *prefix)
 290{
 291        char *file = git_pathdup("ADD_EDIT.patch");
 292        const char *apply_argv[] = { "apply", "--recount", "--cached",
 293                NULL, NULL };
 294        struct child_process child;
 295        struct rev_info rev;
 296        int out;
 297        struct stat st;
 298
 299        apply_argv[3] = file;
 300
 301        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 302
 303        if (read_cache() < 0)
 304                die (_("Could not read the index"));
 305
 306        init_revisions(&rev, prefix);
 307        rev.diffopt.context = 7;
 308
 309        argc = setup_revisions(argc, argv, &rev, NULL);
 310        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 311        DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 312        out = open(file, O_CREAT | O_WRONLY, 0666);
 313        if (out < 0)
 314                die (_("Could not open '%s' for writing."), file);
 315        rev.diffopt.file = xfdopen(out, "w");
 316        rev.diffopt.close_file = 1;
 317        if (run_diff_files(&rev, 0))
 318                die (_("Could not write patch"));
 319
 320        launch_editor(file, NULL, NULL);
 321
 322        if (stat(file, &st))
 323                die_errno(_("Could not stat '%s'"), file);
 324        if (!st.st_size)
 325                die(_("Empty patch. Aborted."));
 326
 327        memset(&child, 0, sizeof(child));
 328        child.git_cmd = 1;
 329        child.argv = apply_argv;
 330        if (run_command(&child))
 331                die (_("Could not apply '%s'"), file);
 332
 333        unlink(file);
 334        free(file);
 335        return 0;
 336}
 337
 338static struct lock_file lock_file;
 339
 340static const char ignore_error[] =
 341N_("The following paths are ignored by one of your .gitignore files:\n");
 342
 343static int verbose, show_only, ignored_too, refresh_only;
 344static int ignore_add_errors, intent_to_add, ignore_missing;
 345
 346#define ADDREMOVE_DEFAULT 0 /* Change to 1 in Git 2.0 */
 347static int addremove = ADDREMOVE_DEFAULT;
 348static int addremove_explicit = -1; /* unspecified */
 349
 350static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
 351{
 352        /* if we are told to ignore, we are not adding removals */
 353        *(int *)opt->value = !unset ? 0 : 1;
 354        return 0;
 355}
 356
 357static struct option builtin_add_options[] = {
 358        OPT__DRY_RUN(&show_only, N_("dry run")),
 359        OPT__VERBOSE(&verbose, N_("be verbose")),
 360        OPT_GROUP(""),
 361        OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
 362        OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
 363        OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
 364        OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
 365        OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
 366        OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
 367        OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
 368        { OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
 369          NULL /* takes no arguments */,
 370          N_("ignore paths removed in the working tree (same as --no-all)"),
 371          PARSE_OPT_NOARG, ignore_removal_cb },
 372        OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
 373        OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
 374        OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
 375        OPT_END(),
 376};
 377
 378static int add_config(const char *var, const char *value, void *cb)
 379{
 380        if (!strcmp(var, "add.ignoreerrors") ||
 381            !strcmp(var, "add.ignore-errors")) {
 382                ignore_add_errors = git_config_bool(var, value);
 383                return 0;
 384        }
 385        return git_default_config(var, value, cb);
 386}
 387
 388static int add_files(struct dir_struct *dir, int flags)
 389{
 390        int i, exit_status = 0;
 391
 392        if (dir->ignored_nr) {
 393                fprintf(stderr, _(ignore_error));
 394                for (i = 0; i < dir->ignored_nr; i++)
 395                        fprintf(stderr, "%s\n", dir->ignored[i]->name);
 396                fprintf(stderr, _("Use -f if you really want to add them.\n"));
 397                die(_("no files added"));
 398        }
 399
 400        for (i = 0; i < dir->nr; i++)
 401                if (add_file_to_cache(dir->entries[i]->name, flags)) {
 402                        if (!ignore_add_errors)
 403                                die(_("adding files failed"));
 404                        exit_status = 1;
 405                }
 406        return exit_status;
 407}
 408
 409int cmd_add(int argc, const char **argv, const char *prefix)
 410{
 411        int exit_status = 0;
 412        int newfd;
 413        struct pathspec pathspec;
 414        struct dir_struct dir;
 415        int flags;
 416        int add_new_files;
 417        int require_pathspec;
 418        char *seen = NULL;
 419        int implicit_dot = 0;
 420        struct update_callback_data update_data;
 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        /*
 445         * Warn when "git add pathspec..." was given without "-u" or "-A"
 446         * and pathspec... covers a removed path.
 447         */
 448        memset(&update_data, 0, sizeof(update_data));
 449        if (!take_worktree_changes && addremove_explicit < 0)
 450                update_data.warn_add_would_remove = 1;
 451
 452        if (!take_worktree_changes && addremove_explicit < 0 && argc)
 453                /*
 454                 * Turn "git add pathspec..." to "git add -A pathspec..."
 455                 * in Git 2.0 but not yet
 456                 */
 457                ; /* addremove = 1; */
 458
 459        if (!show_only && ignore_missing)
 460                die(_("Option --ignore-missing can only be used together with --dry-run"));
 461        if (addremove) {
 462                option_with_implicit_dot = "--all";
 463                short_option_with_implicit_dot = "-A";
 464        }
 465        if (take_worktree_changes) {
 466                option_with_implicit_dot = "--update";
 467                short_option_with_implicit_dot = "-u";
 468        }
 469        if (option_with_implicit_dot && !argc) {
 470                static const char *here[2] = { ".", NULL };
 471                argc = 1;
 472                argv = here;
 473                implicit_dot = 1;
 474        }
 475
 476        add_new_files = !take_worktree_changes && !refresh_only;
 477        require_pathspec = !take_worktree_changes;
 478
 479        newfd = hold_locked_index(&lock_file, 1);
 480
 481        flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
 482                 (show_only ? ADD_CACHE_PRETEND : 0) |
 483                 (intent_to_add ? ADD_CACHE_INTENT : 0) |
 484                 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
 485                 (!(addremove || take_worktree_changes)
 486                  ? ADD_CACHE_IGNORE_REMOVAL : 0)) |
 487                 (implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0);
 488
 489        if (require_pathspec && argc == 0) {
 490                fprintf(stderr, _("Nothing specified, nothing added.\n"));
 491                fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
 492                return 0;
 493        }
 494
 495        if (read_cache() < 0)
 496                die(_("index file corrupt"));
 497
 498        /*
 499         * Check the "pathspec '%s' did not match any files" block
 500         * below before enabling new magic.
 501         */
 502        parse_pathspec(&pathspec, 0,
 503                       PATHSPEC_PREFER_FULL |
 504                       PATHSPEC_SYMLINK_LEADING_PATH |
 505                       PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE,
 506                       prefix, argv);
 507
 508        if (add_new_files) {
 509                int baselen;
 510
 511                /* Set up the default git porcelain excludes */
 512                memset(&dir, 0, sizeof(dir));
 513                if (!ignored_too) {
 514                        dir.flags |= DIR_COLLECT_IGNORED;
 515                        setup_standard_excludes(&dir);
 516                }
 517
 518                /* This picks up the paths that are not tracked */
 519                baselen = fill_directory(&dir, implicit_dot ? NULL : pathspec.raw);
 520                if (pathspec.nr)
 521                        seen = prune_directory(&dir, pathspec.raw, baselen,
 522                                        implicit_dot ? WARN_IMPLICIT_DOT : 0);
 523        }
 524
 525        if (refresh_only) {
 526                refresh(verbose, &pathspec);
 527                goto finish;
 528        }
 529        if (implicit_dot && prefix)
 530                refresh_cache(REFRESH_QUIET);
 531
 532        if (pathspec.nr) {
 533                int i;
 534
 535                if (!seen)
 536                        seen = find_pathspecs_matching_against_index(pathspec.raw);
 537
 538                /*
 539                 * file_exists() assumes exact match
 540                 */
 541                GUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);
 542
 543                for (i = 0; pathspec.raw[i]; i++) {
 544                        if (!seen[i] && pathspec.raw[i][0]
 545                            && !file_exists(pathspec.raw[i])) {
 546                                if (ignore_missing) {
 547                                        int dtype = DT_UNKNOWN;
 548                                        if (is_excluded(&dir, pathspec.raw[i], &dtype))
 549                                                dir_add_ignored(&dir, pathspec.raw[i], strlen(pathspec.raw[i]));
 550                                } else
 551                                        die(_("pathspec '%s' did not match any files"),
 552                                            pathspec.raw[i]);
 553                        }
 554                }
 555                free(seen);
 556        }
 557
 558        plug_bulk_checkin();
 559
 560        if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
 561                /*
 562                 * Check for modified files throughout the worktree so
 563                 * update_callback has a chance to warn about changes
 564                 * outside the cwd.
 565                 */
 566                update_data.implicit_dot = prefix;
 567                update_data.implicit_dot_len = strlen(prefix);
 568                free_pathspec(&pathspec);
 569                memset(&pathspec, 0, sizeof(pathspec));
 570        }
 571        update_data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
 572        update_files_in_cache(prefix, pathspec.raw, &update_data);
 573
 574        exit_status |= !!update_data.add_errors;
 575        if (add_new_files)
 576                exit_status |= add_files(&dir, flags);
 577
 578        unplug_bulk_checkin();
 579
 580 finish:
 581        if (active_cache_changed) {
 582                if (write_cache(newfd, active_cache, active_nr) ||
 583                    commit_locked_index(&lock_file))
 584                        die(_("Unable to write new index file"));
 585        }
 586
 587        return exit_status;
 588}