@@ -220,6 +220,7 @@ static int collect_merge_info_callback(int n,
220
220
size_t len ;
221
221
char * fullpath ;
222
222
unsigned filemask = mask & ~dirmask ;
223
+ unsigned match_mask = 0 ; /* will be updated below */
223
224
unsigned mbase_null = !(mask & 1 );
224
225
unsigned side1_null = !(mask & 2 );
225
226
unsigned side2_null = !(mask & 4 );
@@ -233,6 +234,22 @@ static int collect_merge_info_callback(int n,
233
234
names [1 ].mode == names [2 ].mode &&
234
235
oideq (& names [1 ].oid , & names [2 ].oid ));
235
236
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
+
236
253
/* n = 3 is a fundamental assumption. */
237
254
if (n != 3 )
238
255
BUG ("Called collect_merge_info_callback wrong" );
@@ -248,6 +265,14 @@ static int collect_merge_info_callback(int n,
248
265
assert (!mbase_null || !side1_null || !side2_null );
249
266
assert (mask > 0 && mask < 8 );
250
267
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
+
251
276
/*
252
277
* Get the name of the relevant filepath, which we'll pass to
253
278
* setup_path_info() for tracking.
@@ -266,6 +291,8 @@ static int collect_merge_info_callback(int n,
266
291
* so we can resolve later in process_entries.
267
292
*/
268
293
ci = xcalloc (1 , sizeof (struct conflict_info ));
294
+ ci -> df_conflict = df_conflict ;
295
+ ci -> match_mask = match_mask ;
269
296
strmap_put (& opti -> paths , fullpath , ci );
270
297
271
298
/* If dirmask, recurse into subdirectories */
@@ -282,6 +309,15 @@ static int collect_merge_info_callback(int n,
282
309
newinfo .name = p -> path ;
283
310
newinfo .namelen = p -> pathlen ;
284
311
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
+ */
285
321
286
322
for (i = MERGE_BASE ; i <= MERGE_SIDE2 ; i ++ ) {
287
323
if (i == 1 && side1_matches_mbase )
0 commit comments