Merge branch 'sg/fast-import-dump-refs-on-checkpoint-fix'
[gitweb.git] / unpack-trees.c
index 79fd97074ec238714634de1c9e6144accdc710f3..f9efee0836a20e7072477ae0f3de7c9e1a29ff78 100644 (file)
@@ -1,5 +1,6 @@
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
+#include "argv-array.h"
 #include "repository.h"
 #include "config.h"
 #include "dir.h"
@@ -15,6 +16,7 @@
 #include "submodule.h"
 #include "submodule-config.h"
 #include "fsmonitor.h"
+#include "object-store.h"
 #include "fetch-object.h"
 
 /*
@@ -103,6 +105,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
        const char **msgs = opts->msgs;
        const char *msg;
 
+       argv_array_init(&opts->msgs_to_free);
+
        if (!strcmp(cmd, "checkout"))
                msg = advice_commit_before_merge
                      ? _("Your local changes to the following files would be overwritten by checkout:\n%%s"
@@ -119,7 +123,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                          "Please commit your changes or stash them before you %s.")
                      : _("Your local changes to the following files would be overwritten by %s:\n%%s");
        msgs[ERROR_WOULD_OVERWRITE] = msgs[ERROR_NOT_UPTODATE_FILE] =
-               xstrfmt(msg, cmd, cmd);
+               argv_array_pushf(&opts->msgs_to_free, msg, cmd, cmd);
 
        msgs[ERROR_NOT_UPTODATE_DIR] =
                _("Updating the following directories would lose untracked files in them:\n%s");
@@ -139,7 +143,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                      ? _("The following untracked working tree files would be removed by %s:\n%%s"
                          "Please move or remove them before you %s.")
                      : _("The following untracked working tree files would be removed by %s:\n%%s");
-       msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = xstrfmt(msg, cmd, cmd);
+       msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] =
+               argv_array_pushf(&opts->msgs_to_free, msg, cmd, cmd);
 
        if (!strcmp(cmd, "checkout"))
                msg = advice_commit_before_merge
@@ -156,7 +161,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                      ? _("The following untracked working tree files would be overwritten by %s:\n%%s"
                          "Please move or remove them before you %s.")
                      : _("The following untracked working tree files would be overwritten by %s:\n%%s");
-       msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = xstrfmt(msg, cmd, cmd);
+       msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] =
+               argv_array_pushf(&opts->msgs_to_free, msg, cmd, cmd);
 
        /*
         * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
@@ -179,6 +185,12 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                opts->unpack_rejects[i].strdup_strings = 1;
 }
 
+void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
+{
+       argv_array_clear(&opts->msgs_to_free);
+       memset(opts->msgs, 0, sizeof(opts->msgs));
+}
+
 static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
                         unsigned int set, unsigned int clear)
 {
@@ -192,20 +204,11 @@ static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
                               ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
 }
 
-static struct cache_entry *dup_entry(const struct cache_entry *ce)
-{
-       unsigned int size = ce_size(ce);
-       struct cache_entry *new_entry = xmalloc(size);
-
-       memcpy(new_entry, ce, size);
-       return new_entry;
-}
-
 static void add_entry(struct unpack_trees_options *o,
                      const struct cache_entry *ce,
                      unsigned int set, unsigned int clear)
 {
-       do_add_entry(o, dup_entry(ce), set, clear);
+       do_add_entry(o, dup_cache_entry(ce, &o->result), set, clear);
 }
 
 /*
@@ -290,7 +293,7 @@ static void load_gitmodules_file(struct index_state *index,
                if (!state && ce->ce_flags & CE_WT_REMOVE) {
                        repo_read_gitmodules(the_repository);
                } else if (state && (ce->ce_flags & CE_UPDATE)) {
-                       submodule_free();
+                       submodule_free(the_repository);
                        checkout_entry(ce, state, NULL);
                        repo_read_gitmodules(the_repository);
                }
@@ -398,7 +401,7 @@ static int check_updates(struct unpack_trees_options *o)
 
                if (ce->ce_flags & CE_UPDATE) {
                        if (ce->ce_flags & CE_WT_REMOVE)
-                               die("BUG: both update and delete flags are set on %s",
+                               BUG("both update and delete flags are set on %s",
                                    ce->name);
                        display_progress(progress, ++cnt);
                        ce->ce_flags &= ~CE_UPDATE;
@@ -786,10 +789,17 @@ static int ce_in_traverse_path(const struct cache_entry *ce,
        return (info->pathlen < ce_namelen(ce));
 }
 
-static struct cache_entry *create_ce_entry(const struct traverse_info *info, const struct name_entry *n, int stage)
+static struct cache_entry *create_ce_entry(const struct traverse_info *info,
+       const struct name_entry *n,
+       int stage,
+       struct index_state *istate,
+       int is_transient)
 {
        int len = traverse_path_len(info, n);
-       struct cache_entry *ce = xcalloc(1, cache_entry_size(len));
+       struct cache_entry *ce =
+               is_transient ?
+               make_empty_transient_cache_entry(len) :
+               make_empty_cache_entry(istate, len);
 
        ce->ce_mode = create_ce_mode(n->mode);
        ce->ce_flags = create_ce_flags(stage);
@@ -835,7 +845,15 @@ static int unpack_nondirectories(int n, unsigned long mask,
                        stage = 3;
                else
                        stage = 2;
-               src[i + o->merge] = create_ce_entry(info, names + i, stage);
+
+               /*
+                * If the merge bit is set, then the cache entries are
+                * discarded in the following block.  In this case,
+                * construct "transient" cache_entries, as they are
+                * not stored in the index.  otherwise construct the
+                * cache entry from the index aware logic.
+                */
+               src[i + o->merge] = create_ce_entry(info, names + i, stage, &o->result, o->merge);
        }
 
        if (o->merge) {
@@ -844,7 +862,7 @@ static int unpack_nondirectories(int n, unsigned long mask,
                for (i = 0; i < n; i++) {
                        struct cache_entry *ce = src[i + o->merge];
                        if (ce != o->df_conflict_entry)
-                               free(ce);
+                               discard_cache_entry(ce);
                }
                return rc;
        }
@@ -1235,7 +1253,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,
                if (select_flag && !(ce->ce_flags & select_flag))
                        continue;
 
-               if (!ce_stage(ce))
+               if (!ce_stage(ce) && !(ce->ce_flags & CE_CONFLICTED))
                        ce->ce_flags |= skip_wt_flag;
                else
                        ce->ce_flags &= ~skip_wt_flag;
@@ -1284,10 +1302,21 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        o->result.timestamp.sec = o->src_index->timestamp.sec;
        o->result.timestamp.nsec = o->src_index->timestamp.nsec;
        o->result.version = o->src_index->version;
-       o->result.split_index = o->src_index->split_index;
-       if (o->result.split_index)
+       if (!o->src_index->split_index) {
+               o->result.split_index = NULL;
+       } else if (o->src_index == o->dst_index) {
+               /*
+                * o->dst_index (and thus o->src_index) will be discarded
+                * and overwritten with o->result at the end of this function,
+                * so just use src_index's split_index to avoid having to
+                * create a new one.
+                */
+               o->result.split_index = o->src_index->split_index;
                o->result.split_index->refcount++;
-       hashcpy(o->result.sha1, o->src_index->sha1);
+       } else {
+               o->result.split_index = init_split_index(&o->result);
+       }
+       oidcpy(&o->result.oid, &o->src_index->oid);
        o->merge_size = len;
        mark_all_ce_unused(o->src_index);
 
@@ -1401,7 +1430,6 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                }
        }
 
-       o->src_index = NULL;
        ret = check_updates(o) ? (-2) : 0;
        if (o->dst_index) {
                if (!ret) {
@@ -1412,12 +1440,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                                                  WRITE_TREE_SILENT |
                                                  WRITE_TREE_REPAIR);
                }
-               move_index_extensions(&o->result, o->dst_index);
+               move_index_extensions(&o->result, o->src_index);
                discard_index(o->dst_index);
                *o->dst_index = o->result;
        } else {
                discard_index(&o->result);
        }
+       o->src_index = NULL;
 
 done:
        clear_exclude_list(&el);
@@ -1765,7 +1794,7 @@ static int merged_entry(const struct cache_entry *ce,
                        struct unpack_trees_options *o)
 {
        int update = CE_UPDATE;
-       struct cache_entry *merge = dup_entry(ce);
+       struct cache_entry *merge = dup_cache_entry(ce, &o->result);
 
        if (!old) {
                /*
@@ -1785,7 +1814,7 @@ static int merged_entry(const struct cache_entry *ce,
 
                if (verify_absent(merge,
                                  ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
-                       free(merge);
+                       discard_cache_entry(merge);
                        return -1;
                }
                invalidate_ce_path(merge, o);
@@ -1811,7 +1840,7 @@ static int merged_entry(const struct cache_entry *ce,
                        update = 0;
                } else {
                        if (verify_uptodate(old, o)) {
-                               free(merge);
+                               discard_cache_entry(merge);
                                return -1;
                        }
                        /* Migrate old flags over */