diff-lib: simplify do_diff_cache()
[gitweb.git] / unpack-trees.c
index 149bc5d3585196e7d9b7e773b5e3d875fa6967d4..07f83642443601d107e0a2425407b3250c022dcd 100644 (file)
@@ -16,7 +16,7 @@
  * situation better.  See how "git checkout" and "git merge" replaces
  * them using setup_unpack_trees_porcelain(), for example.
  */
-const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
+static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
        /* ERROR_WOULD_OVERWRITE */
        "Entry '%s' would be overwritten by merge. Cannot merge.",
 
@@ -203,7 +203,7 @@ static int check_updates(struct unpack_trees_options *o)
 
                if (ce->ce_flags & CE_WT_REMOVE) {
                        display_progress(progress, ++cnt);
-                       if (o->update)
+                       if (o->update && !o->dry_run)
                                unlink_entry(ce);
                        continue;
                }
@@ -217,7 +217,7 @@ static int check_updates(struct unpack_trees_options *o)
                if (ce->ce_flags & CE_UPDATE) {
                        display_progress(progress, ++cnt);
                        ce->ce_flags &= ~CE_UPDATE;
-                       if (o->update) {
+                       if (o->update && !o->dry_run) {
                                errs |= checkout_entry(ce, &state, NULL);
                        }
                }
@@ -427,10 +427,6 @@ static int switch_cache_bottom(struct traverse_info *info)
        return ret;
 }
 
-static int fast_forward_merge(int n, unsigned long dirmask,
-                             struct name_entry *names,
-                             struct traverse_info *info);
-
 static int traverse_trees_recursive(int n, unsigned long dirmask,
                                    unsigned long df_conflicts,
                                    struct name_entry *names,
@@ -442,11 +438,6 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
        struct traverse_info newinfo;
        struct name_entry *p;
 
-       if (!df_conflicts) {
-               int status = fast_forward_merge(n, dirmask, names, info);
-               if (status)
-                       return status;
-       }
        p = names;
        while (!p->mode)
                p++;
@@ -694,53 +685,6 @@ static struct cache_entry *find_cache_entry(struct traverse_info *info,
                return NULL;
 }
 
-static int fast_forward_merge(int n, unsigned long dirmask,
-                             struct name_entry *names,
-                             struct traverse_info *info)
-{
-       int i;
-       struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
-       struct unpack_trees_options *o = info->data;
-
-       /* merging two or more trees with an identical subdirectory? */
-       if ((n < 2) || ((1UL << n) - 1) != dirmask ||
-           !o->merge || o->reset || o->initial_checkout)
-               return 0;
-       for (i = 1; i < n; i++)
-               if (hashcmp(names[i-1].sha1, names[i].sha1))
-                       return 0;
-
-       /*
-        * Instead of descending into the directory, keep the contents
-        * of the current index.
-        */
-       while (1) {
-               struct cache_entry *ce;
-               ce = next_cache_entry(o);
-               if (!ce)
-                       break;
-               /* Is the entry still in that directory? */
-               if (do_compare_entry(ce, info, names))
-                       break;
-               /*
-                * Note: we do not just run unpack_index_entry() here,
-                * as the callback may want to compare what is in the
-                * index with what are from the HEAD and the other tree
-                * and reject the merge.  We pretend that ancestors, the
-                * HEAD and the other tree all have the same contents as
-                * the current index, which is a lie, but it works.
-                */
-               for (i = 0; i < n + 1; i++)
-                       src[i] = ce;
-               mark_ce_used(ce, o);
-               if (call_unpack_fn(src, o) < 0)
-                       return unpack_failed(o, NULL);
-               if (ce_stage(ce))
-                       mark_ce_used_same_name(ce, o);
-       }
-       return dirmask;
-}
-
 static void debug_path(struct traverse_info *info)
 {
        if (info->prev) {
@@ -870,43 +814,45 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
        return mask;
 }
 
+static int clear_ce_flags_1(struct cache_entry **cache, int nr,
+                           char *prefix, int prefix_len,
+                           int select_mask, int clear_mask,
+                           struct exclude_list *el, int defval);
+
 /* Whole directory matching */
 static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
                              char *prefix, int prefix_len,
                              char *basename,
                              int select_mask, int clear_mask,
-                             struct exclude_list *el)
+                             struct exclude_list *el, int defval)
 {
-       struct cache_entry **cache_end = cache + nr;
+       struct cache_entry **cache_end;
        int dtype = DT_DIR;
        int ret = excluded_from_list(prefix, prefix_len, basename, &dtype, el);
 
        prefix[prefix_len++] = '/';
 
-       /* included, no clearing for any entries under this directory */
-       if (!ret) {
-               for (; cache != cache_end; cache++) {
-                       struct cache_entry *ce = *cache;
-                       if (strncmp(ce->name, prefix, prefix_len))
-                               break;
-               }
-               return nr - (cache_end - cache);
-       }
+       /* If undecided, use matching result of parent dir in defval */
+       if (ret < 0)
+               ret = defval;
 
-       /* excluded, clear all selected entries under this directory. */
-       if (ret == 1) {
-               for (; cache != cache_end; cache++) {
-                       struct cache_entry *ce = *cache;
-                       if (select_mask && !(ce->ce_flags & select_mask))
-                               continue;
-                       if (strncmp(ce->name, prefix, prefix_len))
-                               break;
-                       ce->ce_flags &= ~clear_mask;
-               }
-               return nr - (cache_end - cache);
+       for (cache_end = cache; cache_end != cache + nr; cache_end++) {
+               struct cache_entry *ce = *cache_end;
+               if (strncmp(ce->name, prefix, prefix_len))
+                       break;
        }
 
-       return 0;
+       /*
+        * TODO: check el, if there are no patterns that may conflict
+        * with ret (iow, we know in advance the incl/excl
+        * decision for the entire directory), clear flag here without
+        * calling clear_ce_flags_1(). That function will call
+        * the expensive excluded_from_list() on every entry.
+        */
+       return clear_ce_flags_1(cache, cache_end - cache,
+                               prefix, prefix_len,
+                               select_mask, clear_mask,
+                               el, ret);
 }
 
 /*
@@ -927,7 +873,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
 static int clear_ce_flags_1(struct cache_entry **cache, int nr,
                            char *prefix, int prefix_len,
                            int select_mask, int clear_mask,
-                           struct exclude_list *el)
+                           struct exclude_list *el, int defval)
 {
        struct cache_entry **cache_end = cache + nr;
 
@@ -938,7 +884,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
        while(cache != cache_end) {
                struct cache_entry *ce = *cache;
                const char *name, *slash;
-               int len, dtype;
+               int len, dtype, ret;
 
                if (select_mask && !(ce->ce_flags & select_mask)) {
                        cache++;
@@ -967,7 +913,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
                                                       prefix, prefix_len + len,
                                                       prefix + prefix_len,
                                                       select_mask, clear_mask,
-                                                      el);
+                                                      el, defval);
 
                        /* clear_c_f_dir eats a whole dir already? */
                        if (processed) {
@@ -978,13 +924,16 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
                        prefix[prefix_len + len++] = '/';
                        cache += clear_ce_flags_1(cache, cache_end - cache,
                                                  prefix, prefix_len + len,
-                                                 select_mask, clear_mask, el);
+                                                 select_mask, clear_mask, el, defval);
                        continue;
                }
 
                /* Non-directory */
                dtype = ce_to_dtype(ce);
-               if (excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el) > 0)
+               ret = excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el);
+               if (ret < 0)
+                       ret = defval;
+               if (ret > 0)
                        ce->ce_flags &= ~clear_mask;
                cache++;
        }
@@ -999,7 +948,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,
        return clear_ce_flags_1(cache, nr,
                                prefix, 0,
                                select_mask, clear_mask,
-                               el);
+                               el, 0);
 }
 
 /*