xdl_change_compact(): introduce the concept of a change group
[gitweb.git] / builtin / add.c
index 06ad3653f0105b411d5effe219105305cb47b843..b1dddb4ac635ab7e2cc55be546002f8e68efa331 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include "cache.h"
 #include "builtin.h"
+#include "lockfile.h"
 #include "dir.h"
 #include "pathspec.h"
 #include "exec_cmd.h"
 #include "argv-array.h"
 
 static const char * const builtin_add_usage[] = {
-       N_("git add [options] [--] <pathspec>..."),
+       N_("git add [<options>] [--] <pathspec>..."),
        NULL
 };
 static int patch_interactive, add_interactive, edit_interactive;
 static int take_worktree_changes;
 
 struct update_callback_data {
-       int flags;
+       int flags, force_mode;
        int add_errors;
 };
 
@@ -64,7 +65,8 @@ static void update_callback(struct diff_queue_struct *q,
                        die(_("unexpected diff status %c"), p->status);
                case DIFF_STATUS_MODIFIED:
                case DIFF_STATUS_TYPE_CHANGED:
-                       if (add_file_to_index(&the_index, path, data->flags)) {
+                       if (add_file_to_index(&the_index, path,
+                                       data->flags, data->force_mode)) {
                                if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
                                        die(_("updating files failed"));
                                data->add_errors++;
@@ -82,14 +84,15 @@ static void update_callback(struct diff_queue_struct *q,
        }
 }
 
-int add_files_to_cache(const char *prefix,
-                      const struct pathspec *pathspec, int flags)
+int add_files_to_cache(const char *prefix, const struct pathspec *pathspec,
+       int flags, int force_mode)
 {
        struct update_callback_data data;
        struct rev_info rev;
 
        memset(&data, 0, sizeof(data));
        data.flags = flags;
+       data.force_mode = force_mode;
 
        init_revisions(&rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
@@ -180,7 +183,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        char *file = git_pathdup("ADD_EDIT.patch");
        const char *apply_argv[] = { "apply", "--recount", "--cached",
                NULL, NULL };
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct rev_info rev;
        int out;
        struct stat st;
@@ -207,14 +210,14 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        if (run_diff_files(&rev, 0))
                die(_("Could not write patch"));
 
-       launch_editor(file, NULL, NULL);
+       if (launch_editor(file, NULL, NULL))
+               die(_("editing patch failed"));
 
        if (stat(file, &st))
                die_errno(_("Could not stat '%s'"), file);
        if (!st.st_size)
                die(_("Empty patch. Aborted."));
 
-       memset(&child, 0, sizeof(child));
        child.git_cmd = 1;
        child.argv = apply_argv;
        if (run_command(&child))
@@ -237,6 +240,8 @@ static int ignore_add_errors, intent_to_add, ignore_missing;
 static int addremove = ADDREMOVE_DEFAULT;
 static int addremove_explicit = -1; /* unspecified */
 
+static char *chmod_arg;
+
 static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
 {
        /* if we are told to ignore, we are not adding removals */
@@ -262,6 +267,7 @@ static struct option builtin_add_options[] = {
        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")),
+       OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")),
        OPT_END(),
 };
 
@@ -275,7 +281,7 @@ static int add_config(const char *var, const char *value, void *cb)
        return git_default_config(var, value, cb);
 }
 
-static int add_files(struct dir_struct *dir, int flags)
+static int add_files(struct dir_struct *dir, int flags, int force_mode)
 {
        int i, exit_status = 0;
 
@@ -284,11 +290,12 @@ static int add_files(struct dir_struct *dir, int flags)
                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"));
-               die(_("no files added"));
+               exit_status = 1;
        }
 
        for (i = 0; i < dir->nr; i++)
-               if (add_file_to_cache(dir->entries[i]->name, flags)) {
+               if (add_file_to_index(&the_index, dir->entries[i]->name,
+                               flags, force_mode)) {
                        if (!ignore_add_errors)
                                die(_("adding files failed"));
                        exit_status = 1;
@@ -299,10 +306,9 @@ static int add_files(struct dir_struct *dir, int flags)
 int cmd_add(int argc, const char **argv, const char *prefix)
 {
        int exit_status = 0;
-       int newfd;
        struct pathspec pathspec;
        struct dir_struct dir;
-       int flags;
+       int flags, force_mode;
        int add_new_files;
        int require_pathspec;
        char *seen = NULL;
@@ -336,10 +342,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (!show_only && ignore_missing)
                die(_("Option --ignore-missing can only be used together with --dry-run"));
 
+       if (!chmod_arg)
+               force_mode = 0;
+       else if (!strcmp(chmod_arg, "-x"))
+               force_mode = 0666;
+       else if (!strcmp(chmod_arg, "+x"))
+               force_mode = 0777;
+       else
+               die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
+
        add_new_files = !take_worktree_changes && !refresh_only;
        require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
 
-       newfd = hold_locked_index(&lock_file, 1);
+       hold_locked_index(&lock_file, 1);
 
        flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
                 (show_only ? ADD_CACHE_PRETEND : 0) |
@@ -369,7 +384,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
        if (add_new_files) {
                int baselen;
-               struct pathspec empty_pathspec;
 
                /* Set up the default git porcelain excludes */
                memset(&dir, 0, sizeof(dir));
@@ -378,7 +392,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                        setup_standard_excludes(&dir);
                }
 
-               memset(&empty_pathspec, 0, sizeof(empty_pathspec));
                /* This picks up the paths that are not tracked */
                baselen = fill_directory(&dir, &pathspec);
                if (pathspec.nr)
@@ -428,17 +441,16 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
        plug_bulk_checkin();
 
-       exit_status |= add_files_to_cache(prefix, &pathspec, flags);
+       exit_status |= add_files_to_cache(prefix, &pathspec, flags, force_mode);
 
        if (add_new_files)
-               exit_status |= add_files(&dir, flags);
+               exit_status |= add_files(&dir, flags, force_mode);
 
        unplug_bulk_checkin();
 
 finish:
        if (active_cache_changed) {
-               if (write_cache(newfd, active_cache, active_nr) ||
-                   commit_locked_index(&lock_file))
+               if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                        die(_("Unable to write new index file"));
        }