]> git.ipfire.org Git - thirdparty/git.git/commitdiff
merge-ort: defer recursing into directories when merge base is matched
authorElijah Newren <newren@gmail.com>
Fri, 16 Jul 2021 05:22:35 +0000 (05:22 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 20 Jul 2021 21:47:39 +0000 (14:47 -0700)
When one side of history matches the merge base (including when the
merge base has no entry for the given directory), have
collect_merge_info_callback() defer recursing into the directory.  To
ensure those entries are eventually handled, add a call to
handled_deferred_entries() in collect_merge_info() after
traverse_trees() returns.

Note that the condition in collect_merge_info_callback() may look more
complicated than necessary at first glance;
renames->trivial_merges_okay[side] is always true until
handle_deferred_entries() is called, and possible_trivial_merges[side]
is always empty right now (and in the future won't be filled until
handle_deferred_entries() is called).  However, when
handle_deferred_entries() calls traverse_trees() for the relevant
deferred directories, those traverse_trees() calls will once again end
up in collect_merge_info_callback() for all the entries under those
subdirectories.  The extra conditions are there for such deferred cases
and will be used more as we do more with those variables.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
merge-ort.c

index 6f817958460078afad4626413d1cc3e141ebbab7..7e624fcd366b0c38ce345635d87cfa24bc9a7435 100644 (file)
@@ -1147,8 +1147,36 @@ static int collect_merge_info_callback(int n,
                struct tree_desc t[3];
                void *buf[3] = {NULL, NULL, NULL};
                const char *original_dir_name;
-               int i, ret;
+               int i, ret, side;
 
+               /*
+                * Check for whether we can avoid recursing due to one side
+                * matching the merge base.  The side that does NOT match is
+                * the one that might have a rename destination we need.
+                */
+               assert(!side1_matches_mbase || !side2_matches_mbase);
+               side = side1_matches_mbase ? MERGE_SIDE2 :
+                       side2_matches_mbase ? MERGE_SIDE1 : MERGE_BASE;
+               if (filemask == 0 && (dirmask == 2 || dirmask == 4)) {
+                       /*
+                        * Also defer recursing into new directories; set up a
+                        * few variables to let us do so.
+                        */
+                       ci->match_mask = (7 - dirmask);
+                       side = dirmask / 2;
+               }
+               if (renames->dir_rename_mask != 0x07 &&
+                   side != MERGE_BASE &&
+                   renames->deferred[side].trivial_merges_okay &&
+                   !strset_contains(&renames->deferred[side].target_dirs,
+                                    pi.string)) {
+                       strintmap_set(&renames->deferred[side].possible_trivial_merges,
+                                     pi.string, renames->dir_rename_mask);
+                       renames->dir_rename_mask = prev_dir_rename_mask;
+                       return mask;
+               }
+
+               /* We need to recurse */
                ci->match_mask &= filemask;
                newinfo = *info;
                newinfo.prev = info;
@@ -1202,7 +1230,6 @@ static int collect_merge_info_callback(int n,
        return mask;
 }
 
-MAYBE_UNUSED
 static int handle_deferred_entries(struct merge_options *opt,
                                   struct traverse_info *info)
 {
@@ -1291,6 +1318,8 @@ static int collect_merge_info(struct merge_options *opt,
 
        trace2_region_enter("merge", "traverse_trees", opt->repo);
        ret = traverse_trees(NULL, 3, t, &info);
+       if (ret == 0)
+               ret = handle_deferred_entries(opt, &info);
        trace2_region_leave("merge", "traverse_trees", opt->repo);
 
        return ret;