From: Elijah Newren <newren@gmail.com>
To: git@vger.kernel.org
Cc: Elijah Newren <newren@gmail.com>
Subject: [WIP PATCH 05/10] merge-recursive: Fix sorting order and directory change assumptions
Date: Mon, 21 Mar 2011 12:30:59 -0600 [thread overview]
Message-ID: <1300732264-9638-6-git-send-email-newren@gmail.com> (raw)
In-Reply-To: <1300732264-9638-1-git-send-email-newren@gmail.com>
As pointed out in the review of my earlier series, we cannot assume that
directory/file conflicts will appear in sorted order; for example,
'letters.txt' comes between 'letters' and 'letters/file'.
Also, we should not make changes to the working directory when merging
merge-bases, so removing files to make room for directories of d/f
conflicts should be skipped in such cases.
(These changes were made last September/October, but were mixed in with
an update of my series that I never got around to resubmitting. Now that
the original series was accepted, I split these changes back out.)
---
merge-recursive.c | 38 +++++++++++++++++++++++++++++++++-----
t/t6020-merge-df.sh | 26 ++++++++++++++++++--------
2 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 1da385c..7a04ca7 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -344,6 +344,28 @@ static struct string_list *get_unmerged(void)
return unmerged;
}
+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;
+ /*
+ * 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.
+ */
+ return df_name_compare(one->string, strlen(one->string), S_IFDIR,
+ two->string, strlen(two->string), S_IFDIR);
+}
+
+
+
static void make_room_for_directories_of_df_conflicts(struct merge_options *o,
struct string_list *entries)
{
@@ -356,17 +378,23 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o,
* otherwise, if the file is not supposed to be removed by the
* merge, the contents of the file will be placed in another
* unique filename.
- *
- * NOTE: This function relies on the fact that entries for a
- * D/F conflict will appear adjacent in the index, with the
- * entries for the file appearing before entries for paths
- * below the corresponding directory.
*/
const char *last_file = NULL;
int last_len = 0;
struct stage_data *last_e;
int i;
+ /*
+ * If we're merging merge-bases, we don't want to bother with
+ * any working directory changes.
+ */
+ if (o->call_depth)
+ return;
+
+ /* Ensure D/F conflicts are adjacent in the entries list. */
+ qsort(entries->items, entries->nr, sizeof(*entries->items),
+ string_list_df_name_compare);
+
for (i = 0; i < entries->nr; i++) {
const char *path = entries->items[i].string;
int len = strlen(path);
diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh
index eec8f4e..27c3d73 100755
--- a/t/t6020-merge-df.sh
+++ b/t/t6020-merge-df.sh
@@ -59,15 +59,19 @@ test_expect_success 'setup modify/delete + directory/file conflict' '
git add letters &&
git commit -m initial &&
+ # Throw in letters.txt for sorting order fun
+ # ("letters.txt" sorts between "letters" and "letters/file")
echo i >>letters &&
- git add letters &&
+ echo "version 2" >letters.txt &&
+ git add letters letters.txt &&
git commit -m modified &&
git checkout -b delete HEAD^ &&
git rm letters &&
mkdir letters &&
>letters/file &&
- git add letters &&
+ echo "version 1" >letters.txt &&
+ git add letters letters.txt &&
git commit -m deleted
'
@@ -75,25 +79,31 @@ test_expect_success 'modify/delete + directory/file conflict' '
git checkout delete^0 &&
test_must_fail git merge modify &&
- test 3 = $(git ls-files -s | wc -l) &&
- test 2 = $(git ls-files -u | wc -l) &&
- test 1 = $(git ls-files -o | wc -l) &&
+ test 5 -eq $(git ls-files -s | wc -l) &&
+ test 4 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
test -f letters/file &&
+ test -f letters.txt &&
test -f letters~modify
'
test_expect_success 'modify/delete + directory/file conflict; other way' '
+ # Yes, we really need the double reset since "letters" appears as
+ # both a file and a directory.
+ git reset --hard &&
git reset --hard &&
git clean -f &&
git checkout modify^0 &&
+
test_must_fail git merge delete &&
- test 3 = $(git ls-files -s | wc -l) &&
- test 2 = $(git ls-files -u | wc -l) &&
- test 1 = $(git ls-files -o | wc -l) &&
+ test 5 -eq $(git ls-files -s | wc -l) &&
+ test 4 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
test -f letters/file &&
+ test -f letters.txt &&
test -f letters~HEAD
'
--
1.7.4
next prev parent reply other threads:[~2011-03-21 18:24 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
2011-03-21 18:30 ` [WIP PATCH 01/10] merge-recursive: Remove redundant check for removing rename source Elijah Newren
2011-03-21 18:30 ` [WIP PATCH 02/10] Reminder to fix o->call_depth handling in conflict_rename_rename_1to2 Elijah Newren
2011-03-21 18:30 ` [WIP PATCH 03/10] A bunch of fixes and FIXMEs Elijah Newren
2011-03-21 18:30 ` [WIP PATCH 04/10] Correct a comment Elijah Newren
2011-03-21 18:30 ` Elijah Newren [this message]
2011-03-21 18:31 ` [WIP PATCH 06/10] Add a comment pointing out a bug Elijah Newren
2011-03-21 18:31 ` [WIP PATCH 07/10] Good testcases Elijah Newren
2011-03-21 18:31 ` [WIP PATCH 08/10] More test scripts Elijah Newren
2011-03-21 18:31 ` [WIP PATCH 09/10] Tests and fixes associated with rename/rename conflicts Elijah Newren
2011-03-21 18:31 ` [WIP PATCH 10/10] Add new testcase (temp14) showing how undetected renames can cause or spuriously avoid merge conflicts Elijah Newren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1300732264-9638-6-git-send-email-newren@gmail.com \
--to=newren@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.