add: speed up cmd_add() by utilizing read_cache_preload()
[gitweb.git] / apply.c
diff --git a/apply.c b/apply.c
index d79e61591b3814339fb8b2a39fb7d1e211d622c6..073d5f04512ac6febc2949040f53ef273433f3c0 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -9,6 +9,7 @@
 
 #include "cache.h"
 #include "config.h"
+#include "object-store.h"
 #include "blob.h"
 #include "delta.h"
 #include "diff.h"
@@ -75,10 +76,12 @@ static int parse_ignorewhitespace_option(struct apply_state *state,
 }
 
 int init_apply_state(struct apply_state *state,
+                    struct repository *repo,
                     const char *prefix)
 {
        memset(state, 0, sizeof(*state));
        state->prefix = prefix;
+       state->repo = repo;
        state->apply = 1;
        state->line_termination = '\n';
        state->p_value = 1;
@@ -141,6 +144,8 @@ int check_apply_state(struct apply_state *state, int force_apply)
                        return error(_("--cached outside a repository"));
                state->check_index = 1;
        }
+       if (state->ita_only && (state->check_index || is_not_gitdir))
+               state->ita_only = 0;
        if (state->check_index)
                state->unsafe_paths = 0;
 
@@ -218,8 +223,8 @@ struct patch {
        struct fragment *fragments;
        char *result;
        size_t resultsize;
-       char old_sha1_prefix[41];
-       char new_sha1_prefix[41];
+       char old_oid_prefix[GIT_MAX_HEXSZ + 1];
+       char new_oid_prefix[GIT_MAX_HEXSZ + 1];
        struct patch *next;
 
        /* three-way fallback result */
@@ -1088,13 +1093,14 @@ static int gitdiff_index(struct apply_state *state,
         */
        const char *ptr, *eol;
        int len;
+       const unsigned hexsz = the_hash_algo->hexsz;
 
        ptr = strchr(line, '.');
-       if (!ptr || ptr[1] != '.' || 40 < ptr - line)
+       if (!ptr || ptr[1] != '.' || hexsz < ptr - line)
                return 0;
        len = ptr - line;
-       memcpy(patch->old_sha1_prefix, line, len);
-       patch->old_sha1_prefix[len] = 0;
+       memcpy(patch->old_oid_prefix, line, len);
+       patch->old_oid_prefix[len] = 0;
 
        line = ptr + 2;
        ptr = strchr(line, ' ');
@@ -1104,10 +1110,10 @@ static int gitdiff_index(struct apply_state *state,
                ptr = eol;
        len = ptr - line;
 
-       if (40 < len)
+       if (hexsz < len)
                return 0;
-       memcpy(patch->new_sha1_prefix, line, len);
-       patch->new_sha1_prefix[len] = 0;
+       memcpy(patch->new_oid_prefix, line, len);
+       patch->new_oid_prefix[len] = 0;
        if (*ptr == ' ')
                return gitdiff_oldmode(state, ptr + 1, patch);
        return 0;
@@ -2126,10 +2132,12 @@ static int parse_chunk(struct apply_state *state, char *buffer, unsigned long si
 
        if (!use_patch(state, patch))
                patch->ws_rule = 0;
+       else if (patch->new_name)
+               patch->ws_rule = whitespace_rule(state->repo->index,
+                                                patch->new_name);
        else
-               patch->ws_rule = whitespace_rule(patch->new_name
-                                                ? patch->new_name
-                                                : patch->old_name);
+               patch->ws_rule = whitespace_rule(state->repo->index,
+                                                patch->old_name);
 
        patchsize = parse_single_patch(state,
                                       buffer + offset + hdrsize,
@@ -2199,7 +2207,7 @@ static void reverse_patches(struct patch *p)
                SWAP(p->new_mode, p->old_mode);
                SWAP(p->is_new, p->is_delete);
                SWAP(p->lines_added, p->lines_deleted);
-               SWAP(p->old_sha1_prefix, p->new_sha1_prefix);
+               SWAP(p->old_oid_prefix, p->new_oid_prefix);
 
                for (; frag; frag = frag->next) {
                        SWAP(frag->newpos, frag->oldpos);
@@ -3137,15 +3145,16 @@ static int apply_binary(struct apply_state *state,
 {
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
        struct object_id oid;
+       const unsigned hexsz = the_hash_algo->hexsz;
 
        /*
         * For safety, we require patch index line to contain
-        * full 40-byte textual SHA1 for old and new, at least for now.
+        * full hex textual object ID for old and new, at least for now.
         */
-       if (strlen(patch->old_sha1_prefix) != 40 ||
-           strlen(patch->new_sha1_prefix) != 40 ||
-           get_oid_hex(patch->old_sha1_prefix, &oid) ||
-           get_oid_hex(patch->new_sha1_prefix, &oid))
+       if (strlen(patch->old_oid_prefix) != hexsz ||
+           strlen(patch->new_oid_prefix) != hexsz ||
+           get_oid_hex(patch->old_oid_prefix, &oid) ||
+           get_oid_hex(patch->new_oid_prefix, &oid))
                return error(_("cannot apply binary patch to '%s' "
                               "without full index line"), name);
 
@@ -3155,7 +3164,7 @@ static int apply_binary(struct apply_state *state,
                 * applies to.
                 */
                hash_object_file(img->buf, img->len, blob_type, &oid);
-               if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
+               if (strcmp(oid_to_hex(&oid), patch->old_oid_prefix))
                        return error(_("the patch applies to '%s' (%s), "
                                       "which does not match the "
                                       "current contents."),
@@ -3168,7 +3177,7 @@ static int apply_binary(struct apply_state *state,
                                       "'%s' but it is not empty"), name);
        }
 
-       get_oid_hex(patch->new_sha1_prefix, &oid);
+       get_oid_hex(patch->new_oid_prefix, &oid);
        if (is_null_oid(&oid)) {
                clear_image(img);
                return 0; /* deletion patch */
@@ -3184,7 +3193,7 @@ static int apply_binary(struct apply_state *state,
                if (!result)
                        return error(_("the necessary postimage %s for "
                                       "'%s' cannot be read"),
-                                    patch->new_sha1_prefix, name);
+                                    patch->new_oid_prefix, name);
                clear_image(img);
                img->buf = result;
                img->len = size;
@@ -3200,9 +3209,9 @@ static int apply_binary(struct apply_state *state,
 
                /* verify that the result matches */
                hash_object_file(img->buf, img->len, blob_type, &oid);
-               if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
+               if (strcmp(oid_to_hex(&oid), patch->new_oid_prefix))
                        return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
-                               name, patch->new_sha1_prefix, oid_to_hex(&oid));
+                               name, patch->new_oid_prefix, oid_to_hex(&oid));
        }
 
        return 0;
@@ -3371,14 +3380,17 @@ static struct patch *previous_patch(struct apply_state *state,
        return previous;
 }
 
-static int verify_index_match(const struct cache_entry *ce, struct stat *st)
+static int verify_index_match(struct apply_state *state,
+                             const struct cache_entry *ce,
+                             struct stat *st)
 {
        if (S_ISGITLINK(ce->ce_mode)) {
                if (!S_ISDIR(st->st_mode))
                        return -1;
                return 0;
        }
-       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+       return ie_match_stat(state->repo->index, ce, st,
+                            CE_MATCH_IGNORE_VALID | CE_MATCH_IGNORE_SKIP_WORKTREE);
 }
 
 #define SUBMODULE_PATCH_WITHOUT_INDEX 1
@@ -3459,7 +3471,8 @@ static int load_preimage(struct apply_state *state,
        return 0;
 }
 
-static int three_way_merge(struct image *image,
+static int three_way_merge(struct apply_state *state,
+                          struct image *image,
                           char *path,
                           const struct object_id *base,
                           const struct object_id *ours,
@@ -3475,7 +3488,9 @@ static int three_way_merge(struct image *image,
        status = ll_merge(&result, path,
                          &base_file, "base",
                          &our_file, "ours",
-                         &their_file, "theirs", NULL);
+                         &their_file, "theirs",
+                         state->repo->index,
+                         NULL);
        free(base_file.ptr);
        free(our_file.ptr);
        free(their_file.ptr);
@@ -3511,17 +3526,17 @@ static int load_current(struct apply_state *state,
        if (!patch->is_new)
                BUG("patch to %s is not a creation", patch->old_name);
 
-       pos = cache_name_pos(name, strlen(name));
+       pos = index_name_pos(state->repo->index, name, strlen(name));
        if (pos < 0)
                return error(_("%s: does not exist in index"), name);
-       ce = active_cache[pos];
+       ce = state->repo->index->cache[pos];
        if (lstat(name, &st)) {
                if (errno != ENOENT)
                        return error_errno("%s", name);
-               if (checkout_target(&the_index, ce, &st))
+               if (checkout_target(state->repo->index, ce, &st))
                        return -1;
        }
-       if (verify_index_match(ce, &st))
+       if (verify_index_match(state, ce, &st))
                return error(_("%s: does not match index"), name);
 
        status = load_patch_target(state, &buf, ce, &st, patch, name, mode);
@@ -3555,7 +3570,7 @@ static int try_threeway(struct apply_state *state,
        /* Preimage the patch was prepared for */
        if (patch->is_new)
                write_object_file("", 0, blob_type, &pre_oid);
-       else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
+       else if (get_oid(patch->old_oid_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
 
@@ -3587,7 +3602,7 @@ static int try_threeway(struct apply_state *state,
        clear_image(&tmp_image);
 
        /* in-core three-way merge between post and our using pre as base */
-       status = three_way_merge(image, patch->new_name,
+       status = three_way_merge(state, image, patch->new_name,
                                 &pre_oid, &our_oid, &post_oid);
        if (status < 0) {
                if (state->apply_verbosity > verbosity_silent)
@@ -3680,18 +3695,19 @@ static int check_preimage(struct apply_state *state,
        }
 
        if (state->check_index && !previous) {
-               int pos = cache_name_pos(old_name, strlen(old_name));
+               int pos = index_name_pos(state->repo->index, old_name,
+                                        strlen(old_name));
                if (pos < 0) {
                        if (patch->is_new < 0)
                                goto is_new;
                        return error(_("%s: does not exist in index"), old_name);
                }
-               *ce = active_cache[pos];
+               *ce = state->repo->index->cache[pos];
                if (stat_ret < 0) {
-                       if (checkout_target(&the_index, *ce, st))
+                       if (checkout_target(state->repo->index, *ce, st))
                                return -1;
                }
-               if (!state->cached && verify_index_match(*ce, st))
+               if (!state->cached && verify_index_match(state, *ce, st))
                        return error(_("%s: does not match index"), old_name);
                if (state->cached)
                        st_mode = (*ce)->ce_mode;
@@ -3735,7 +3751,7 @@ static int check_to_create(struct apply_state *state,
        struct stat nst;
 
        if (state->check_index &&
-           cache_name_pos(new_name, strlen(new_name)) >= 0 &&
+           index_name_pos(state->repo->index, new_name, strlen(new_name)) >= 0 &&
            !ok_if_exists)
                return EXISTS_IN_INDEX;
        if (state->cached)
@@ -3824,7 +3840,8 @@ static int path_is_beyond_symlink_1(struct apply_state *state, struct strbuf *na
                if (state->check_index) {
                        struct cache_entry *ce;
 
-                       ce = cache_file_exists(name->buf, name->len, ignore_case);
+                       ce = index_file_exists(state->repo->index, name->buf,
+                                              name->len, ignore_case);
                        if (ce && S_ISLNK(ce->ce_mode))
                                return 1;
                } else {
@@ -3999,9 +4016,10 @@ static int check_patch_list(struct apply_state *state, struct patch *patch)
 static int read_apply_cache(struct apply_state *state)
 {
        if (state->index_file)
-               return read_cache_from(state->index_file);
+               return read_index_from(state->repo->index, state->index_file,
+                                      get_git_dir());
        else
-               return read_cache();
+               return read_index(state->repo->index);
 }
 
 /* This function tries to read the object name from the current index */
@@ -4012,10 +4030,10 @@ static int get_current_oid(struct apply_state *state, const char *path,
 
        if (read_apply_cache(state) < 0)
                return -1;
-       pos = cache_name_pos(path, strlen(path));
+       pos = index_name_pos(state->repo->index, path, strlen(path));
        if (pos < 0)
                return -1;
-       oidcpy(oid, &active_cache[pos]->oid);
+       oidcpy(oid, &state->repo->index->cache[pos]->oid);
        return 0;
 }
 
@@ -4044,16 +4062,16 @@ static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
            starts_with(++preimage, heading) &&
            /* does it record full SHA-1? */
            !get_oid_hex(preimage + sizeof(heading) - 1, oid) &&
-           preimage[sizeof(heading) + GIT_SHA1_HEXSZ - 1] == '\n' &&
+           preimage[sizeof(heading) + the_hash_algo->hexsz - 1] == '\n' &&
            /* does the abbreviated name on the index line agree with it? */
-           starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
+           starts_with(preimage + sizeof(heading) - 1, p->old_oid_prefix))
                return 0; /* it all looks fine */
 
        /* we may have full object name on the index line */
-       return get_oid_hex(p->old_sha1_prefix, oid);
+       return get_oid_hex(p->old_oid_prefix, oid);
 }
 
-/* Build an index that contains the just the files needed for a 3way merge */
+/* Build an index that contains just the files needed for a 3way merge */
 static int build_fake_ancestor(struct apply_state *state, struct patch *list)
 {
        struct patch *patch;
@@ -4079,7 +4097,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
                        else
                                return error(_("sha1 information is lacking or "
                                               "useless for submodule %s"), name);
-               } else if (!get_oid_blob(patch->old_sha1_prefix, &oid)) {
+               } else if (!get_oid_blob(patch->old_oid_prefix, &oid)) {
                        ; /* ok */
                } else if (!patch->lines_added && !patch->lines_deleted) {
                        /* mode-only change: update the current */
@@ -4090,12 +4108,12 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
                        return error(_("sha1 information is lacking or useless "
                                       "(%s)."), name);
 
-               ce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);
+               ce = make_cache_entry(&result, patch->old_mode, &oid, name, 0, 0);
                if (!ce)
                        return error(_("make_cache_entry failed for path '%s'"),
                                     name);
                if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("could not add %s to temporary index"),
                                     name);
                }
@@ -4242,8 +4260,8 @@ static void patch_stats(struct apply_state *state, struct patch *patch)
 
 static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
 {
-       if (state->update_index) {
-               if (remove_file_from_cache(patch->old_name) < 0)
+       if (state->update_index && !state->ita_only) {
+               if (remove_file_from_index(state->repo->index, patch->old_name) < 0)
                        return error(_("unable to remove %s from index"), patch->old_name);
        }
        if (!state->cached) {
@@ -4263,28 +4281,27 @@ static int add_index_file(struct apply_state *state,
        struct stat st;
        struct cache_entry *ce;
        int namelen = strlen(path);
-       unsigned ce_size = cache_entry_size(namelen);
-
-       if (!state->update_index)
-               return 0;
 
-       ce = xcalloc(1, ce_size);
+       ce = make_empty_cache_entry(state->repo->index, namelen);
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = namelen;
-       if (S_ISGITLINK(mode)) {
+       if (state->ita_only) {
+               ce->ce_flags |= CE_INTENT_TO_ADD;
+               set_object_name_for_intent_to_add_entry(ce);
+       } else if (S_ISGITLINK(mode)) {
                const char *s;
 
                if (!skip_prefix(buf, "Subproject commit ", &s) ||
                    get_oid_hex(s, &ce->oid)) {
-                       free(ce);
-                      return error(_("corrupt patch for submodule %s"), path);
+                       discard_cache_entry(ce);
+                       return error(_("corrupt patch for submodule %s"), path);
                }
        } else {
                if (!state->cached) {
                        if (lstat(path, &st) < 0) {
-                               free(ce);
+                               discard_cache_entry(ce);
                                return error_errno(_("unable to stat newly "
                                                     "created file '%s'"),
                                                   path);
@@ -4292,13 +4309,13 @@ static int add_index_file(struct apply_state *state,
                        fill_stat_cache_info(ce, &st);
                }
                if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("unable to create backing store "
                                       "for newly created file %s"), path);
                }
        }
-       if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
-               free(ce);
+       if (add_index_entry(state->repo->index, ce, ADD_CACHE_OK_TO_ADD) < 0) {
+               discard_cache_entry(ce);
                return error(_("unable to add cache entry for %s"), path);
        }
 
@@ -4311,7 +4328,9 @@ static int add_index_file(struct apply_state *state,
  *   0 if everything went well
  *   1 if a recoverable error happened
  */
-static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
+static int try_create_file(struct apply_state *state, const char *path,
+                          unsigned int mode, const char *buf,
+                          unsigned long size)
 {
        int fd, res;
        struct strbuf nbuf = STRBUF_INIT;
@@ -4333,7 +4352,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
        if (fd < 0)
                return 1;
 
-       if (convert_to_working_tree(path, buf, size, &nbuf)) {
+       if (convert_to_working_tree(state->repo->index, path, buf, size, &nbuf)) {
                size = nbuf.len;
                buf  = nbuf.buf;
        }
@@ -4369,7 +4388,7 @@ static int create_one_file(struct apply_state *state,
        if (state->cached)
                return 0;
 
-       res = try_create_file(path, mode, buf, size);
+       res = try_create_file(state, path, mode, buf, size);
        if (res < 0)
                return -1;
        if (!res)
@@ -4378,7 +4397,7 @@ static int create_one_file(struct apply_state *state,
        if (errno == ENOENT) {
                if (safe_create_leading_directories(path))
                        return 0;
-               res = try_create_file(path, mode, buf, size);
+               res = try_create_file(state, path, mode, buf, size);
                if (res < 0)
                        return -1;
                if (!res)
@@ -4400,7 +4419,7 @@ static int create_one_file(struct apply_state *state,
                for (;;) {
                        char newpath[PATH_MAX];
                        mksnpath(newpath, sizeof(newpath), "%s~%u", path, nr);
-                       res = try_create_file(newpath, mode, buf, size);
+                       res = try_create_file(state, newpath, mode, buf, size);
                        if (res < 0)
                                return -1;
                        if (!res) {
@@ -4422,27 +4441,26 @@ static int add_conflicted_stages_file(struct apply_state *state,
                                       struct patch *patch)
 {
        int stage, namelen;
-       unsigned ce_size, mode;
+       unsigned mode;
        struct cache_entry *ce;
 
        if (!state->update_index)
                return 0;
        namelen = strlen(patch->new_name);
-       ce_size = cache_entry_size(namelen);
        mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
 
-       remove_file_from_cache(patch->new_name);
+       remove_file_from_index(state->repo->index, patch->new_name);
        for (stage = 1; stage < 4; stage++) {
                if (is_null_oid(&patch->threeway_stage[stage - 1]))
                        continue;
-               ce = xcalloc(1, ce_size);
+               ce = make_empty_cache_entry(state->repo->index, namelen);
                memcpy(ce->name, patch->new_name, namelen);
                ce->ce_mode = create_ce_mode(mode);
                ce->ce_flags = create_ce_flags(stage);
                ce->ce_namelen = namelen;
                oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
-               if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
-                       free(ce);
+               if (add_index_entry(state->repo->index, ce, ADD_CACHE_OK_TO_ADD) < 0) {
+                       discard_cache_entry(ce);
                        return error(_("unable to add cache entry for %s"),
                                     patch->new_name);
                }
@@ -4465,8 +4483,9 @@ static int create_file(struct apply_state *state, struct patch *patch)
 
        if (patch->conflicted_threeway)
                return add_conflicted_stages_file(state, patch);
-       else
+       else if (state->update_index)
                return add_index_file(state, path, mode, buf, size);
+       return 0;
 }
 
 /* phase zero is to remove, phase one is to create */
@@ -4615,7 +4634,7 @@ static int write_out_results(struct apply_state *state, struct patch *list)
                }
                string_list_clear(&cpath, 0);
 
-               rerere(0);
+               repo_rerere(state->repo, 0);
        }
 
        return errs;
@@ -4686,7 +4705,7 @@ static int apply_patch(struct apply_state *state,
        if (state->whitespace_error && (state->ws_error_action == die_on_ws_error))
                state->apply = 0;
 
-       state->update_index = state->check_index && state->apply;
+       state->update_index = (state->check_index || state->ita_only) && state->apply;
        if (state->update_index && !is_lock_file_locked(&state->lock_file)) {
                if (state->index_file)
                        hold_lock_file_for_update(&state->lock_file,
@@ -4889,7 +4908,7 @@ int apply_all_patches(struct apply_state *state,
        }
 
        if (state->update_index) {
-               res = write_locked_index(&the_index, &state->lock_file, COMMIT_LOCK);
+               res = write_locked_index(state->repo->index, &state->lock_file, COMMIT_LOCK);
                if (res) {
                        error(_("Unable to write new index file"));
                        res = -128;
@@ -4941,6 +4960,8 @@ int apply_parse_options(int argc, const char **argv,
                        N_("instead of applying the patch, see if the patch is applicable")),
                OPT_BOOL(0, "index", &state->check_index,
                        N_("make sure the patch is applicable to the current index")),
+               OPT_BOOL('N', "intent-to-add", &state->ita_only,
+                       N_("mark new files with `git add --intent-to-add`")),
                OPT_BOOL(0, "cached", &state->cached,
                        N_("apply a patch without touching the working tree")),
                OPT_BOOL_F(0, "unsafe-paths", &state->unsafe_paths,