@@ -465,6 +465,33 @@ static int detect_and_process_renames(struct merge_options *opt,
return clean;
}
+static int string_list_df_name_compare(const char *one, const char *two)
+{
+ int onelen = strlen(one);
+ int twolen = strlen(two);
+ /*
+ * Here we only care that entries for D/F conflicts are
+ * adjacent, in particular with the file of the D/F conflict
+ * appearing before files below the corresponding directory.
+ * The order of the rest of the list is irrelevant for us.
+ *
+ * To achieve this, we sort with df_name_compare and provide
+ * the mode S_IFDIR so that D/F conflicts will sort correctly.
+ * We use the mode S_IFDIR for everything else for simplicity,
+ * since in other cases any changes in their order due to
+ * sorting cause no problems for us.
+ */
+ int cmp = df_name_compare(one, onelen, S_IFDIR,
+ two, twolen, S_IFDIR);
+ /*
+ * Now that 'foo' and 'foo/bar' compare equal, we have to make sure
+ * that 'foo' comes before 'foo/bar'.
+ */
+ if (cmp)
+ return cmp;
+ return onelen - twolen;
+}
+
/* Per entry merge function */
static void process_entry(struct merge_options *opt,
const char *path,
@@ -551,24 +578,44 @@ static void process_entries(struct merge_options *opt,
{
struct hashmap_iter iter;
struct strmap_entry *e;
+ struct string_list plist = STRING_LIST_INIT_NODUP;
+ struct string_list_item *entry;
if (strmap_empty(&opt->priv->paths)) {
oidcpy(result_oid, opt->repo->hash_algo->empty_tree);
return;
}
+ /* Hack to pre-allocate plist to the desired size */
+ ALLOC_GROW(plist.items, strmap_get_size(&opt->priv->paths), plist.alloc);
+
+ /* Put every entry from paths into plist, then sort */
strmap_for_each_entry(&opt->priv->paths, &iter, e) {
+ string_list_append(&plist, e->key)->util = e->value;
+ }
+ plist.cmp = string_list_df_name_compare;
+ string_list_sort(&plist);
+
+ /*
+ * Iterate over the items in reverse order, so we can handle paths
+ * below a directory before needing to handle the directory itself.
+ */
+ for (entry = &plist.items[plist.nr-1]; entry >= plist.items; --entry) {
+ char *path = entry->string;
/*
* NOTE: mi may actually be a pointer to a conflict_info, but
* we have to check mi->clean first to see if it's safe to
* reassign to such a pointer type.
*/
- struct merged_info *mi = e->value;
+ struct merged_info *mi = entry->util;
- if (!mi->clean)
- process_entry(opt, e->key, e->value);
+ if (!mi->clean) {
+ struct conflict_info *ci = (struct conflict_info *)mi;
+ process_entry(opt, path, ci);
+ }
}
+ string_list_clear(&plist, 0);
die("Tree creation not yet implemented");
}