]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/add.c
Merge branch 'en/ort-perf-batch-9'
[thirdparty/git.git] / builtin / add.c
index 4c38aff41957a07cc52eee8ac64bbb4afe2969e4..ea762a41e3a2d2c41718de2e97c6a0e6031ce91c 100644 (file)
@@ -18,7 +18,7 @@
 #include "diffcore.h"
 #include "revision.h"
 #include "bulk-checkin.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "submodule.h"
 #include "add-interactive.h"
 
@@ -31,25 +31,34 @@ static int take_worktree_changes;
 static int add_renormalize;
 static int pathspec_file_nul;
 static const char *pathspec_from_file;
+static int legacy_stash_p; /* support for the scripted `git stash` */
 
 struct update_callback_data {
        int flags;
        int add_errors;
 };
 
-static void chmod_pathspec(struct pathspec *pathspec, char flip)
+static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
 {
-       int i;
+       int i, ret = 0;
 
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce = active_cache[i];
+               int err;
 
                if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
                        continue;
 
-               if (chmod_cache_entry(ce, flip) < 0)
-                       fprintf(stderr, "cannot chmod %cx '%s'\n", flip, ce->name);
+               if (!show_only)
+                       err = chmod_cache_entry(ce, flip);
+               else
+                       err = S_ISREG(ce->ce_mode) ? 0 : -1;
+
+               if (err < 0)
+                       ret = error(_("cannot chmod %cx '%s'"), flip, ce->name);
        }
+
+       return ret;
 }
 
 static int fix_unmerged_status(struct diff_filepair *p,
@@ -187,39 +196,58 @@ int run_add_interactive(const char *revision, const char *patch_mode,
                        const struct pathspec *pathspec)
 {
        int status, i;
-       struct argv_array argv = ARGV_ARRAY_INIT;
+       struct strvec argv = STRVEC_INIT;
        int use_builtin_add_i =
                git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
 
-       if (use_builtin_add_i < 0)
-               git_config_get_bool("add.interactive.usebuiltin",
-                                   &use_builtin_add_i);
+       if (use_builtin_add_i < 0) {
+               int experimental;
+               if (!git_config_get_bool("add.interactive.usebuiltin",
+                                        &use_builtin_add_i))
+                       ; /* ok */
+               else if (!git_config_get_bool("feature.experimental", &experimental) &&
+                        experimental)
+                       use_builtin_add_i = 1;
+       }
 
        if (use_builtin_add_i == 1) {
+               enum add_p_mode mode;
+
                if (!patch_mode)
                        return !!run_add_i(the_repository, pathspec);
-               if (strcmp(patch_mode, "--patch"))
-                       die("'%s' not yet supported in the built-in add -p",
-                           patch_mode);
-               return !!run_add_p(the_repository, pathspec);
+
+               if (!strcmp(patch_mode, "--patch"))
+                       mode = ADD_P_ADD;
+               else if (!strcmp(patch_mode, "--patch=stash"))
+                       mode = ADD_P_STASH;
+               else if (!strcmp(patch_mode, "--patch=reset"))
+                       mode = ADD_P_RESET;
+               else if (!strcmp(patch_mode, "--patch=checkout"))
+                       mode = ADD_P_CHECKOUT;
+               else if (!strcmp(patch_mode, "--patch=worktree"))
+                       mode = ADD_P_WORKTREE;
+               else
+                       die("'%s' not supported", patch_mode);
+
+               return !!run_add_p(the_repository, mode, revision, pathspec);
        }
 
-       argv_array_push(&argv, "add--interactive");
+       strvec_push(&argv, "add--interactive");
        if (patch_mode)
-               argv_array_push(&argv, patch_mode);
+               strvec_push(&argv, patch_mode);
        if (revision)
-               argv_array_push(&argv, revision);
-       argv_array_push(&argv, "--");
+               strvec_push(&argv, revision);
+       strvec_push(&argv, "--");
        for (i = 0; i < pathspec->nr; i++)
                /* pass original pathspec, to be re-parsed */
-               argv_array_push(&argv, pathspec->items[i].original);
+               strvec_push(&argv, pathspec->items[i].original);
 
-       status = run_command_v_opt(argv.argv, RUN_GIT_CMD);
-       argv_array_clear(&argv);
+       status = run_command_v_opt(argv.v, RUN_GIT_CMD);
+       strvec_clear(&argv);
        return status;
 }
 
-int interactive_add(int argc, const char **argv, const char *prefix, int patch)
+int interactive_add(const char **argv, const char *prefix, int patch)
 {
        struct pathspec pathspec;
 
@@ -316,10 +344,10 @@ static struct option builtin_add_options[] = {
        OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")),
        OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
        OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
-       { OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
+       OPT_CALLBACK_F(0, "ignore-removal", &addremove_explicit,
          NULL /* takes no arguments */,
          N_("ignore paths removed in the working tree (same as --no-all)"),
-         PARSE_OPT_NOARG, ignore_removal_cb },
+         PARSE_OPT_NOARG, ignore_removal_cb),
        OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
        OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
        OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
@@ -327,6 +355,8 @@ static struct option builtin_add_options[] = {
                   N_("override the executable bit of the listed files")),
        OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
                        N_("warn when adding an embedded repository")),
+       OPT_HIDDEN_BOOL(0, "legacy-stash-p", &legacy_stash_p,
+                       N_("backend for `git stash -p`")),
        OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
        OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
        OPT_END(),
@@ -390,7 +420,10 @@ static int add_files(struct dir_struct *dir, int flags)
                fprintf(stderr, _(ignore_error));
                for (i = 0; i < dir->ignored_nr; i++)
                        fprintf(stderr, "%s\n", dir->ignored[i]->name);
-               fprintf(stderr, _("Use -f if you really want to add them.\n"));
+               if (advice_add_ignored_file)
+                       advise(_("Use -f if you really want to add them.\n"
+                               "Turn this message off by running\n"
+                               "\"git config advice.addIgnoredFile false\""));
                exit_status = 1;
        }
 
@@ -426,7 +459,18 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (add_interactive) {
                if (pathspec_from_file)
                        die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
-               exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
+               exit(interactive_add(argv + 1, prefix, patch_interactive));
+       }
+       if (legacy_stash_p) {
+               struct pathspec pathspec;
+
+               parse_pathspec(&pathspec, 0,
+                       PATHSPEC_PREFER_FULL |
+                       PATHSPEC_SYMLINK_LEADING_PATH |
+                       PATHSPEC_PREFIX_ORIGIN,
+                       prefix, argv);
+
+               return run_add_interactive(NULL, "--patch=stash", &pathspec);
        }
 
        if (edit_interactive) {
@@ -480,7 +524,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
        if (require_pathspec && pathspec.nr == 0) {
                fprintf(stderr, _("Nothing specified, nothing added.\n"));
-               fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
+               if (advice_add_empty_pathspec)
+                       advise( _("Maybe you wanted to say 'git add .'?\n"
+                               "Turn this message off by running\n"
+                               "\"git config advice.addEmptyPathspec false\""));
                return 0;
        }
 
@@ -501,11 +548,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        die_in_unpopulated_submodule(&the_index, prefix);
        die_path_inside_submodule(&the_index, &pathspec);
 
+       dir_init(&dir);
        if (add_new_files) {
                int baselen;
 
                /* Set up the default git porcelain excludes */
-               memset(&dir, 0, sizeof(dir));
                if (!ignored_too) {
                        dir.flags |= DIR_COLLECT_IGNORED;
                        setup_standard_excludes(&dir);
@@ -570,7 +617,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                exit_status |= add_files(&dir, flags);
 
        if (chmod_arg && pathspec.nr)
-               chmod_pathspec(&pathspec, chmod_arg[0]);
+               exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
        unplug_bulk_checkin();
 
 finish:
@@ -578,7 +625,7 @@ finish:
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
                die(_("Unable to write new index file"));
 
+       dir_clear(&dir);
        UNLEAK(pathspec);
-       UNLEAK(dir);
        return exit_status;
 }