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