@@ -220,6 +220,7 @@ static int collect_merge_info_callback(int n,
220220 size_t len ;
221221 char * fullpath ;
222222 unsigned filemask = mask & ~dirmask ;
223+ unsigned match_mask = 0 ; /* will be updated below */
223224 unsigned mbase_null = !(mask & 1 );
224225 unsigned side1_null = !(mask & 2 );
225226 unsigned side2_null = !(mask & 4 );
@@ -233,6 +234,22 @@ static int collect_merge_info_callback(int n,
233234 names [1 ].mode == names [2 ].mode &&
234235 oideq (& names [1 ].oid , & names [2 ].oid ));
235236
237+ /*
238+ * Note: When a path is a file on one side of history and a directory
239+ * in another, we have a directory/file conflict. In such cases, if
240+ * the conflict doesn't resolve from renames and deletions, then we
241+ * always leave directories where they are and move files out of the
242+ * way. Thus, while struct conflict_info has a df_conflict field to
243+ * track such conflicts, we ignore that field for any directories at
244+ * a path and only pay attention to it for files at the given path.
245+ * The fact that we leave directories were they are also means that
246+ * we do not need to worry about getting additional df_conflict
247+ * information propagated from parent directories down to children
248+ * (unlike, say traverse_trees_recursive() in unpack-trees.c, which
249+ * sets a newinfo.df_conflicts field specifically to propagate it).
250+ */
251+ unsigned df_conflict = (filemask != 0 ) && (dirmask != 0 );
252+
236253 /* n = 3 is a fundamental assumption. */
237254 if (n != 3 )
238255 BUG ("Called collect_merge_info_callback wrong" );
@@ -248,6 +265,14 @@ static int collect_merge_info_callback(int n,
248265 assert (!mbase_null || !side1_null || !side2_null );
249266 assert (mask > 0 && mask < 8 );
250267
268+ /* Determine match_mask */
269+ if (side1_matches_mbase )
270+ match_mask = (side2_matches_mbase ? 7 : 3 );
271+ else if (side2_matches_mbase )
272+ match_mask = 5 ;
273+ else if (sides_match )
274+ match_mask = 6 ;
275+
251276 /*
252277 * Get the name of the relevant filepath, which we'll pass to
253278 * setup_path_info() for tracking.
@@ -266,6 +291,8 @@ static int collect_merge_info_callback(int n,
266291 * so we can resolve later in process_entries.
267292 */
268293 ci = xcalloc (1 , sizeof (struct conflict_info ));
294+ ci -> df_conflict = df_conflict ;
295+ ci -> match_mask = match_mask ;
269296 strmap_put (& opti -> paths , fullpath , ci );
270297
271298 /* If dirmask, recurse into subdirectories */
@@ -282,6 +309,15 @@ static int collect_merge_info_callback(int n,
282309 newinfo .name = p -> path ;
283310 newinfo .namelen = p -> pathlen ;
284311 newinfo .pathlen = st_add3 (newinfo .pathlen , p -> pathlen , 1 );
312+ /*
313+ * If this directory we are about to recurse into cared about
314+ * its parent directory (the current directory) having a D/F
315+ * conflict, then we'd propagate the masks in this way:
316+ * newinfo.df_conflicts |= (mask & ~dirmask);
317+ * But we don't worry about propagating D/F conflicts. (See
318+ * comment near setting of local df_conflict variable near
319+ * the beginning of this function).
320+ */
285321
286322 for (i = MERGE_BASE ; i <= MERGE_SIDE2 ; i ++ ) {
287323 if (i == 1 && side1_matches_mbase )
0 commit comments