builtin / add.con commit Merge branch 'mh/ref-lock-entry' (f2dd90f)
   1/*
   2 * "git add" builtin command
   3 *
   4 * Copyright (C) 2006 Linus Torvalds
   5 */
   6#include "cache.h"
   7#include "config.h"
   8#include "builtin.h"
   9#include "lockfile.h"
  10#include "dir.h"
  11#include "pathspec.h"
  12#include "exec_cmd.h"
  13#include "cache-tree.h"
  14#include "run-command.h"
  15#include "parse-options.h"
  16#include "diff.h"
  17#include "diffcore.h"
  18#include "revision.h"
  19#include "bulk-checkin.h"
  20#include "argv-array.h"
  21#include "submodule.h"
  22
  23static const char * const builtin_add_usage[] = {
  24        N_("git add [<options>] [--] <pathspec>..."),
  25        NULL
  26};
  27static int patch_interactive, add_interactive, edit_interactive;
  28static int take_worktree_changes;
  29
  30struct update_callback_data {
  31        int flags;
  32        int add_errors;
  33};
  34
  35static void chmod_pathspec(struct pathspec *pathspec, char flip)
  36{
  37        int i;
  38
  39        for (i = 0; i < active_nr; i++) {
  40                struct cache_entry *ce = active_cache[i];
  41
  42                if (pathspec && !ce_path_match(ce, pathspec, NULL))
  43                        continue;
  44
  45                if (chmod_cache_entry(ce, flip) < 0)
  46                        fprintf(stderr, "cannot chmod %cx '%s'\n", flip, ce->name);
  47        }
  48}
  49
  50static int fix_unmerged_status(struct diff_filepair *p,
  51                               struct update_callback_data *data)
  52{
  53        if (p->status != DIFF_STATUS_UNMERGED)
  54                return p->status;
  55        if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
  56                /*
  57                 * This is not an explicit add request, and the
  58                 * path is missing from the working tree (deleted)
  59                 */
  60                return DIFF_STATUS_DELETED;
  61        else
  62                /*
  63                 * Either an explicit add request, or path exists
  64                 * in the working tree.  An attempt to explicitly
  65                 * add a path that does not exist in the working tree
  66                 * will be caught as an error by the caller immediately.
  67                 */
  68                return DIFF_STATUS_MODIFIED;
  69}
  70
  71static void update_callback(struct diff_queue_struct *q,
  72                            struct diff_options *opt, void *cbdata)
  73{
  74        int i;
  75        struct update_callback_data *data = cbdata;
  76
  77        for (i = 0; i < q->nr; i++) {
  78                struct diff_filepair *p = q->queue[i];
  79                const char *path = p->one->path;
  80                switch (fix_unmerged_status(p, data)) {
  81                default:
  82                        die(_("unexpected diff status %c"), p->status);
  83                case DIFF_STATUS_MODIFIED:
  84                case DIFF_STATUS_TYPE_CHANGED:
  85                        if (add_file_to_index(&the_index, path, data->flags)) {
  86                                if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
  87                                        die(_("updating files failed"));
  88                                data->add_errors++;
  89                        }
  90                        break;
  91                case DIFF_STATUS_DELETED:
  92                        if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
  93                                break;
  94                        if (!(data->flags & ADD_CACHE_PRETEND))
  95                                remove_file_from_index(&the_index, path);
  96                        if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
  97                                printf(_("remove '%s'\n"), path);
  98                        break;
  99                }
 100        }
 101}
 102
 103int add_files_to_cache(const char *prefix,
 104                       const struct pathspec *pathspec, int flags)
 105{
 106        struct update_callback_data data;
 107        struct rev_info rev;
 108
 109        memset(&data, 0, sizeof(data));
 110        data.flags = flags;
 111
 112        init_revisions(&rev, prefix);
 113        setup_revisions(0, NULL, &rev, NULL);
 114        if (pathspec)
 115                copy_pathspec(&rev.prune_data, pathspec);
 116        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
 117        rev.diffopt.format_callback = update_callback;
 118        rev.diffopt.format_callback_data = &data;
 119        rev.diffopt.flags |= DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
 120        rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
 121        run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
 122        return !!data.add_errors;
 123}
 124
 125static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)
 126{
 127        char *seen;
 128        int i;
 129        struct dir_entry **src, **dst;
 130
 131        seen = xcalloc(pathspec->nr, 1);
 132
 133        src = dst = dir->entries;
 134        i = dir->nr;
 135        while (--i >= 0) {
 136                struct dir_entry *entry = *src++;
 137                if (dir_path_match(entry, pathspec, prefix, seen))
 138                        *dst++ = entry;
 139        }
 140        dir->nr = dst - dir->entries;
 141        add_pathspec_matches_against_index(pathspec, &the_index, seen);
 142        return seen;
 143}
 144
 145static void refresh(int verbose, const struct pathspec *pathspec)
 146{
 147        char *seen;
 148        int i;
 149
 150        seen = xcalloc(pathspec->nr, 1);
 151        refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
 152                      pathspec, seen, _("Unstaged changes after refreshing the index:"));
 153        for (i = 0; i < pathspec->nr; i++) {
 154                if (!seen[i])
 155                        die(_("pathspec '%s' did not match any files"),
 156                            pathspec->items[i].match);
 157        }
 158        free(seen);
 159}
 160
 161int run_add_interactive(const char *revision, const char *patch_mode,
 162                        const struct pathspec *pathspec)
 163{
 164        int status, i;
 165        struct argv_array argv = ARGV_ARRAY_INIT;
 166
 167        argv_array_push(&argv, "add--interactive");
 168        if (patch_mode)
 169                argv_array_push(&argv, patch_mode);
 170        if (revision)
 171                argv_array_push(&argv, revision);
 172        argv_array_push(&argv, "--");
 173        for (i = 0; i < pathspec->nr; i++)
 174                /* pass original pathspec, to be re-parsed */
 175                argv_array_push(&argv, pathspec->items[i].original);
 176
 177        status = run_command_v_opt(argv.argv, RUN_GIT_CMD);
 178        argv_array_clear(&argv);
 179        return status;
 180}
 181
 182int interactive_add(int argc, const char **argv, const char *prefix, int patch)
 183{
 184        struct pathspec pathspec;
 185
 186        parse_pathspec(&pathspec, 0,
 187                       PATHSPEC_PREFER_FULL |
 188                       PATHSPEC_SYMLINK_LEADING_PATH |
 189                       PATHSPEC_PREFIX_ORIGIN,
 190                       prefix, argv);
 191
 192        return run_add_interactive(NULL,
 193                                   patch ? "--patch" : NULL,
 194                                   &pathspec);
 195}
 196
 197static int edit_patch(int argc, const char **argv, const char *prefix)
 198{
 199        char *file = git_pathdup("ADD_EDIT.patch");
 200        const char *apply_argv[] = { "apply", "--recount", "--cached",
 201                NULL, NULL };
 202        struct child_process child = CHILD_PROCESS_INIT;
 203        struct rev_info rev;
 204        int out;
 205        struct stat st;
 206
 207        apply_argv[3] = file;
 208
 209        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 210
 211        if (read_cache() < 0)
 212                die(_("Could not read the index"));
 213
 214        init_revisions(&rev, prefix);
 215        rev.diffopt.context = 7;
 216
 217        argc = setup_revisions(argc, argv, &rev, NULL);
 218        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 219        rev.diffopt.use_color = 0;
 220        DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
 221        out = open(file, O_CREAT | O_WRONLY, 0666);
 222        if (out < 0)
 223                die(_("Could not open '%s' for writing."), file);
 224        rev.diffopt.file = xfdopen(out, "w");
 225        rev.diffopt.close_file = 1;
 226        if (run_diff_files(&rev, 0))
 227                die(_("Could not write patch"));
 228
 229        if (launch_editor(file, NULL, NULL))
 230                die(_("editing patch failed"));
 231
 232        if (stat(file, &st))
 233                die_errno(_("Could not stat '%s'"), file);
 234        if (!st.st_size)
 235                die(_("Empty patch. Aborted."));
 236
 237        child.git_cmd = 1;
 238        child.argv = apply_argv;
 239        if (run_command(&child))
 240                die(_("Could not apply '%s'"), file);
 241
 242        unlink(file);
 243        free(file);
 244        return 0;
 245}
 246
 247static struct lock_file lock_file;
 248
 249static const char ignore_error[] =
 250N_("The following paths are ignored by one of your .gitignore files:\n");
 251
 252static int verbose, show_only, ignored_too, refresh_only;
 253static int ignore_add_errors, intent_to_add, ignore_missing;
 254static int warn_on_embedded_repo = 1;
 255
 256#define ADDREMOVE_DEFAULT 1
 257static int addremove = ADDREMOVE_DEFAULT;
 258static int addremove_explicit = -1; /* unspecified */
 259
 260static char *chmod_arg;
 261
 262static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
 263{
 264        /* if we are told to ignore, we are not adding removals */
 265        *(int *)opt->value = !unset ? 0 : 1;
 266        return 0;
 267}
 268
 269static struct option builtin_add_options[] = {
 270        OPT__DRY_RUN(&show_only, N_("dry run")),
 271        OPT__VERBOSE(&verbose, N_("be verbose")),
 272        OPT_GROUP(""),
 273        OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
 274        OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
 275        OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
 276        OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
 277        OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
 278        OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
 279        OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
 280        { OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
 281          NULL /* takes no arguments */,
 282          N_("ignore paths removed in the working tree (same as --no-all)"),
 283          PARSE_OPT_NOARG, ignore_removal_cb },
 284        OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
 285        OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
 286        OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
 287        OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")),
 288        OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
 289                        N_("warn when adding an embedded repository")),
 290        OPT_END(),
 291};
 292
 293static int add_config(const char *var, const char *value, void *cb)
 294{
 295        if (!strcmp(var, "add.ignoreerrors") ||
 296            !strcmp(var, "add.ignore-errors")) {
 297                ignore_add_errors = git_config_bool(var, value);
 298                return 0;
 299        }
 300        return git_default_config(var, value, cb);
 301}
 302
 303static const char embedded_advice[] = N_(
 304"You've added another git repository inside your current repository.\n"
 305"Clones of the outer repository will not contain the contents of\n"
 306"the embedded repository and will not know how to obtain it.\n"
 307"If you meant to add a submodule, use:\n"
 308"\n"
 309"       git submodule add <url> %s\n"
 310"\n"
 311"If you added this path by mistake, you can remove it from the\n"
 312"index with:\n"
 313"\n"
 314"       git rm --cached %s\n"
 315"\n"
 316"See \"git help submodule\" for more information."
 317);
 318
 319static void check_embedded_repo(const char *path)
 320{
 321        struct strbuf name = STRBUF_INIT;
 322
 323        if (!warn_on_embedded_repo)
 324                return;
 325        if (!ends_with(path, "/"))
 326                return;
 327
 328        /* Drop trailing slash for aesthetics */
 329        strbuf_addstr(&name, path);
 330        strbuf_strip_suffix(&name, "/");
 331
 332        warning(_("adding embedded git repository: %s"), name.buf);
 333        if (advice_add_embedded_repo) {
 334                advise(embedded_advice, name.buf, name.buf);
 335                /* there may be multiple entries; advise only once */
 336                advice_add_embedded_repo = 0;
 337        }
 338
 339        strbuf_release(&name);
 340}
 341
 342static int add_files(struct dir_struct *dir, int flags)
 343{
 344        int i, exit_status = 0;
 345
 346        if (dir->ignored_nr) {
 347                fprintf(stderr, _(ignore_error));
 348                for (i = 0; i < dir->ignored_nr; i++)
 349                        fprintf(stderr, "%s\n", dir->ignored[i]->name);
 350                fprintf(stderr, _("Use -f if you really want to add them.\n"));
 351                exit_status = 1;
 352        }
 353
 354        for (i = 0; i < dir->nr; i++) {
 355                check_embedded_repo(dir->entries[i]->name);
 356                if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
 357                        if (!ignore_add_errors)
 358                                die(_("adding files failed"));
 359                        exit_status = 1;
 360                }
 361        }
 362        return exit_status;
 363}
 364
 365int cmd_add(int argc, const char **argv, const char *prefix)
 366{
 367        int exit_status = 0;
 368        struct pathspec pathspec;
 369        struct dir_struct dir;
 370        int flags;
 371        int add_new_files;
 372        int require_pathspec;
 373        char *seen = NULL;
 374
 375        git_config(add_config, NULL);
 376
 377        argc = parse_options(argc, argv, prefix, builtin_add_options,
 378                          builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
 379        if (patch_interactive)
 380                add_interactive = 1;
 381        if (add_interactive)
 382                exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
 383
 384        if (edit_interactive)
 385                return(edit_patch(argc, argv, prefix));
 386        argc--;
 387        argv++;
 388
 389        if (0 <= addremove_explicit)
 390                addremove = addremove_explicit;
 391        else if (take_worktree_changes && ADDREMOVE_DEFAULT)
 392                addremove = 0; /* "-u" was given but not "-A" */
 393
 394        if (addremove && take_worktree_changes)
 395                die(_("-A and -u are mutually incompatible"));
 396
 397        if (!take_worktree_changes && addremove_explicit < 0 && argc)
 398                /* Turn "git add pathspec..." to "git add -A pathspec..." */
 399                addremove = 1;
 400
 401        if (!show_only && ignore_missing)
 402                die(_("Option --ignore-missing can only be used together with --dry-run"));
 403
 404        if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') ||
 405                          chmod_arg[1] != 'x' || chmod_arg[2]))
 406                die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
 407
 408        add_new_files = !take_worktree_changes && !refresh_only;
 409        require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
 410
 411        hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 412
 413        flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
 414                 (show_only ? ADD_CACHE_PRETEND : 0) |
 415                 (intent_to_add ? ADD_CACHE_INTENT : 0) |
 416                 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
 417                 (!(addremove || take_worktree_changes)
 418                  ? ADD_CACHE_IGNORE_REMOVAL : 0));
 419
 420        if (require_pathspec && argc == 0) {
 421                fprintf(stderr, _("Nothing specified, nothing added.\n"));
 422                fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
 423                return 0;
 424        }
 425
 426        if (read_cache() < 0)
 427                die(_("index file corrupt"));
 428
 429        die_in_unpopulated_submodule(&the_index, prefix);
 430
 431        /*
 432         * Check the "pathspec '%s' did not match any files" block
 433         * below before enabling new magic.
 434         */
 435        parse_pathspec(&pathspec, 0,
 436                       PATHSPEC_PREFER_FULL |
 437                       PATHSPEC_SYMLINK_LEADING_PATH,
 438                       prefix, argv);
 439
 440        die_path_inside_submodule(&the_index, &pathspec);
 441
 442        if (add_new_files) {
 443                int baselen;
 444
 445                /* Set up the default git porcelain excludes */
 446                memset(&dir, 0, sizeof(dir));
 447                if (!ignored_too) {
 448                        dir.flags |= DIR_COLLECT_IGNORED;
 449                        setup_standard_excludes(&dir);
 450                }
 451
 452                /* This picks up the paths that are not tracked */
 453                baselen = fill_directory(&dir, &the_index, &pathspec);
 454                if (pathspec.nr)
 455                        seen = prune_directory(&dir, &pathspec, baselen);
 456        }
 457
 458        if (refresh_only) {
 459                refresh(verbose, &pathspec);
 460                goto finish;
 461        }
 462
 463        if (pathspec.nr) {
 464                int i;
 465
 466                if (!seen)
 467                        seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
 468
 469                /*
 470                 * file_exists() assumes exact match
 471                 */
 472                GUARD_PATHSPEC(&pathspec,
 473                               PATHSPEC_FROMTOP |
 474                               PATHSPEC_LITERAL |
 475                               PATHSPEC_GLOB |
 476                               PATHSPEC_ICASE |
 477                               PATHSPEC_EXCLUDE);
 478
 479                for (i = 0; i < pathspec.nr; i++) {
 480                        const char *path = pathspec.items[i].match;
 481                        if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
 482                                continue;
 483                        if (!seen[i] && path[0] &&
 484                            ((pathspec.items[i].magic &
 485                              (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
 486                             !file_exists(path))) {
 487                                if (ignore_missing) {
 488                                        int dtype = DT_UNKNOWN;
 489                                        if (is_excluded(&dir, &the_index, path, &dtype))
 490                                                dir_add_ignored(&dir, &the_index,
 491                                                                path, pathspec.items[i].len);
 492                                } else
 493                                        die(_("pathspec '%s' did not match any files"),
 494                                            pathspec.items[i].original);
 495                        }
 496                }
 497                free(seen);
 498        }
 499
 500        plug_bulk_checkin();
 501
 502        exit_status |= add_files_to_cache(prefix, &pathspec, flags);
 503
 504        if (add_new_files)
 505                exit_status |= add_files(&dir, flags);
 506
 507        if (chmod_arg && pathspec.nr)
 508                chmod_pathspec(&pathspec, chmod_arg[0]);
 509        unplug_bulk_checkin();
 510
 511finish:
 512        if (active_cache_changed) {
 513                if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
 514                        die(_("Unable to write new index file"));
 515        }
 516
 517        return exit_status;
 518}