Skip to content

Commit 8adffaa

Browse files
newrengitster
authored andcommitted
merge-ort: have process_entries operate in a defined order
We want to handle paths below a directory before needing to handle the directory itself. Also, we want to handle the directory immediately after the paths below it, so we can't use simple lexicographic ordering from strcmp (which would insert foo.txt between foo and foo/file.c). Copy string_list_df_name_compare() from merge-recursive.c, and set up a string list of paths sorted by that function so that we can iterate in the desired order. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6a02dd9 commit 8adffaa

File tree

1 file changed

+50
-3
lines changed

1 file changed

+50
-3
lines changed

merge-ort.c

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,33 @@ static int detect_and_process_renames(struct merge_options *opt,
492492
return clean;
493493
}
494494

495+
static int string_list_df_name_compare(const char *one, const char *two)
496+
{
497+
int onelen = strlen(one);
498+
int twolen = strlen(two);
499+
/*
500+
* Here we only care that entries for D/F conflicts are
501+
* adjacent, in particular with the file of the D/F conflict
502+
* appearing before files below the corresponding directory.
503+
* The order of the rest of the list is irrelevant for us.
504+
*
505+
* To achieve this, we sort with df_name_compare and provide
506+
* the mode S_IFDIR so that D/F conflicts will sort correctly.
507+
* We use the mode S_IFDIR for everything else for simplicity,
508+
* since in other cases any changes in their order due to
509+
* sorting cause no problems for us.
510+
*/
511+
int cmp = df_name_compare(one, onelen, S_IFDIR,
512+
two, twolen, S_IFDIR);
513+
/*
514+
* Now that 'foo' and 'foo/bar' compare equal, we have to make sure
515+
* that 'foo' comes before 'foo/bar'.
516+
*/
517+
if (cmp)
518+
return cmp;
519+
return onelen - twolen;
520+
}
521+
495522
/* Per entry merge function */
496523
static void process_entry(struct merge_options *opt,
497524
const char *path,
@@ -578,24 +605,44 @@ static void process_entries(struct merge_options *opt,
578605
{
579606
struct hashmap_iter iter;
580607
struct strmap_entry *e;
608+
struct string_list plist = STRING_LIST_INIT_NODUP;
609+
struct string_list_item *entry;
581610

582611
if (strmap_empty(&opt->priv->paths)) {
583612
oidcpy(result_oid, opt->repo->hash_algo->empty_tree);
584613
return;
585614
}
586615

616+
/* Hack to pre-allocate plist to the desired size */
617+
ALLOC_GROW(plist.items, strmap_get_size(&opt->priv->paths), plist.alloc);
618+
619+
/* Put every entry from paths into plist, then sort */
587620
strmap_for_each_entry(&opt->priv->paths, &iter, e) {
621+
string_list_append(&plist, e->key)->util = e->value;
622+
}
623+
plist.cmp = string_list_df_name_compare;
624+
string_list_sort(&plist);
625+
626+
/*
627+
* Iterate over the items in reverse order, so we can handle paths
628+
* below a directory before needing to handle the directory itself.
629+
*/
630+
for (entry = &plist.items[plist.nr-1]; entry >= plist.items; --entry) {
631+
char *path = entry->string;
588632
/*
589633
* NOTE: mi may actually be a pointer to a conflict_info, but
590634
* we have to check mi->clean first to see if it's safe to
591635
* reassign to such a pointer type.
592636
*/
593-
struct merged_info *mi = e->value;
637+
struct merged_info *mi = entry->util;
594638

595-
if (!mi->clean)
596-
process_entry(opt, e->key, e->value);
639+
if (!mi->clean) {
640+
struct conflict_info *ci = (struct conflict_info *)mi;
641+
process_entry(opt, path, ci);
642+
}
597643
}
598644

645+
string_list_clear(&plist, 0);
599646
die("Tree creation not yet implemented");
600647
}
601648

0 commit comments

Comments
 (0)