cvsserver: Do not include status output for subdirectories if -l is passed
[gitweb.git] / unpack-trees.c
index ee9be29374cb9ad65ced0c30bd62c7b569e4ccd8..a59f47557a2b3760c27b93fa678697c35211f952 100644 (file)
@@ -1,3 +1,4 @@
+#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "dir.h"
 #include "tree.h"
@@ -7,10 +8,18 @@
 #include "progress.h"
 #include "refs.h"
 
-static inline void remove_entry(int remove)
+static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+       unsigned int set, unsigned int clear)
 {
-       if (remove >= 0)
-               remove_cache_entry_at(remove);
+       unsigned int size = ce_size(ce);
+       struct cache_entry *new = xmalloc(size);
+
+       clear |= CE_HASHED | CE_UNHASHED;
+
+       memcpy(new, ce, size);
+       new->next = NULL;
+       new->ce_flags = (new->ce_flags & ~clear) | set;
+       add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|ADD_CACHE_SKIP_DFCHECK);
 }
 
 /* Unlink the last component and attempt to remove leading
@@ -45,16 +54,18 @@ static void unlink_entry(char *name, char *last_symlink)
 }
 
 static struct checkout state;
-static void check_updates(struct unpack_trees_options *o)
+static int check_updates(struct unpack_trees_options *o)
 {
        unsigned cnt = 0, total = 0;
        struct progress *progress = NULL;
        char last_symlink[PATH_MAX];
+       struct index_state *index = &o->result;
        int i;
+       int errs = 0;
 
        if (o->update && o->verbose_update) {
-               for (total = cnt = 0; cnt < active_nr; cnt++) {
-                       struct cache_entry *ce = active_cache[cnt];
+               for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
+                       struct cache_entry *ce = index->cache[cnt];
                        if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
                                total++;
                }
@@ -65,57 +76,56 @@ static void check_updates(struct unpack_trees_options *o)
        }
 
        *last_symlink = '\0';
-       for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
+       for (i = 0; i < index->cache_nr; i++) {
+               struct cache_entry *ce = index->cache[i];
 
                if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
                        display_progress(progress, ++cnt);
                if (ce->ce_flags & CE_REMOVE) {
                        if (o->update)
                                unlink_entry(ce->name, last_symlink);
-                       remove_cache_entry_at(i);
+                       remove_index_entry_at(&o->result, i);
                        i--;
                        continue;
                }
                if (ce->ce_flags & CE_UPDATE) {
                        ce->ce_flags &= ~CE_UPDATE;
                        if (o->update) {
-                               checkout_entry(ce, &state, NULL);
+                               errs |= checkout_entry(ce, &state, NULL);
                                *last_symlink = '\0';
                        }
                }
        }
        stop_progress(&progress);
+       return errs != 0;
 }
 
-static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o, int remove)
+static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o)
 {
-       int ret = o->fn(src, o, remove);
-       if (ret > 0) {
-               o->pos += ret;
+       int ret = o->fn(src, o);
+       if (ret > 0)
                ret = 0;
-       }
        return ret;
 }
 
 static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_options *o)
 {
        struct cache_entry *src[5] = { ce, };
+
+       o->pos++;
        if (ce_stage(ce)) {
                if (o->skip_unmerged) {
-                       o->pos++;
-               } else {
-                       remove_entry(o->pos);
+                       add_entry(o, ce, 0, 0);
+                       return 0;
                }
-               return 0;
        }
-       return call_unpack_fn(src, o, o->pos);
+       return call_unpack_fn(src, o);
 }
 
 int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info)
 {
        int i;
-       struct tree_desc t[3];
+       struct tree_desc t[MAX_UNPACK_TREES];
        struct traverse_info newinfo;
        struct name_entry *p;
 
@@ -135,8 +145,7 @@ int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conf
                        sha1 = names[i].sha1;
                fill_tree_descriptor(t+i, sha1);
        }
-       traverse_trees(n, t, &newinfo);
-       return 0;
+       return traverse_trees(n, t, &newinfo);
 }
 
 /*
@@ -199,7 +208,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
 }
 
 static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmask, struct cache_entry *src[5],
-       const struct name_entry *names, const struct traverse_info *info, int remove)
+       const struct name_entry *names, const struct traverse_info *info)
 {
        int i;
        struct unpack_trees_options *o = info->data;
@@ -239,12 +248,11 @@ static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmas
        }
 
        if (o->merge)
-               return call_unpack_fn(src, o, remove);
+               return call_unpack_fn(src, o);
 
        n += o->merge;
-       remove_entry(remove);
        for (i = 0; i < n; i++)
-               add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+               add_entry(o, src[i], 0, 0);
        return 0;
 }
 
@@ -252,7 +260,6 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 {
        struct cache_entry *src[5] = { NULL, };
        struct unpack_trees_options *o = info->data;
-       int remove = -1;
        const struct name_entry *p = names;
 
        /* Find first entry with a real name (we could use "mask" too) */
@@ -261,8 +268,8 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 
        /* Are we supposed to look at the index too? */
        if (o->merge) {
-               while (o->pos < active_nr) {
-                       struct cache_entry *ce = active_cache[o->pos];
+               while (o->pos < o->src_index->cache_nr) {
+                       struct cache_entry *ce = o->src_index->cache[o->pos];
                        int cmp = compare_entry(ce, info, p);
                        if (cmp < 0) {
                                if (unpack_index_entry(ce, o) < 0)
@@ -270,24 +277,24 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
                                continue;
                        }
                        if (!cmp) {
+                               o->pos++;
                                if (ce_stage(ce)) {
                                        /*
                                         * If we skip unmerged index entries, we'll skip this
                                         * entry *and* the tree entries associated with it!
                                         */
-                                       if (o->skip_unmerged)
+                                       if (o->skip_unmerged) {
+                                               add_entry(o, ce, 0, 0);
                                                return mask;
-                                       remove_entry(o->pos);
-                                       continue;
+                                       }
                                }
                                src[0] = ce;
-                               remove = o->pos;
                        }
                        break;
                }
        }
 
-       if (unpack_nondirectories(n, mask, dirmask, src, names, info, remove) < 0)
+       if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0)
                return -1;
 
        /* Now handle any directories.. */
@@ -298,7 +305,9 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
                        if (src[0])
                                conflicts |= 1;
                }
-               traverse_trees_recursive(n, dirmask, conflicts, names, info);
+               if (traverse_trees_recursive(n, dirmask, conflicts,
+                                            names, info) < 0)
+                       return -1;
                return mask;
        }
 
@@ -307,13 +316,12 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 
 static int unpack_failed(struct unpack_trees_options *o, const char *message)
 {
+       discard_index(&o->result);
        if (!o->gently) {
                if (message)
                        return error(message);
                return -1;
        }
-       discard_cache();
-       read_cache();
        return -1;
 }
 
@@ -321,14 +329,17 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 {
        static struct cache_entry *dfc;
 
-       if (len > 4)
-               die("unpack_trees takes at most four trees");
+       if (len > MAX_UNPACK_TREES)
+               die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
        memset(&state, 0, sizeof(state));
        state.base_dir = "";
        state.force = 1;
        state.quiet = 1;
        state.refresh_cache = 1;
 
+       memset(&o->result, 0, sizeof(o->result));
+       if (o->src_index)
+               o->result.timestamp = o->src_index->timestamp;
        o->merge_size = len;
 
        if (!dfc)
@@ -349,8 +360,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
        /* Any left-over entries in the index? */
        if (o->merge) {
-               while (o->pos < active_nr) {
-                       struct cache_entry *ce = active_cache[o->pos];
+               while (o->pos < o->src_index->cache_nr) {
+                       struct cache_entry *ce = o->src_index->cache[o->pos];
                        if (unpack_index_entry(ce, o) < 0)
                                return unpack_failed(o, NULL);
                }
@@ -359,7 +370,11 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        if (o->trivial_merges_only && o->nontrivial_merge)
                return unpack_failed(o, "Merge requires file-level merging");
 
-       check_updates(o);
+       o->src_index = NULL;
+       if (check_updates(o))
+               return -1;
+       if (o->dst_index)
+               *o->dst_index = o->result;
        return 0;
 }
 
@@ -395,7 +410,7 @@ static int verify_uptodate(struct cache_entry *ce,
                return 0;
 
        if (!lstat(ce->name, &st)) {
-               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
+               unsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return 0;
                /*
@@ -415,10 +430,10 @@ static int verify_uptodate(struct cache_entry *ce,
                error("Entry '%s' not uptodate. Cannot merge.", ce->name);
 }
 
-static void invalidate_ce_path(struct cache_entry *ce)
+static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
 {
        if (ce)
-               cache_tree_invalidate_path(active_cache_tree, ce->name);
+               cache_tree_invalidate_path(o->src_index->cache_tree, ce->name);
 }
 
 /*
@@ -463,12 +478,12 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
         * in that directory.
         */
        namelen = strlen(ce->name);
-       pos = cache_name_pos(ce->name, namelen);
+       pos = index_name_pos(o->src_index, ce->name, namelen);
        if (0 <= pos)
                return cnt; /* we have it as nondirectory */
        pos = -pos - 1;
-       for (i = pos; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
+       for (i = pos; i < o->src_index->cache_nr; i++) {
+               struct cache_entry *ce = o->src_index->cache[i];
                int len = ce_namelen(ce);
                if (len < namelen ||
                    strncmp(ce->name, ce->name, namelen) ||
@@ -480,7 +495,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
                if (!ce_stage(ce)) {
                        if (verify_uptodate(ce, o))
                                return -1;
-                       ce->ce_flags |= CE_REMOVE;
+                       add_entry(o, ce, CE_REMOVE, 0);
                }
                cnt++;
        }
@@ -566,9 +581,9 @@ static int verify_absent(struct cache_entry *ce, const char *action,
                 * delete this path, which is in a subdirectory that
                 * is being replaced with a blob.
                 */
-               cnt = cache_name_pos(ce->name, strlen(ce->name));
+               cnt = index_name_pos(&o->result, ce->name, strlen(ce->name));
                if (0 <= cnt) {
-                       struct cache_entry *ce = active_cache[cnt];
+                       struct cache_entry *ce = o->result.cache[cnt];
                        if (ce->ce_flags & CE_REMOVE)
                                return 0;
                }
@@ -583,52 +598,54 @@ static int verify_absent(struct cache_entry *ce, const char *action,
 static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
                struct unpack_trees_options *o)
 {
-       merge->ce_flags |= CE_UPDATE;
+       int update = CE_UPDATE;
+
        if (old) {
                /*
                 * See if we can re-use the old CE directly?
                 * That way we get the uptodate stat info.
                 *
-                * This also removes the UPDATE flag on
-                * a match.
+                * This also removes the UPDATE flag on a match; otherwise
+                * we will end up overwriting local changes in the work tree.
                 */
                if (same(old, merge)) {
                        copy_cache_entry(merge, old);
+                       update = 0;
                } else {
                        if (verify_uptodate(old, o))
                                return -1;
-                       invalidate_ce_path(old);
+                       invalidate_ce_path(old, o);
                }
        }
        else {
                if (verify_absent(merge, "overwritten", o))
                        return -1;
-               invalidate_ce_path(merge);
+               invalidate_ce_path(merge, o);
        }
 
-       merge->ce_flags &= ~CE_STAGEMASK;
-       add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+       add_entry(o, merge, update, CE_STAGEMASK);
        return 1;
 }
 
 static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
                struct unpack_trees_options *o)
 {
-       if (old) {
-               if (verify_uptodate(old, o))
-                       return -1;
-       } else
+       /* Did it exist in the index? */
+       if (!old) {
                if (verify_absent(ce, "removed", o))
                        return -1;
-       ce->ce_flags |= CE_REMOVE;
-       add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
-       invalidate_ce_path(ce);
+               return 0;
+       }
+       if (verify_uptodate(old, o))
+               return -1;
+       add_entry(o, ce, CE_REMOVE, 0);
+       invalidate_ce_path(ce, o);
        return 1;
 }
 
 static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o)
 {
-       add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+       add_entry(o, ce, 0, 0);
        return 1;
 }
 
@@ -648,9 +665,7 @@ static void show_stage_entry(FILE *o,
 }
 #endif
 
-int threeway_merge(struct cache_entry **stages,
-               struct unpack_trees_options *o,
-               int remove)
+int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
 {
        struct cache_entry *index;
        struct cache_entry *head;
@@ -727,10 +742,8 @@ int threeway_merge(struct cache_entry **stages,
        }
 
        /* #1 */
-       if (!head && !remote && any_anc_missing) {
-               remove_entry(remove);
+       if (!head && !remote && any_anc_missing)
                return 0;
-       }
 
        /* Under the new "aggressive" rule, we resolve mostly trivial
         * cases that we historically had git-merge-one-file resolve.
@@ -762,10 +775,9 @@ int threeway_merge(struct cache_entry **stages,
                if ((head_deleted && remote_deleted) ||
                    (head_deleted && remote && remote_match) ||
                    (remote_deleted && head && head_match)) {
-                       remove_entry(remove);
                        if (index)
                                return deleted_entry(index, index, o);
-                       else if (ce && !head_deleted) {
+                       if (ce && !head_deleted) {
                                if (verify_absent(ce, "removed", o))
                                        return -1;
                        }
@@ -788,7 +800,6 @@ int threeway_merge(struct cache_entry **stages,
                        return -1;
        }
 
-       remove_entry(remove);
        o->nontrivial_merge = 1;
 
        /* #2, #3, #4, #6, #7, #9, #10, #11. */
@@ -823,9 +834,7 @@ int threeway_merge(struct cache_entry **stages,
  * "carry forward" rule, please see <Documentation/git-read-tree.txt>.
  *
  */
-int twoway_merge(struct cache_entry **src,
-               struct unpack_trees_options *o,
-               int remove)
+int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
 {
        struct cache_entry *current = src[0];
        struct cache_entry *oldtree = src[1];
@@ -853,7 +862,6 @@ int twoway_merge(struct cache_entry **src,
                }
                else if (oldtree && !newtree && same(current, oldtree)) {
                        /* 10 or 11 */
-                       remove_entry(remove);
                        return deleted_entry(oldtree, current, o);
                }
                else if (oldtree && newtree &&
@@ -863,7 +871,6 @@ int twoway_merge(struct cache_entry **src,
                }
                else {
                        /* all other failures */
-                       remove_entry(remove);
                        if (oldtree)
                                return o->gently ? -1 : reject_merge(oldtree);
                        if (current)
@@ -875,7 +882,6 @@ int twoway_merge(struct cache_entry **src,
        }
        else if (newtree)
                return merged_entry(newtree, current, o);
-       remove_entry(remove);
        return deleted_entry(oldtree, current, o);
 }
 
@@ -886,8 +892,7 @@ int twoway_merge(struct cache_entry **src,
  * stage0 does not have anything there.
  */
 int bind_merge(struct cache_entry **src,
-               struct unpack_trees_options *o,
-               int remove)
+               struct unpack_trees_options *o)
 {
        struct cache_entry *old = src[0];
        struct cache_entry *a = src[1];
@@ -897,7 +902,7 @@ int bind_merge(struct cache_entry **src,
                             o->merge_size);
        if (a && old)
                return o->gently ? -1 :
-                       error("Entry '%s' overlaps.  Cannot bind.", a->name);
+                       error("Entry '%s' overlaps with '%s'.  Cannot bind.", a->name, old->name);
        if (!a)
                return keep_entry(old, o);
        else
@@ -910,9 +915,7 @@ int bind_merge(struct cache_entry **src,
  * The rule is:
  * - take the stat information from stage0, take the data from stage1
  */
-int oneway_merge(struct cache_entry **src,
-               struct unpack_trees_options *o,
-               int remove)
+int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)
 {
        struct cache_entry *old = src[0];
        struct cache_entry *a = src[1];
@@ -921,18 +924,19 @@ int oneway_merge(struct cache_entry **src,
                return error("Cannot do a oneway merge of %d trees",
                             o->merge_size);
 
-       if (!a) {
-               remove_entry(remove);
+       if (!a)
                return deleted_entry(old, old, o);
-       }
+
        if (old && same(old, a)) {
+               int update = 0;
                if (o->reset) {
                        struct stat st;
                        if (lstat(old->name, &st) ||
-                           ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID))
-                               old->ce_flags |= CE_UPDATE;
+                           ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID))
+                               update |= CE_UPDATE;
                }
-               return keep_entry(old, o);
+               add_entry(o, old, update, 0);
+               return 0;
        }
        return merged_entry(a, old, o);
 }