@@ -343,6 +343,13 @@ static void path_msg(struct merge_options *opt,
343343 strbuf_addch (sb , '\n' );
344344}
345345
346+ static char * unique_path (struct strmap * existing_paths ,
347+ const char * path ,
348+ const char * branch )
349+ {
350+ die ("Not yet implemented." );
351+ }
352+
346353/*** Function Grouping: functions related to collect_merge_info() ***/
347354
348355static void setup_path_info (struct merge_options * opt ,
@@ -962,6 +969,8 @@ static void process_entry(struct merge_options *opt,
962969 struct conflict_info * ci ,
963970 struct directory_versions * dir_metadata )
964971{
972+ int df_file_index = 0 ;
973+
965974 VERIFY_CI (ci );
966975 assert (ci -> filemask >= 0 && ci -> filemask <= 7 );
967976 /* ci->match_mask == 7 was handled in collect_merge_info_callback() */
@@ -998,13 +1007,86 @@ static void process_entry(struct merge_options *opt,
9981007 oidcpy (& ci -> stages [i ].oid , & null_oid );
9991008 }
10001009 } else if (ci -> df_conflict && ci -> merged .result .mode != 0 ) {
1001- die ("Not yet implemented." );
1010+ /*
1011+ * This started out as a D/F conflict, and the entries in
1012+ * the competing directory were not removed by the merge as
1013+ * evidenced by write_completed_directory() writing a value
1014+ * to ci->merged.result.mode.
1015+ */
1016+ struct conflict_info * new_ci ;
1017+ const char * branch ;
1018+ const char * old_path = path ;
1019+ int i ;
1020+
1021+ assert (ci -> merged .result .mode == S_IFDIR );
1022+
1023+ /*
1024+ * If filemask is 1, we can just ignore the file as having
1025+ * been deleted on both sides. We do not want to overwrite
1026+ * ci->merged.result, since it stores the tree for all the
1027+ * files under it.
1028+ */
1029+ if (ci -> filemask == 1 ) {
1030+ ci -> filemask = 0 ;
1031+ return ;
1032+ }
1033+
1034+ /*
1035+ * This file still exists on at least one side, and we want
1036+ * the directory to remain here, so we need to move this
1037+ * path to some new location.
1038+ */
1039+ new_ci = xcalloc (1 , sizeof (* new_ci ));
1040+ /* We don't really want new_ci->merged.result copied, but it'll
1041+ * be overwritten below so it doesn't matter. We also don't
1042+ * want any directory mode/oid values copied, but we'll zero
1043+ * those out immediately. We do want the rest of ci copied.
1044+ */
1045+ memcpy (new_ci , ci , sizeof (* ci ));
1046+ new_ci -> match_mask = (new_ci -> match_mask & ~new_ci -> dirmask );
1047+ new_ci -> dirmask = 0 ;
1048+ for (i = MERGE_BASE ; i <= MERGE_SIDE2 ; i ++ ) {
1049+ if (new_ci -> filemask & (1 << i ))
1050+ continue ;
1051+ /* zero out any entries related to directories */
1052+ new_ci -> stages [i ].mode = 0 ;
1053+ oidcpy (& new_ci -> stages [i ].oid , & null_oid );
1054+ }
1055+
1056+ /*
1057+ * Find out which side this file came from; note that we
1058+ * cannot just use ci->filemask, because renames could cause
1059+ * the filemask to go back to 7. So we use dirmask, then
1060+ * pick the opposite side's index.
1061+ */
1062+ df_file_index = (ci -> dirmask & (1 << 1 )) ? 2 : 1 ;
1063+ branch = (df_file_index == 1 ) ? opt -> branch1 : opt -> branch2 ;
1064+ path = unique_path (& opt -> priv -> paths , path , branch );
1065+ strmap_put (& opt -> priv -> paths , path , new_ci );
1066+
1067+ path_msg (opt , path , 0 ,
1068+ _ ("CONFLICT (file/directory): directory in the way "
1069+ "of %s from %s; moving it to %s instead." ),
1070+ old_path , branch , path );
1071+
1072+ /*
1073+ * Zero out the filemask for the old ci. At this point, ci
1074+ * was just an entry for a directory, so we don't need to
1075+ * do anything more with it.
1076+ */
1077+ ci -> filemask = 0 ;
1078+
1079+ /*
1080+ * Now note that we're working on the new entry (path was
1081+ * updated above.
1082+ */
1083+ ci = new_ci ;
10021084 }
10031085
10041086 /*
10051087 * NOTE: Below there is a long switch-like if-elseif-elseif... block
10061088 * which the code goes through even for the df_conflict cases
1007- * above. Well, it will once we don't die-not-implemented above.
1089+ * above.
10081090 */
10091091 if (ci -> match_mask ) {
10101092 ci -> merged .clean = 1 ;
0 commit comments