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