Subject: Re: [PATCH 22/48] merge-recursive: Fix sorting order and directory change assumptions

From: Johannes Sixt <[email-masked]>
Date: Wed, 13 Jul 2011 09:24:30 +0200

Am 7/12/2011 9:27, schrieb Johannes Sixt:
> Am 7/11/2011 9:04, schrieb Johannes Sixt:
>> A heads-up: This test case fails here on Windows. The messages produced are:
> 
>> As you can see, "Removing letters..." is missing on Windows, and the file
>> 'letters' is indeed left in the working tree. Any quick ideas where to
>> begin debugging this?
> 
> And the reason for this is that the qsort call in record_df_conflict_files
> assumes that qsort is a stable sort; but this is not guaranteed. In
> particular, the entry "letters" can be moved after "letters/file", which
> is not expected by the loop that follows the qsort.

Perhaps something like below. It passes the tests that previously failed.

--- >8 ---
From: Johannes Sixt <[email-masked]>
Subject: [PATCH] fixup! Do not assume that qsort is stable

Signed-off-by: Johannes Sixt <[email-masked]>
---
 merge-recursive.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/merge-recursive.c b/merge-recursive.c
index 88167c3..81fac5f 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -361,6 +361,8 @@ static int string_list_df_name_compare(const void *a, const void *b)
 {
 	const struct string_list_item *one = a;
 	const struct string_list_item *two = b;
+	int onelen = strlen(one->string);
+	int twolen = strlen(two->string);
 	/*
 	 * Here we only care that entries for D/F conflicts are
 	 * adjacent, in particular with the file of the D/F conflict
@@ -373,8 +375,15 @@ static int string_list_df_name_compare(const void *a, const void *b)
 	 * since in other cases any changes in their order due to
 	 * sorting cause no problems for us.
 	 */
-	return df_name_compare(one->string, strlen(one->string), S_IFDIR,
-			       two->string, strlen(two->string), S_IFDIR);
+	int cmp = df_name_compare(one->string, onelen, S_IFDIR,
+				  two->string, 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;
 }
 
 static void record_df_conflict_files(struct merge_options *o,
-- 
1.7.6.1317.gd8c5a.dirty