Merge branch 'da/imap-send-use-credential-helper'
[gitweb.git] / builtin / reset.c
index 60048030dd4d05e9938f298002d02afc31528bf1..f368266762fae1e6c783d7351e289e423e408b3c 100644 (file)
@@ -116,25 +116,34 @@ static void update_index_from_diff(struct diff_queue_struct *q,
                struct diff_options *opt, void *data)
 {
        int i;
+       int intent_to_add = *(int *)data;
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filespec *one = q->queue[i]->one;
-               if (one->mode && !is_null_sha1(one->sha1)) {
-                       struct cache_entry *ce;
-                       ce = make_cache_entry(one->mode, one->sha1, one->path,
-                               0, 0);
-                       if (!ce)
-                               die(_("make_cache_entry failed for path '%s'"),
-                                   one->path);
-                       add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
-                               ADD_CACHE_OK_TO_REPLACE);
-               } else
+               int is_missing = !(one->mode && !is_null_sha1(one->sha1));
+               struct cache_entry *ce;
+
+               if (is_missing && !intent_to_add) {
                        remove_file_from_cache(one->path);
+                       continue;
+               }
+
+               ce = make_cache_entry(one->mode, one->sha1, one->path,
+                                     0, 0);
+               if (!ce)
+                       die(_("make_cache_entry failed for path '%s'"),
+                           one->path);
+               if (is_missing) {
+                       ce->ce_flags |= CE_INTENT_TO_ADD;
+                       set_object_name_for_intent_to_add_entry(ce);
+               }
+               add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
        }
 }
 
 static int read_from_tree(const struct pathspec *pathspec,
-                         unsigned char *tree_sha1)
+                         unsigned char *tree_sha1,
+                         int intent_to_add)
 {
        struct diff_options opt;
 
@@ -142,6 +151,7 @@ static int read_from_tree(const struct pathspec *pathspec,
        copy_pathspec(&opt.pathspec, pathspec);
        opt.output_format = DIFF_FORMAT_CALLBACK;
        opt.format_callback = update_index_from_diff;
+       opt.format_callback_data = &intent_to_add;
 
        if (do_diff_cache(tree_sha1, &opt))
                return 1;
@@ -242,11 +252,13 @@ static int reset_refs(const char *rev, const unsigned char *sha1)
        if (!get_sha1("HEAD", sha1_orig)) {
                orig = sha1_orig;
                set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
-               update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
+               update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
+                          UPDATE_REFS_MSG_ON_ERR);
        } else if (old_orig)
                delete_ref("ORIG_HEAD", old_orig, 0);
        set_reflog_message(&msg, "updating HEAD", rev);
-       update_ref_status = update_ref(msg.buf, "HEAD", sha1, orig, 0, MSG_ON_ERR);
+       update_ref_status = update_ref(msg.buf, "HEAD", sha1, orig, 0,
+                                      UPDATE_REFS_MSG_ON_ERR);
        strbuf_release(&msg);
        return update_ref_status;
 }
@@ -258,6 +270,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
        const char *rev;
        unsigned char sha1[20];
        struct pathspec pathspec;
+       int intent_to_add = 0;
        const struct option options[] = {
                OPT__QUIET(&quiet, N_("be quiet, only report errors")),
                OPT_SET_INT(0, "mixed", &reset_type,
@@ -270,6 +283,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                OPT_SET_INT(0, "keep", &reset_type,
                                N_("reset HEAD but keep local changes"), KEEP),
                OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
+               OPT_BOOL('N', "intent-to-add", &intent_to_add,
+                               N_("record only the fact that removed paths will be added later")),
                OPT_END()
        };
 
@@ -320,13 +335,16 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
        if (reset_type == NONE)
                reset_type = MIXED; /* by default */
 
-       if (reset_type != SOFT && reset_type != MIXED)
+       if (reset_type != SOFT && (reset_type != MIXED || get_git_work_tree()))
                setup_work_tree();
 
        if (reset_type == MIXED && is_bare_repository())
                die(_("%s reset is not allowed in a bare repository"),
                    _(reset_type_names[reset_type]));
 
+       if (intent_to_add && reset_type != MIXED)
+               die(_("-N can only be used with --mixed"));
+
        /* Soft reset does not touch the index file nor the working tree
         * at all, but requires them in a good order.  Other resets reset
         * the index file to the tree object we are switching to. */
@@ -338,10 +356,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                int newfd = hold_locked_index(lock, 1);
                if (reset_type == MIXED) {
                        int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
-                       if (read_from_tree(&pathspec, sha1))
+                       if (read_from_tree(&pathspec, sha1, intent_to_add))
                                return 1;
-                       refresh_index(&the_index, flags, NULL, NULL,
-                                     _("Unstaged changes after reset:"));
+                       if (get_git_work_tree())
+                               refresh_index(&the_index, flags, NULL, NULL,
+                                             _("Unstaged changes after reset:"));
                } else {
                        int err = reset_index(sha1, reset_type, quiet);
                        if (reset_type == KEEP && !err)