Merge branch 'rs/no-null-ptr-arith-in-fast-export'
[gitweb.git] / unpack-trees.c
index 862cfce661e57e50f7c6030dd5a8eda0add0cca5..0f01be60047fff034fed2280981e1ad70abf6ed9 100644 (file)
@@ -1,5 +1,6 @@
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
+#include "repository.h"
 #include "config.h"
 #include "dir.h"
 #include "tree.h"
@@ -13,6 +14,8 @@
 #include "dir.h"
 #include "submodule.h"
 #include "submodule-config.h"
+#include "fsmonitor.h"
+#include "fetch-object.h"
 
 /*
  * Error messages expected by scripts out of plumbing commands such as
@@ -162,7 +165,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
        msgs[ERROR_BIND_OVERLAP] = _("Entry '%s' overlaps with '%s'.  Cannot bind.");
 
        msgs[ERROR_SPARSE_NOT_UPTODATE_FILE] =
-               _("Cannot update sparse checkout: the following entries are not up-to-date:\n%s");
+               _("Cannot update sparse checkout: the following entries are not up to date:\n%s");
        msgs[ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN] =
                _("The following working tree files would be overwritten by sparse checkout update:\n%s");
        msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
@@ -192,10 +195,10 @@ static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
 static struct cache_entry *dup_entry(const struct cache_entry *ce)
 {
        unsigned int size = ce_size(ce);
-       struct cache_entry *new = xmalloc(size);
+       struct cache_entry *new_entry = xmalloc(size);
 
-       memcpy(new, ce, size);
-       return new;
+       memcpy(new_entry, ce, size);
+       return new_entry;
 }
 
 static void add_entry(struct unpack_trees_options *o,
@@ -255,47 +258,41 @@ static int check_submodule_move_head(const struct cache_entry *ce,
 {
        unsigned flags = SUBMODULE_MOVE_HEAD_DRY_RUN;
        const struct submodule *sub = submodule_from_ce(ce);
+
        if (!sub)
                return 0;
 
        if (o->reset)
                flags |= SUBMODULE_MOVE_HEAD_FORCE;
 
-       switch (sub->update_strategy.type) {
-       case SM_UPDATE_UNSPECIFIED:
-       case SM_UPDATE_CHECKOUT:
-               if (submodule_move_head(ce->name, old_id, new_id, flags))
-                       return o->gently ? -1 :
-                               add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
-               return 0;
-       case SM_UPDATE_NONE:
-               return 0;
-       case SM_UPDATE_REBASE:
-       case SM_UPDATE_MERGE:
-       case SM_UPDATE_COMMAND:
-       default:
-               warning(_("submodule update strategy not supported for submodule '%s'"), ce->name);
-               return -1;
-       }
+       if (submodule_move_head(ce->name, old_id, new_id, flags))
+               return o->gently ? -1 :
+                                  add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
+       return 0;
 }
 
-static void reload_gitmodules_file(struct index_state *index,
-                                  struct checkout *state)
+/*
+ * Preform the loading of the repository's gitmodules file.  This function is
+ * used by 'check_update()' to perform loading of the gitmodules file in two
+ * differnt situations:
+ * (1) before removing entries from the working tree if the gitmodules file has
+ *     been marked for removal.  This situation is specified by 'state' == NULL.
+ * (2) before checking out entries to the working tree if the gitmodules file
+ *     has been marked for update.  This situation is specified by 'state' != NULL.
+ */
+static void load_gitmodules_file(struct index_state *index,
+                                struct checkout *state)
 {
-       int i;
-       for (i = 0; i < index->cache_nr; i++) {
-               struct cache_entry *ce = index->cache[i];
-               if (ce->ce_flags & CE_UPDATE) {
-                       int r = strcmp(ce->name, ".gitmodules");
-                       if (r < 0)
-                               continue;
-                       else if (r == 0) {
-                               submodule_free();
-                               checkout_entry(ce, state, NULL);
-                               gitmodules_config();
-                               git_config(submodule_config, NULL);
-                       } else
-                               break;
+       int pos = index_name_pos(index, GITMODULES_FILE, strlen(GITMODULES_FILE));
+
+       if (pos >= 0) {
+               struct cache_entry *ce = index->cache[pos];
+               if (!state && ce->ce_flags & CE_WT_REMOVE) {
+                       repo_read_gitmodules(the_repository);
+               } else if (state && (ce->ce_flags & CE_UPDATE)) {
+                       submodule_free(the_repository);
+                       checkout_entry(ce, state, NULL);
+                       repo_read_gitmodules(the_repository);
                }
        }
 }
@@ -308,19 +305,9 @@ static void unlink_entry(const struct cache_entry *ce)
 {
        const struct submodule *sub = submodule_from_ce(ce);
        if (sub) {
-               switch (sub->update_strategy.type) {
-               case SM_UPDATE_UNSPECIFIED:
-               case SM_UPDATE_CHECKOUT:
-               case SM_UPDATE_REBASE:
-               case SM_UPDATE_MERGE:
-                       /* state.force is set at the caller. */
-                       submodule_move_head(ce->name, "HEAD", NULL,
-                                           SUBMODULE_MOVE_HEAD_FORCE);
-                       break;
-               case SM_UPDATE_NONE:
-               case SM_UPDATE_COMMAND:
-                       return; /* Do not touch the submodule. */
-               }
+               /* state.force is set at the caller. */
+               submodule_move_head(ce->name, "HEAD", NULL,
+                                   SUBMODULE_MOVE_HEAD_FORCE);
        }
        if (!check_leading_path(ce->name, ce_namelen(ce)))
                return;
@@ -343,8 +330,7 @@ static struct progress *get_progress(struct unpack_trees_options *o)
                        total++;
        }
 
-       return start_progress_delay(_("Checking out files"),
-                                   total, 50, 1);
+       return start_delayed_progress(_("Checking out files"), total);
 }
 
 static int check_updates(struct unpack_trees_options *o)
@@ -365,6 +351,10 @@ static int check_updates(struct unpack_trees_options *o)
 
        if (o->update)
                git_attr_set_direction(GIT_ATTR_CHECKOUT, index);
+
+       if (should_update_submodules() && o->update && !o->dry_run)
+               load_gitmodules_file(index, NULL);
+
        for (i = 0; i < index->cache_nr; i++) {
                const struct cache_entry *ce = index->cache[i];
 
@@ -378,9 +368,31 @@ static int check_updates(struct unpack_trees_options *o)
        remove_scheduled_dirs();
 
        if (should_update_submodules() && o->update && !o->dry_run)
-               reload_gitmodules_file(index, &state);
+               load_gitmodules_file(index, &state);
 
        enable_delayed_checkout(&state);
+       if (repository_format_partial_clone && o->update && !o->dry_run) {
+               /*
+                * Prefetch the objects that are to be checked out in the loop
+                * below.
+                */
+               struct oid_array to_fetch = OID_ARRAY_INIT;
+               int fetch_if_missing_store = fetch_if_missing;
+               fetch_if_missing = 0;
+               for (i = 0; i < index->cache_nr; i++) {
+                       struct cache_entry *ce = index->cache[i];
+                       if ((ce->ce_flags & CE_UPDATE) &&
+                           !S_ISGITLINK(ce->ce_mode)) {
+                               if (!has_object_file(&ce->oid))
+                                       oid_array_append(&to_fetch, &ce->oid);
+                       }
+               }
+               if (to_fetch.nr)
+                       fetch_objects(repository_format_partial_clone,
+                                     &to_fetch);
+               fetch_if_missing = fetch_if_missing_store;
+               oid_array_clear(&to_fetch);
+       }
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
 
@@ -395,8 +407,8 @@ static int check_updates(struct unpack_trees_options *o)
                        }
                }
        }
-       errs |= finish_delayed_checkout(&state);
        stop_progress(&progress);
+       errs |= finish_delayed_checkout(&state);
        if (o->update)
                git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
        return errs != 0;
@@ -420,6 +432,7 @@ static int apply_sparse_checkout(struct index_state *istate,
                ce->ce_flags &= ~CE_SKIP_WORKTREE;
        if (was_skip_worktree != ce_skip_worktree(ce)) {
                ce->ce_flags |= CE_UPDATE_IN_BASE;
+               mark_fsmonitor_invalid(istate, ce);
                istate->cache_changed |= CE_ENTRY_CHANGED;
        }
 
@@ -662,10 +675,10 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
                else if (i > 1 && are_same_oid(&names[i], &names[i - 2]))
                        t[i] = t[i - 2];
                else {
-                       const unsigned char *sha1 = NULL;
+                       const struct object_id *oid = NULL;
                        if (dirmask & 1)
-                               sha1 = names[i].oid->hash;
-                       buf[nr_buf++] = fill_tree_descriptor(t+i, sha1);
+                               oid = names[i].oid;
+                       buf[nr_buf++] = fill_tree_descriptor(t + i, oid);
                }
        }
 
@@ -1271,9 +1284,20 @@ 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++;
+       } else {
+               o->result.split_index = init_split_index(&o->result);
+       }
        hashcpy(o->result.sha1, o->src_index->sha1);
        o->merge_size = len;
        mark_all_ce_unused(o->src_index);
@@ -1388,7 +1412,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) {
@@ -1399,12 +1422,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);
@@ -1496,8 +1520,8 @@ static int verify_uptodate_1(const struct cache_entry *ce,
                add_rejected_path(o, error_type, ce->name);
 }
 
-static int verify_uptodate(const struct cache_entry *ce,
-                          struct unpack_trees_options *o)
+int verify_uptodate(const struct cache_entry *ce,
+                   struct unpack_trees_options *o)
 {
        if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
                return 0;
@@ -1516,7 +1540,7 @@ static void invalidate_ce_path(const struct cache_entry *ce,
        if (!ce)
                return;
        cache_tree_invalidate_path(o->src_index, ce->name);
-       untracked_cache_invalidate_path(o->src_index, ce->name);
+       untracked_cache_invalidate_path(o->src_index, ce->name, 1);
 }
 
 /*
@@ -1553,15 +1577,15 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
        int cnt = 0;
 
        if (S_ISGITLINK(ce->ce_mode)) {
-               unsigned char sha1[20];
-               int sub_head = resolve_gitlink_ref(ce->name, "HEAD", sha1);
+               struct object_id oid;
+               int sub_head = resolve_gitlink_ref(ce->name, "HEAD", &oid);
                /*
                 * If we are not going to update the submodule, then
                 * we don't care.
                 */
-               if (!sub_head && !hashcmp(sha1, ce->oid.hash))
+               if (!sub_head && !oidcmp(&oid, &ce->oid))
                        return 0;
-               return verify_clean_submodule(sub_head ? NULL : sha1_to_hex(sha1),
+               return verify_clean_submodule(sub_head ? NULL : oid_to_hex(&oid),
                                              ce, error_type, o);
        }
 
@@ -2149,6 +2173,9 @@ int oneway_merge(const struct cache_entry * const *src,
                            ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
                                update |= CE_UPDATE;
                }
+               if (o->update && S_ISGITLINK(old->ce_mode) &&
+                   should_update_submodules() && !verify_uptodate(old, o))
+                       update |= CE_UPDATE;
                add_entry(o, old, update, 0);
                return 0;
        }