builtin / add.con commit git add: avoid "-u/-A without pathspec" warning on stat-dirty paths (0df7b8e)
   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
 144int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
 145{
 146        struct update_callback_data data;
 147        struct rev_info rev;
 148
 149        memset(&data, 0, sizeof(data));
 150        data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
 151        if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
 152                /*
 153                 * Check for modified files throughout the worktree so
 154                 * update_callback has a chance to warn about changes
 155                 * outside the cwd.
 156                 */
 157                data.implicit_dot = prefix;
 158                data.implicit_dot_len = strlen(prefix);
 159                pathspec = NULL;
 160        }
 161
 162        init_revisions(&rev, prefix);
 163        setup_revisions(0, NULL, &rev, NULL);
 164        init_pathspec(&rev.prune_data, pathspec);
 165        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
 166        rev.diffopt.format_callback = update_callback;
 167        rev.diffopt.format_callback_data = &data;
 168        rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
 169        run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
 170        return !!data.add_errors;
 171}
 172
 173#define WARN_IMPLICIT_DOT (1u << 0)
 174static char *prune_directory(struct dir_struct *dir, const char **pathspec,
 175                             int prefix, unsigned flag)
 176{
 177        char *seen;
 178        int i, specs;
 179        struct dir_entry **src, **dst;
 180
 181        for (specs = 0; pathspec[specs];  specs++)
 182                /* nothing */;
 183        seen = xcalloc(specs, 1);
 184
 185        src = dst = dir->entries;
 186        i = dir->nr;
 187        while (--i >= 0) {
 188                struct dir_entry *entry = *src++;
 189                if (match_pathspec(pathspec, entry->name, entry->len,
 190                                   prefix, seen))
 191                        *dst++ = entry;
 192                else if (flag & WARN_IMPLICIT_DOT)
 193                        /*
 194                         * "git add -A" was run from a subdirectory with a
 195                         * new file outside that directory.
 196                         *
 197                         * "git add -A" will behave like "git add -A :/"
 198                         * instead of "git add -A ." in the future.
 199                         * Warn about the coming behavior change.
 200                         */
 201                        warn_pathless_add();
 202        }
 203        dir->nr = dst - dir->entries;
 204        add_pathspec_matches_against_index(pathspec, seen, specs);
 205        return seen;
 206}
 207
 208/*
 209 * Checks the index to see whether any path in pathspec refers to
 210 * something inside a submodule.  If so, dies with an error message.
 211 */
 212static void treat_gitlinks(const char **pathspec)
 213{
 214        int i;
 215
 216        if (!pathspec || !*pathspec)
 217                return;
 218
 219        for (i = 0; pathspec[i]; i++)
 220                pathspec[i] = check_path_for_gitlink(pathspec[i]);
 221}
 222
 223static void refresh(int verbose, const char **pathspec)
 224{
 225        char *seen;
 226        int i, specs;
 227
 228        for (specs = 0; pathspec[specs];  specs++)
 229                /* nothing */;
 230        seen = xcalloc(specs, 1);
 231        refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
 232                      pathspec, seen, _("Unstaged changes after refreshing the index:"));
 233        for (i = 0; i < specs; i++) {
 234                if (!seen[i])
 235                        die(_("pathspec '%s' did not match any files"), pathspec[i]);
 236        }
 237        free(seen);
 238}
 239
 240/*
 241 * Normalizes argv relative to prefix, via get_pathspec(), and then
 242 * runs die_if_path_beyond_symlink() on each path in the normalized
 243 * list.
 244 */
 245static const char **validate_pathspec(const char **argv, const char *prefix)
 246{
 247        const char **pathspec = get_pathspec(prefix, argv);
 248
 249        if (pathspec) {
 250                const char **p;
 251                for (p = pathspec; *p; p++) {
 252                        die_if_path_beyond_symlink(*p, prefix);
 253                }
 254        }
 255
 256        return pathspec;
 257}
 258
 259int run_add_interactive(const char *revision, const char *patch_mode,
 260                        const char **pathspec)
 261{
 262        int status, ac, pc = 0;
 263        const char **args;
 264
 265        if (pathspec)
 266                while (pathspec[pc])
 267                        pc++;
 268
 269        args = xcalloc(sizeof(const char *), (pc + 5));
 270        ac = 0;
 271        args[ac++] = "add--interactive";
 272        if (patch_mode)
 273                args[ac++] = patch_mode;
 274        if (revision)
 275                args[ac++] = revision;
 276        args[ac++] = "--";
 277        if (pc) {
 278                memcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);
 279                ac += pc;
 280        }
 281        args[ac] = NULL;
 282
 283        status = run_command_v_opt(args, RUN_GIT_CMD);
 284        free(args);
 285        return status;
 286}
 287
 288int interactive_add(int argc, const char **argv, const char *prefix, int patch)
 289{
 290        const char **pathspec = NULL;
 291
 292        if (argc) {
 293                pathspec = validate_pathspec(argv, prefix);
 294                if (!pathspec)
 295                        return -1;
 296        }
 297
 298        return run_add_interactive(NULL,
 299                                   patch ? "--patch" : NULL,
 300                                   pathspec);
 301}
 302
 303static int edit_patch(int argc, const char **argv, const char *prefix)
 304{
 305        char *file = git_pathdup("ADD_EDIT.patch");
 306        const char *apply_argv[] = { "apply", "--recount", "--cached",
 307                NULL, NULL };
 308        struct child_process child;
 309        struct rev_info rev;
 310        int out;
 311        struct stat st;
 312
 313        apply_argv[3] = file;
 314
 315        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 316
 317        if (read_cache() < 0)
 318                die (_("Could not read the index"));
 319
 320        init_revisions(&rev, prefix);
 321        rev.diffopt.context = 7;
 322
 323        argc = setup_revisions(argc, argv, &rev, NULL);
 324        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 325        DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 326        out = open(file, O_CREAT | O_WRONLY, 0666);
 327        if (out < 0)
 328                die (_("Could not open '%s' for writing."), file);
 329        rev.diffopt.file = xfdopen(out, "w");
 330        rev.diffopt.close_file = 1;
 331        if (run_diff_files(&rev, 0))
 332                die (_("Could not write patch"));
 333
 334        launch_editor(file, NULL, NULL);
 335
 336        if (stat(file, &st))
 337                die_errno(_("Could not stat '%s'"), file);
 338        if (!st.st_size)
 339                die(_("Empty patch. Aborted."));
 340
 341        memset(&child, 0, sizeof(child));
 342        child.git_cmd = 1;
 343        child.argv = apply_argv;
 344        if (run_command(&child))
 345                die (_("Could not apply '%s'"), file);
 346
 347        unlink(file);
 348        free(file);
 349        return 0;
 350}
 351
 352static struct lock_file lock_file;
 353
 354static const char ignore_error[] =
 355N_("The following paths are ignored by one of your .gitignore files:\n");
 356
 357static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
 358static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0;
 359
 360static struct option builtin_add_options[] = {
 361        OPT__DRY_RUN(&show_only, N_("dry run")),
 362        OPT__VERBOSE(&verbose, N_("be verbose")),
 363        OPT_GROUP(""),
 364        OPT_BOOLEAN('i', "interactive", &add_interactive, N_("interactive picking")),
 365        OPT_BOOLEAN('p', "patch", &patch_interactive, N_("select hunks interactively")),
 366        OPT_BOOLEAN('e', "edit", &edit_interactive, N_("edit current diff and apply")),
 367        OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
 368        OPT_BOOLEAN('u', "update", &take_worktree_changes, N_("update tracked files")),
 369        OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
 370        OPT_BOOLEAN('A', "all", &addremove, N_("add changes from all tracked and untracked files")),
 371        OPT_BOOLEAN( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
 372        OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
 373        OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
 374        OPT_END(),
 375};
 376
 377static int add_config(const char *var, const char *value, void *cb)
 378{
 379        if (!strcmp(var, "add.ignoreerrors") ||
 380            !strcmp(var, "add.ignore-errors")) {
 381                ignore_add_errors = git_config_bool(var, value);
 382                return 0;
 383        }
 384        return git_default_config(var, value, cb);
 385}
 386
 387static int add_files(struct dir_struct *dir, int flags)
 388{
 389        int i, exit_status = 0;
 390
 391        if (dir->ignored_nr) {
 392                fprintf(stderr, _(ignore_error));
 393                for (i = 0; i < dir->ignored_nr; i++)
 394                        fprintf(stderr, "%s\n", dir->ignored[i]->name);
 395                fprintf(stderr, _("Use -f if you really want to add them.\n"));
 396                die(_("no files added"));
 397        }
 398
 399        for (i = 0; i < dir->nr; i++)
 400                if (add_file_to_cache(dir->entries[i]->name, flags)) {
 401                        if (!ignore_add_errors)
 402                                die(_("adding files failed"));
 403                        exit_status = 1;
 404                }
 405        return exit_status;
 406}
 407
 408int cmd_add(int argc, const char **argv, const char *prefix)
 409{
 410        int exit_status = 0;
 411        int newfd;
 412        const char **pathspec;
 413        struct dir_struct dir;
 414        int flags;
 415        int add_new_files;
 416        int require_pathspec;
 417        char *seen = NULL;
 418        int implicit_dot = 0;
 419
 420        git_config(add_config, NULL);
 421
 422        argc = parse_options(argc, argv, prefix, builtin_add_options,
 423                          builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
 424        if (patch_interactive)
 425                add_interactive = 1;
 426        if (add_interactive)
 427                exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
 428
 429        if (edit_interactive)
 430                return(edit_patch(argc, argv, prefix));
 431        argc--;
 432        argv++;
 433
 434        if (addremove && take_worktree_changes)
 435                die(_("-A and -u are mutually incompatible"));
 436        if (!show_only && ignore_missing)
 437                die(_("Option --ignore-missing can only be used together with --dry-run"));
 438        if (addremove) {
 439                option_with_implicit_dot = "--all";
 440                short_option_with_implicit_dot = "-A";
 441        }
 442        if (take_worktree_changes) {
 443                option_with_implicit_dot = "--update";
 444                short_option_with_implicit_dot = "-u";
 445        }
 446        if (option_with_implicit_dot && !argc) {
 447                static const char *here[2] = { ".", NULL };
 448                argc = 1;
 449                argv = here;
 450                implicit_dot = 1;
 451        }
 452
 453        add_new_files = !take_worktree_changes && !refresh_only;
 454        require_pathspec = !take_worktree_changes;
 455
 456        newfd = hold_locked_index(&lock_file, 1);
 457
 458        flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
 459                 (show_only ? ADD_CACHE_PRETEND : 0) |
 460                 (intent_to_add ? ADD_CACHE_INTENT : 0) |
 461                 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
 462                 (!(addremove || take_worktree_changes)
 463                  ? ADD_CACHE_IGNORE_REMOVAL : 0)) |
 464                 (implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0);
 465
 466        if (require_pathspec && argc == 0) {
 467                fprintf(stderr, _("Nothing specified, nothing added.\n"));
 468                fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
 469                return 0;
 470        }
 471        pathspec = validate_pathspec(argv, prefix);
 472
 473        if (read_cache() < 0)
 474                die(_("index file corrupt"));
 475        treat_gitlinks(pathspec);
 476
 477        if (add_new_files) {
 478                int baselen;
 479
 480                /* Set up the default git porcelain excludes */
 481                memset(&dir, 0, sizeof(dir));
 482                if (!ignored_too) {
 483                        dir.flags |= DIR_COLLECT_IGNORED;
 484                        setup_standard_excludes(&dir);
 485                }
 486
 487                /* This picks up the paths that are not tracked */
 488                baselen = fill_directory(&dir, implicit_dot ? NULL : pathspec);
 489                if (pathspec)
 490                        seen = prune_directory(&dir, pathspec, baselen,
 491                                        implicit_dot ? WARN_IMPLICIT_DOT : 0);
 492        }
 493
 494        if (refresh_only) {
 495                refresh(verbose, pathspec);
 496                goto finish;
 497        }
 498        if (implicit_dot && prefix)
 499                refresh_cache(REFRESH_QUIET);
 500
 501        if (pathspec) {
 502                int i;
 503                struct path_exclude_check check;
 504
 505                path_exclude_check_init(&check, &dir);
 506                if (!seen)
 507                        seen = find_pathspecs_matching_against_index(pathspec);
 508                for (i = 0; pathspec[i]; i++) {
 509                        if (!seen[i] && pathspec[i][0]
 510                            && !file_exists(pathspec[i])) {
 511                                if (ignore_missing) {
 512                                        int dtype = DT_UNKNOWN;
 513                                        if (is_path_excluded(&check, pathspec[i], -1, &dtype))
 514                                                dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
 515                                } else
 516                                        die(_("pathspec '%s' did not match any files"),
 517                                            pathspec[i]);
 518                        }
 519                }
 520                free(seen);
 521                path_exclude_check_clear(&check);
 522        }
 523
 524        plug_bulk_checkin();
 525
 526        exit_status |= add_files_to_cache(prefix, pathspec, flags);
 527
 528        if (add_new_files)
 529                exit_status |= add_files(&dir, flags);
 530
 531        unplug_bulk_checkin();
 532
 533 finish:
 534        if (active_cache_changed) {
 535                if (write_cache(newfd, active_cache, active_nr) ||
 536                    commit_locked_index(&lock_file))
 537                        die(_("Unable to write new index file"));
 538        }
 539
 540        return exit_status;
 541}