* [WIP PATCH 01/10] merge-recursive: Remove redundant check for removing rename source
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
@ 2011-03-21 18:30 ` 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
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:30 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
If a file is renamed on the side of history being merged into head, the
filename serving as the source of that rename needs to be removed from the
working directory. (This statement is about a real merge rather than a
merge of merge bases to come up with a virtual ancestor; in the latter
case, no working directory changes of any type should be made).
The path to getting the above statement implemented in merge-recursive took
several steps. The relevant bits of code may be instructive to keep in
mind for the explanation, especially since an English-only description
involves double negatives that are hard to follow. These bits of code are:
int remove_file(..., const char *path, int no_wd)
{
...
int update_working_directory = !o->call_depth && !no_wd;
and
remove_file(o, 1, ren1_src, <expression>);
Where the choice for <expression> has morphed over time:
65ac6e9 (merge-recursive: adjust to loosened "working file clobbered"
check 2006-10-27), introduced the "no_wd" parameter to remove_file() and
used "1" for <expression>. This meant ren1_src was never deleted, leaving
it around in the working copy.
In 8371234 (Remove uncontested renamed files during merge. 2006-12-13),
<expression> was changed to "index_only" (where index_only ==
!!o->call_depth; see b7fa51da). This was equivalent to using "0" for
<expression> (due to the early logic in remove_file), and is orthogonal to
the condition we actually want to check at this point; it resulted in the
source file being removed except when index_only was false. This was
problematic because the file could have been renamed on the side of history
including head, in which case ren1_src could correspond to an untracked
file that should not be deleted.
In 183d797 (Keep untracked files not involved in a merge. 2007-02-04),
<expression> was changed to "index_only || stage == 3". While this gives
correct behavior, the "index_only ||" portion of <expression> is
unnecessary and makes the code slightly harder to follow.
There were also two further changes to this expression, though without
any change in behavior. First in b7fa51d (merge-recursive: get rid of the
index_only global variable 2008-09-02), it was changed to "o->call_depth
|| stage == 3". (index_only == !!o->call_depth). Earlier in this series
(merge-recursive: Small code clarification -- variable name and comments),
this was changed to "o->call_depth || renamed_stage == 2" (where stage
was renamed to other_stage and renamed_stage == other_stage ^ 1).
So we ended with <expression> being "o->call_depth || renamed_stage == 2".
But the "o->call_depth ||" piece was unnecessary. Remove it.
---
merge-recursive.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 42d52cb..6dc74dc 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1055,7 +1055,7 @@ static int process_renames(struct merge_options *o,
int renamed_stage = a_renames == renames1 ? 2 : 3;
int other_stage = a_renames == renames1 ? 3 : 2;
- remove_file(o, 1, ren1_src, o->call_depth || renamed_stage == 2);
+ remove_file(o, 1, ren1_src, renamed_stage == 2);
hashcpy(src_other.sha1, ren1->src_entry->stages[other_stage].sha);
src_other.mode = ren1->src_entry->stages[other_stage].mode;
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 02/10] Reminder to fix o->call_depth handling in conflict_rename_rename_1to2
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 ` Elijah Newren
2011-03-21 18:30 ` [WIP PATCH 03/10] A bunch of fixes and FIXMEs Elijah Newren
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:30 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
---
merge-recursive.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 6dc74dc..8d28a54 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -908,6 +908,10 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
ren2_dst, branch1, dst_name2);
}
if (o->call_depth) {
+ /*
+ * FIXME: This is bogus. dst_nameX are not in cache in
+ * case of D/F conflict.
+ */
remove_file_from_cache(dst_name1);
remove_file_from_cache(dst_name2);
/*
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 03/10] A bunch of fixes and FIXMEs
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 ` Elijah Newren
2011-03-21 18:30 ` [WIP PATCH 04/10] Correct a comment Elijah Newren
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:30 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
---
merge-recursive.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 8d28a54..fde9f9e 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -910,7 +910,8 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
if (o->call_depth) {
/*
* FIXME: This is bogus. dst_nameX are not in cache in
- * case of D/F conflict.
+ * case of D/F conflict. renX_dst are. Simple typo, or
+ * something worse?
*/
remove_file_from_cache(dst_name1);
remove_file_from_cache(dst_name2);
@@ -1290,10 +1291,12 @@ static int merge_content(struct merge_options *o,
const char *new_path;
update_file_flags(o, mfi.sha, mfi.mode, path,
o->call_depth || mfi.clean, 0);
- new_path = unique_path(o, path, df_rename_conflict_branch);
mfi.clean = 0;
- output(o, 1, "Adding as %s instead", new_path);
- update_file_flags(o, mfi.sha, mfi.mode, new_path, 0, 1);
+ if (!o->call_depth) {
+ new_path = unique_path(o, path, df_rename_conflict_branch);
+ output(o, 1, "Adding as %s instead", new_path);
+ update_file(o, mfi.clean, mfi.sha, mfi.mode, new_path);
+ }
} else {
update_file(o, mfi.clean, mfi.sha, mfi.mode, path);
}
@@ -1433,6 +1436,11 @@ static int process_df_entry(struct merge_options *o,
src, conflict_info->pair2->two->path, conflict_info->branch2,
o->call_depth ? " (left unresolved)" : "");
if (o->call_depth) {
+ /*
+ * FIXME: Why remove file from cache, and
+ * then immediately readd it? Why not just
+ * overwrite using update_file only?
+ */
remove_file_from_cache(src);
update_file(o, 0, conflict_info->pair1->one->sha1,
conflict_info->pair1->one->mode, src);
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 04/10] Correct a comment
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
` (2 preceding siblings ...)
2011-03-21 18:30 ` [WIP PATCH 03/10] A bunch of fixes and FIXMEs Elijah Newren
@ 2011-03-21 18:30 ` Elijah Newren
2011-03-21 18:30 ` [WIP PATCH 05/10] merge-recursive: Fix sorting order and directory change assumptions Elijah Newren
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:30 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
---
merge-recursive.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index fde9f9e..1da385c 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1464,7 +1464,7 @@ static int process_df_entry(struct merge_options *o,
handle_delete_modify(o, path, new_path,
a_sha, a_mode, b_sha, b_mode);
} else if (!o_sha && !!a_sha != !!b_sha) {
- /* directory -> (directory, file) */
+ /* directory -> (directory, file) or <nothing> -> (directory, file) */
const char *add_branch;
const char *other_branch;
unsigned mode;
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 05/10] merge-recursive: Fix sorting order and directory change assumptions
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
` (3 preceding siblings ...)
2011-03-21 18:30 ` [WIP PATCH 04/10] Correct a comment Elijah Newren
@ 2011-03-21 18:30 ` Elijah Newren
2011-03-21 18:31 ` [WIP PATCH 06/10] Add a comment pointing out a bug Elijah Newren
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:30 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
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
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 06/10] Add a comment pointing out a bug
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
` (4 preceding siblings ...)
2011-03-21 18:30 ` [WIP PATCH 05/10] merge-recursive: Fix sorting order and directory change assumptions Elijah Newren
@ 2011-03-21 18:31 ` Elijah Newren
2011-03-21 18:31 ` [WIP PATCH 07/10] Good testcases Elijah Newren
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:31 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
---
merge-recursive.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 7a04ca7..544c504 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1064,7 +1064,7 @@ static int process_renames(struct merge_options *o,
ren1->dst_entry,
ren2->dst_entry);
} else {
- remove_file(o, 1, ren1_src, 1);
+ remove_file(o, 1, ren1_src, 1); // BAD
update_stages_and_entry(ren1_dst,
ren1->dst_entry,
ren1->pair->one,
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 07/10] Good testcases
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
` (5 preceding siblings ...)
2011-03-21 18:31 ` [WIP PATCH 06/10] Add a comment pointing out a bug Elijah Newren
@ 2011-03-21 18:31 ` Elijah Newren
2011-03-21 18:31 ` [WIP PATCH 08/10] More test scripts Elijah Newren
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:31 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
---
t/temp1.sh | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
t/temp2.sh | 86 +++++++++++++++++++++++++++++++++++
t/temp3.sh | 72 +++++++++++++++++++++++++++++
t/temp4.sh | 96 +++++++++++++++++++++++++++++++++++++++
t/temp5.sh | 35 ++++++++++++++
t/temp6.sh | 55 ++++++++++++++++++++++
t/temp7.sh | 34 ++++++++++++++
t/temp8.sh | 37 +++++++++++++++
8 files changed, 561 insertions(+), 0 deletions(-)
create mode 100644 t/temp1.sh
create mode 100755 t/temp2.sh
create mode 100755 t/temp3.sh
create mode 100755 t/temp4.sh
create mode 100755 t/temp5.sh
create mode 100755 t/temp6.sh
create mode 100755 t/temp7.sh
create mode 100755 t/temp8.sh
diff --git a/t/temp1.sh b/t/temp1.sh
new file mode 100644
index 0000000..d7075f5
--- /dev/null
+++ b/t/temp1.sh
@@ -0,0 +1,146 @@
+#!/bin/sh
+
+test_description='recursive merge corner cases: d/f conflict (via add/add) + criss-cross merge'
+
+. ./test-lib.sh
+
+#
+# Let's make it a bit more coplicated:
+# Commit A: Neither file 'a' nor directory 'a/' exist.
+# Commit B: Introduce 'a'
+# Commit C: Introduce 'a/file'
+# Two different later cases:
+# Commit D1: Merge B & C, keeping 'a' and deleting 'a/'
+# Commit E1: Merge B & C, deleting 'a' but keeping 'a/file'
+#
+# Commit D2: Merge B & C, keeping a modified 'a' and deleting 'a/'
+# Commit E2: Merge B & C, deleting 'a' but keeping a modified 'a/file'
+# Finally, someone goes to merge D1&E1 or D1&E2 or D2&E1. What happens?
+#
+# B D1 or D2
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E1 or E2
+#
+
+test_expect_success 'setup differently handled merges of directory/file conflict' '
+ >irrelevant-file &&
+ git add irrelevant-file &&
+ test_tick &&
+ git commit -m A &&
+
+ git branch B &&
+ git checkout -b C &&
+ mkdir a &&
+ echo 10 >a/file &&
+ git add a/file &&
+ test_tick &&
+ git commit -m C &&
+
+ git checkout B &&
+ echo 5 >a &&
+ git add a &&
+ test_tick &&
+ git commit -m B &&
+
+ git checkout B^0 &&
+ test_must_fail git merge C &&
+ git clean -f &&
+ rm -rf a/ &&
+ echo 5 >a &&
+ git add a &&
+ test_tick &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ git clean -f &&
+ echo 10 >a/file &&
+ git add a/file &&
+ git rm --cached a &&
+ test_tick &&
+ git commit -m E1 &&
+ git tag E1 &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ git clean -f &&
+ printf "10\n11\n" >a/file &&
+ git add a/file &&
+ git rm --cached a &&
+ test_tick &&
+ git commit -m E2 &&
+ git tag E2
+'
+
+test_expect_success 'git detects conflict and handles merge of D & E1 correctly' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+ git checkout D^0 &&
+
+ test_must_fail git merge -s recursive E1^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :2:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse :3:a/file) = $(git rev-parse C:a/file)
+'
+
+test_expect_failure 'git detects conflict and handles merge of E1 & D correctly' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+ git checkout E1^0 &&
+
+ test_must_fail git merge -s recursive D^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :3:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse :2:a/file) = $(git rev-parse C:a/file)
+'
+
+test_expect_success 'git detects conflict and handles merge of D & E2 correctly' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+ git checkout D^0 &&
+
+ test_must_fail git merge -s recursive E2^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :2:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse :3:a/file) = $(git rev-parse E1:a/file)
+ test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file)
+'
+
+test_expect_success 'git detects conflict and handles merge of E2 & D correctly' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+ git checkout E2^0 &&
+
+ test_must_fail git merge -s recursive D^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :3:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse :2:a/file) = $(git rev-parse E1:a/file)
+ test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file)
+'
+
+test_done
diff --git a/t/temp2.sh b/t/temp2.sh
new file mode 100755
index 0000000..46a8c93
--- /dev/null
+++ b/t/temp2.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+test_description='recursive merge corner case: content conflict + criss-cross merge'
+
+. ./test-lib.sh
+
+#
+# Let's make a really contrived but simple criss-cross merge case:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: file with contents 'A\n'
+# Commit B: file with contents 'B\n'
+# Commit C: file with contents 'C\n'
+# Commit D: file with contents 'D\n'
+# Commit E: file with contents:
+# <<<<<<< Temporary merge branch 1
+# C
+# =======
+# B
+# >>>>>>> Temporary merge branch 2
+#
+# Now, when we merge commits D & E, does git detect the conflict?
+
+test_expect_success 'setup differently handled merges of content conflict' '
+ echo A >file &&
+ git add file &&
+ test_tick &&
+ git commit -m A &&
+
+ git branch B &&
+ git checkout -b C &&
+ echo C >file &&
+ git add file &&
+ test_tick &&
+ git commit -m C &&
+
+ git checkout B &&
+ echo B >file &&
+ git add file &&
+ test_tick &&
+ git commit -m B &&
+
+ git checkout B^0 &&
+ test_must_fail git merge C &&
+ echo D >file &&
+ git add file &&
+ test_tick &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ cat <<EOF >file &&
+<<<<<<< Temporary merge branch 1
+C
+=======
+B
+>>>>>>> Temporary merge branch 2
+EOF
+ git add file &&
+ test_tick &&
+ git commit -m E &&
+ git tag E
+'
+
+test_expect_success 'git detects conflict merging D & E' '
+ git checkout D^0 &&
+
+ test_must_fail git merge -s recursive E^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test $(git rev-parse :2:file) = $(git rev-parse D:file) &&
+ test $(git rev-parse :3:file) = $(git rev-parse E:file)
+'
+
+test_done
diff --git a/t/temp3.sh b/t/temp3.sh
new file mode 100755
index 0000000..3f4ceb1
--- /dev/null
+++ b/t/temp3.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='recursive merge corner case: delete/modify + criss-cross merge'
+
+. ./test-lib.sh
+
+#
+# Standard setup:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: file with contents 'A\n'
+# Commit B: file with contents 'B\n'
+# Commit C: file not present
+# Commit D: file with contents 'B\n'
+# Commit E: file not present
+#
+# Now, when we merge commits D & E, does git detect the conflict?
+
+test_expect_success 'setup differently handled merges of content conflict' '
+ echo A >file &&
+ git add file &&
+ test_tick &&
+ git commit -m A &&
+
+ git branch B &&
+ git checkout -b C &&
+ git rm file &&
+ test_tick &&
+ git commit -m C &&
+
+ git checkout B &&
+ echo B >file &&
+ git add file &&
+ test_tick &&
+ git commit -m B &&
+
+ git checkout B^0 &&
+ test_must_fail git merge C &&
+ echo B >file &&
+ git add file &&
+ test_tick &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ git rm file &&
+ test_tick &&
+ git commit -m E &&
+ git tag E
+'
+
+test_expect_success 'git detects conflict merging D & E' '
+ git checkout D^0 &&
+
+ test_must_fail git merge -s recursive E^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+
+ test $(git rev-parse :1:file) = $(git rev-parse B:file) &&
+ test $(git rev-parse :2:file) = $(git rev-parse B:file)
+'
+
+test_done
diff --git a/t/temp4.sh b/t/temp4.sh
new file mode 100755
index 0000000..2014f5b
--- /dev/null
+++ b/t/temp4.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+test_description='recursive merge rename+content merge+D/F conflict'
+
+. ./test-lib.sh
+
+# Examples where rename/directory conflicts can cause changes to the file
+# not on the same side of history as the rename to be dropped.
+
+test_expect_success 'setup content merge + rename/directory conflict' '
+ printf "1\n2\n3\n4\n5\n6\n" >file &&
+ git add file &&
+ test_tick &&
+ git commit -m base &&
+ git tag base &&
+
+ git checkout -b right &&
+ echo 7 >>file &&
+ mkdir newfile &&
+ echo junk >newfile/realfile &&
+ git add file newfile/realfile &&
+ test_tick &&
+ git commit -m right &&
+
+ git checkout -b left-conflict base &&
+ echo 8 >>file &&
+ git add file &&
+ git mv file newfile &&
+ test_tick &&
+ git commit -m left &&
+
+ git checkout -b left-clean base &&
+ echo 0 >newfile &&
+ cat file >>newfile &&
+ git add newfile &&
+ git rm file &&
+ test_tick &&
+ git commit -m left
+'
+
+test_expect_success 'rename/directory conflict + clean content merge' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+
+ git checkout left-clean^0 &&
+
+ test_must_fail git merge -s recursive right^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 1 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ echo 0 >expect &&
+ git cat-file -p base:file >>expect &&
+ echo 7 >>expect &&
+ test_cmp expect newfile~HEAD &&
+
+ test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
+
+ test -f newfile/realfile &&
+ test -f newfile~HEAD
+'
+
+test_expect_success 'rename/directory conflict + content merge conflict' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+
+ git checkout left-conflict^0 &&
+
+ test_must_fail git merge -s recursive right^0 &&
+
+ test 4 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 1 -eq $(git ls-files -o | wc -l) &&
+
+ git cat-file -p left:newfile >left &&
+ git cat-file -p base:file >base &&
+ git cat-file -p right:file >right &&
+ test_must_fail git merge-file \
+ -L "HEAD:newfile" \
+ -L "" \
+ -L "right^0:file" \
+ left base right &&
+ test_cmp left newfile~HEAD &&
+
+ test $(git rev-parse :1:newfile) = $(git rev-parse base:file) &&
+ test $(git rev-parse :2:newfile) = $(git rev-parse left:newfile) &&
+ test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
+
+ test -f newfile/realfile &&
+ test -f newfile~HEAD
+'
+
+test_done
diff --git a/t/temp5.sh b/t/temp5.sh
new file mode 100755
index 0000000..bc50780
--- /dev/null
+++ b/t/temp5.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+test_description="Does git preserve Gollum's precious artifact?"
+
+. ./test-lib.sh
+
+test_expect_success 'setup abbreviated storyline' '
+ echo "A pretty inscription" >ring &&
+ git add ring &&
+ test_tick &&
+ git commit -m beginning &&
+
+ git branch people &&
+ git checkout -b rename-the-ring &&
+ git mv ring one-ring-to-rule-them-all &&
+ test_tick &&
+ git commit -m fullname &&
+
+ git checkout people &&
+ git rm ring &&
+ echo gollum >owner &&
+ git add owner &&
+ test_tick &&
+ git commit -m track-people-instead-of-objects &&
+ echo "Myyy PRECIOUSSS" >ring
+'
+
+test_expect_success 'Does git preserve the ring?' '
+ test_must_fail git merge -s recursive rename-the-ring &&
+
+ # Make sure git did not delete an untracked file
+ test -f ring
+'
+
+test_done
diff --git a/t/temp6.sh b/t/temp6.sh
new file mode 100755
index 0000000..da00050
--- /dev/null
+++ b/t/temp6.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+test_description='recursive merge rename+content merge+D/F conflict goes away'
+
+. ./test-lib.sh
+
+# Examples where rename/directory conflicts can cause changes to the file
+# not on the same side of history as the rename to be dropped.
+
+test_expect_success 'setup content merge + rename/directory conflict' '
+ mkdir sub &&
+ printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
+ git add sub/file &&
+ test_tick &&
+ git commit -m base &&
+ git tag base &&
+
+ git checkout -b right &&
+ echo 7 >>sub/file &&
+ git add sub/file &&
+ test_tick &&
+ git commit -m right &&
+
+ git checkout -b left base &&
+ echo 0 >newfile &&
+ cat sub/file >>newfile &&
+ git rm sub/file &&
+ mv newfile sub &&
+ git add sub &&
+ test_tick &&
+ git commit -m left
+'
+
+test_expect_success 'disappearing rename/directory conf.+clean content merge' '
+ git reset --hard &&
+ git reset --hard &&
+ git clean -fdqx &&
+
+ git checkout left^0 &&
+
+ git merge -s recursive right^0 &&
+
+ test 1 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ echo 0 >expect &&
+ git cat-file -p base:sub/file >>expect &&
+ echo 7 >>expect &&
+ test_cmp expect sub &&
+
+ test -f sub
+'
+
+test_done
diff --git a/t/temp7.sh b/t/temp7.sh
new file mode 100755
index 0000000..0cb5946
--- /dev/null
+++ b/t/temp7.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+test_description="File renamed identically on both sides + re-add source name"
+
+. ./test-lib.sh
+
+test_expect_success 'setup rename/rename/add resolvable conflict' '
+ >a &&
+ git add a &&
+ test_tick &&
+ git commit -m base &&
+ git tag base &&
+
+ git checkout -b one base &&
+ git mv a b &&
+ test_tick &&
+ git commit -m one &&
+
+ git checkout -b two base &&
+ git mv a b &&
+ echo important-info >a &&
+ test_tick &&
+ git commit -m two
+'
+
+test_expect_success 'merge include important info in new a' '
+ git checkout two^0 &&
+ git merge -s recursive one^0 &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l)
+'
+
+test_done
diff --git a/t/temp8.sh b/t/temp8.sh
new file mode 100755
index 0000000..0736639
--- /dev/null
+++ b/t/temp8.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+test_description="Rename/rename/add conflict"
+
+. ./test-lib.sh
+
+test_expect_success 'setup rename/rename (1to2) + add conflict' '
+ echo stuff >a &&
+ git add a &&
+ test_tick &&
+ git commit -m base &&
+ git tag base &&
+
+ git checkout -b one base &&
+ git mv a b &&
+ echo precious-data >c &&
+ git add c &&
+ test_tick &&
+ git commit -m one &&
+
+ git checkout -b two base &&
+ git mv a c &&
+ echo important-info >b &&
+ git add b &&
+ test_tick &&
+ git commit -m two
+'
+
+test_expect_success 'merge maintains important data from one:c and two:b' '
+ git checkout two^0 &&
+ test_must_fail git merge -s recursive one^0 &&
+
+ test 2 -eq $(git ls-files -u b | wc -l) &&
+ test 2 -eq $(git ls-files -u c | wc -l)
+'
+
+test_done
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 08/10] More test scripts
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
` (6 preceding siblings ...)
2011-03-21 18:31 ` [WIP PATCH 07/10] Good testcases Elijah Newren
@ 2011-03-21 18:31 ` 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
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:31 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
---
t/temp10.sh | 41 +++++++++++++++++++++++++++++++++
t/temp11.sh | 41 +++++++++++++++++++++++++++++++++
t/temp50.sh | 38 ++++++++++++++++++++++++++++++
t/temp9.sh | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 193 insertions(+), 0 deletions(-)
create mode 100755 t/temp10.sh
create mode 100755 t/temp11.sh
create mode 100755 t/temp50.sh
create mode 100755 t/temp9.sh
diff --git a/t/temp10.sh b/t/temp10.sh
new file mode 100755
index 0000000..100c74f
--- /dev/null
+++ b/t/temp10.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+test_description='merge+diff issue: rename/add vs. copy/modify'
+
+. ./test-lib.sh
+
+# Testcase setup:
+# Commit A: new file: a
+# Commit B: modify a slightly
+# Commit C: rename a->b, add completely different a
+#
+# We should be able to merge B & C cleanly
+
+test_expect_success 'setup modify + rename/add(source) merge' '
+ printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ echo 8 >>a &&
+ git add a &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a b &&
+ echo something completely different >a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_success 'no conflict merging B & C' '
+ git checkout B^0 &&
+
+ git merge -s recursive C^0 &&
+
+ test $(git rev-parse B:a) = $(git rev-parse b) &&
+ test $(git rev-parse C:a) = $(git rev-parse a)
+'
+
+test_done
diff --git a/t/temp11.sh b/t/temp11.sh
new file mode 100755
index 0000000..1d8fb9a
--- /dev/null
+++ b/t/temp11.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+test_description='merge+diff issue: rename/add vs. copy/modify, v2'
+
+. ./test-lib.sh
+
+# Testcase setup:
+# Commit A: new file: a
+# Commit B: rename a->b
+# Commit C: rename a->c, add completely different a
+#
+# Merging of B & C should NOT be clean; there's a rename/rename conflict
+
+test_expect_success 'setup modify + rename/add(source) merge' '
+ printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ echo something completely different >a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_success 'detect conflict merging B & C' '
+ git checkout B^0 &&
+
+ test_must_fail git merge -s recursive C^0 &&
+
+ test -f a &&
+ test -f b &&
+ test -f c
+'
+
+test_done
diff --git a/t/temp50.sh b/t/temp50.sh
new file mode 100755
index 0000000..5baebec
--- /dev/null
+++ b/t/temp50.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description="Rename/rename conflict doesn't leave files in place for user"
+
+. ./test-lib.sh
+
+test_expect_success 'setup rename/rename (1to2) conflict' '
+ echo stuff >a &&
+ git add a &&
+ test_tick &&
+ git commit -m base &&
+ git tag base &&
+
+ git checkout -b one base &&
+ git mv a b &&
+ test_tick &&
+ git commit -m one &&
+
+ git checkout -b two base &&
+ git mv a c &&
+ test_tick &&
+ git commit -m two
+'
+
+test_expect_success 'merge has correct working tree contents' '
+ git checkout two^0 &&
+
+ test_must_fail git merge -s recursive one^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 3 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test -f b &&
+ test -f c
+'
+
+test_done
diff --git a/t/temp9.sh b/t/temp9.sh
new file mode 100755
index 0000000..3936461
--- /dev/null
+++ b/t/temp9.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+test_description='recursive merge corner case: rename/rename + criss-cross merge + reintroduce file with name of rename source but different contents'
+
+. ./test-lib.sh
+
+#
+# Standard setup:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: new file: a
+# Commit B: rename a->b
+# Commit C: rename a->c, add different a
+# Commit D: merge B&C, keeping a&b&c, modifying a at the beginning
+# Commit E: merge B&C, keeping a&b&c, modifying a at the end
+#
+# Now, when we merge commits D & E, there should be no conflict...
+
+test_expect_success 'setup rename/rename + criss-cross + new file' '
+ printf "lots\nof\nwords\nand\ncontent\n" >a &&
+ git add a &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a b &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv a c &&
+ printf "2\n3\n4\n5\n6\n7\n" >a &&
+ git add a &&
+ git commit -m C &&
+
+ git checkout B^0 &&
+ exit 1
+ test_must_fail git merge C &&
+ mv a old_a &&
+ echo 1 >a &&
+ cat old_a >>a &&
+ rm old_a &&
+ git add -u &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ echo 6 >> a &&
+ git add -u &&
+ git commit -m E &&
+ git tag E
+'
+
+test_expect_success 'no conflict merging D & E' '
+ git checkout D^0 &&
+
+ git merge -s recursive E^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test 6 -eq $(wc -l < a)
+'
+
+test_done
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 09/10] Tests and fixes associated with rename/rename conflicts
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
` (7 preceding siblings ...)
2011-03-21 18:31 ` [WIP PATCH 08/10] More test scripts Elijah Newren
@ 2011-03-21 18:31 ` 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
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:31 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
Add a new testcase for basic rename/rename (+modify/modify) -- temp12
Add a testcase for tough-to-handle rename/rename + criss-cross merges
Fix up most of temp12 testcase, but not yet handling merging of info from
other side of history.
---
merge-recursive.c | 24 ++++++++--------
t/temp12.sh | 59 +++++++++++++++++++++++++++++++++++++++
t/temp13.sh | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 150 insertions(+), 12 deletions(-)
create mode 100755 t/temp12.sh
create mode 100755 t/temp13.sh
diff --git a/merge-recursive.c b/merge-recursive.c
index 544c504..cea6e27 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -991,12 +991,12 @@ static int process_renames(struct merge_options *o,
for (i = 0; i < a_renames->nr; i++) {
sre = a_renames->items[i].util;
string_list_insert(&a_by_dst, sre->pair->two->path)->util
- = sre->dst_entry;
+ = (void*)sre;
}
for (i = 0; i < b_renames->nr; i++) {
sre = b_renames->items[i].util;
string_list_insert(&b_by_dst, sre->pair->two->path)->util
- = sre->dst_entry;
+ = (void*)sre;
}
for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {
@@ -1110,6 +1110,16 @@ static int process_renames(struct merge_options *o,
clean_merge = 0;
conflict_rename_delete(o, ren1->pair, branch1, branch2);
}
+ } else if ((item = string_list_lookup(renames2Dst, ren1_dst))) {
+ ren2 = item->util;
+ clean_merge = 0;
+ ren2->processed = 1;
+ output(o, 1, "CONFLICT (rename/rename): "
+ "Rename %s->%s in %s. "
+ "Rename %s->%s in %s",
+ ren1_src, ren1_dst, branch1,
+ ren2->pair->one->path, ren2->pair->two->path, branch2);
+ conflict_rename_rename_2to1(o, ren1, branch1, ren2, branch2);
} else if ((dst_other.mode == ren1->pair->two->mode) &&
sha_eq(dst_other.sha1, ren1->pair->two->sha1)) {
/* Added file on the other side
@@ -1150,16 +1160,6 @@ static int process_renames(struct merge_options *o,
output(o, 1, "Adding as %s instead", new_path);
update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
}
- } else if ((item = string_list_lookup(renames2Dst, ren1_dst))) {
- ren2 = item->util;
- clean_merge = 0;
- ren2->processed = 1;
- output(o, 1, "CONFLICT (rename/rename): "
- "Rename %s->%s in %s. "
- "Rename %s->%s in %s",
- ren1_src, ren1_dst, branch1,
- ren2->pair->one->path, ren2->pair->two->path, branch2);
- conflict_rename_rename_2to1(o, ren1, branch1, ren2, branch2);
} else
try_merge = 1;
diff --git a/t/temp12.sh b/t/temp12.sh
new file mode 100755
index 0000000..47e657b
--- /dev/null
+++ b/t/temp12.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='rename/rename (2to1) handling'
+
+. ./test-lib.sh
+
+# Current git gets all kinds of things wrong with rename/rename (2to1); setup:
+# Commit A: new files: a & b
+# Commit B: rename a->c, modify b
+# Commit C: rename b->c, modify a
+#
+# Merging of B & C should NOT be clean. Questions:
+# * Both a & b should be removed by the merge; are they?
+# * The two c's should contain modifications to a & b; do they?
+# * The index should contain two files, both for c; does it?
+# * The working copy should have two files, both of form c~<unique>; does it?
+# * Nothing else should be present. Is anything?
+
+test_expect_success 'setup rename/rename (+ modify/modify)' '
+ printf "1\n2\n3\n4\n5\n" >a &&
+ printf "5\n4\n3\n2\n1\n" >b &&
+ git add a b &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a c &&
+ echo 0 >>b &&
+ git add b &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv b c &&
+ echo 6 >>a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_success 'handle rename/rename conflict correctly' '
+ git checkout B^0 &&
+
+ test_must_fail git merge -s recursive C^0 >out &&
+ grep "CONFLICT (rename/rename)" out &&
+
+ test 2 -eq $(git ls-files -s | wc -l) &&
+ test 2 -eq $(git ls-files -u | wc -l) &&
+ test 2 -eq $(git ls-files -u c | wc -l) &&
+ test 3 -eq $(git ls-files -o | wc -l) &&
+
+ test ! -f a &&
+ test ! -f b &&
+ test -f c~HEAD &&
+ test -f c~C^0 &&
+
+ test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
+ test $(git hash-object c~B) = $(git rev-parse B:b)
+'
+
+test_done
diff --git a/t/temp13.sh b/t/temp13.sh
new file mode 100755
index 0000000..b455a8c
--- /dev/null
+++ b/t/temp13.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+test_description='recursive merge corner case: rename/rename (2to1) + criss-cross merge + introduce funny file on other side of history'
+
+. ./test-lib.sh
+
+#
+# Standard setup:
+#
+# B D
+# o---o
+# / \ / \
+# A o X ? F
+# \ / \ /
+# o---o
+# C E
+#
+# Commit A: new files: a, b
+# Commit B: rename a->c
+# Commit C: rename b->c
+# Commit D: merge B&C, keeping c1 (a) & c2 (b)
+# Commit E: merge B&C, keeping c1 (a) & c2 (b), and introducing c~HEAD, c~C
+#
+# Now, when we merge commits D & E, there should be no conflict...
+
+test_expect_success 'setup rename/rename + criss-cross + new funny files' '
+ echo content >a &&
+ echo other >b &&
+ git add a b &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a c &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ git mv b c &&
+ git commit -m C &&
+
+ git checkout B^0 &&
+ test_must_fail git merge C &&
+ git clean -f &&
+ git rm -rf . &&
+ echo content >c1 &&
+ echo other >c2 &&
+ git add c1 c2 &&
+ git commit -m D &&
+ git tag D &&
+
+ git checkout C^0 &&
+ test_must_fail git merge B &&
+ git clean -f &&
+ git rm -rf . &&
+ git checkout D -- . &&
+ git add c1 c2 &&
+ git mv c1 "c~Temporary merge branch 1" &&
+ git mv c2 "c~Temporary merge branch 2" &&
+ git commit -m E &&
+ git tag E
+'
+
+test_expect_success 'differently renamed files conflict detected' '
+ git checkout D^0 &&
+
+ (
+ # Do not want to use test_must_fail here because we do not want
+ # a premature fatal exit via "BUG: There are unmerged index
+ # entries" (exit code 128) to count as success. We want
+ # the code to run to completion, detect the conflict, and
+ # return an appropriate (not zero and not 128) exit code.
+ git merge -s recursive E^0;
+ exit_code=$? &&
+ test $exit_code -gt 0 -a $exit_code -lt 128
+ )
+
+'
+
+test_done
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [WIP PATCH 10/10] Add new testcase (temp14) showing how undetected renames can cause or spuriously avoid merge conflicts
2011-03-21 18:30 [WIP PATCH 00/10] Work-in-progress merge-recursive work Elijah Newren
` (8 preceding siblings ...)
2011-03-21 18:31 ` [WIP PATCH 09/10] Tests and fixes associated with rename/rename conflicts Elijah Newren
@ 2011-03-21 18:31 ` Elijah Newren
9 siblings, 0 replies; 11+ messages in thread
From: Elijah Newren @ 2011-03-21 18:31 UTC (permalink / raw)
To: git; +Cc: Elijah Newren
---
t/temp14.sh | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 63 insertions(+), 0 deletions(-)
create mode 100755 t/temp14.sh
diff --git a/t/temp14.sh b/t/temp14.sh
new file mode 100755
index 0000000..f82d991
--- /dev/null
+++ b/t/temp14.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+test_description='undetected renames cause merge problems'
+
+. ./test-lib.sh
+
+test_expect_success 'setup undetected rename causing conflict in merge' '
+ printf "1\n2\n3\n4\n5\n" >a &&
+ echo foo >b &&
+ git add a b &&
+ git commit -m A &&
+ git tag A &&
+
+ git checkout -b B A &&
+ git mv a c &&
+ echo "Completely different content" >a &&
+ git add a &&
+ git commit -m B &&
+
+ git checkout -b C A &&
+ echo 6 >>a &&
+ git add a &&
+ git commit -m C
+'
+
+test_expect_success 'undetected rename causes conflict' '
+ git checkout -q C^0 &&
+ git merge -s recursive B^0 &&
+
+ test 3 -eq $(git ls-files -s | wc -l) &&
+ test 0 -eq $(git ls-files -u | wc -l) &&
+ test 0 -eq $(git ls-files -o | wc -l) &&
+
+ test 6 -eq $(wc -l < c) &&
+ test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
+ test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
+'
+
+test_expect_success 'setup undetected rename causing missed merge conflict' '
+ git reset --hard &&
+ git clean -f &&
+
+ git checkout -b D A &&
+ echo 7 >>a &&
+ git add a &&
+ git mv a c &&
+ echo "Completely different content" >a &&
+ git add a &&
+ git commit -m D &&
+
+ git checkout -b E A &&
+ git rm a &&
+ echo "Completely different content" >>a &&
+ git add a &&
+ git commit -m E
+'
+
+test_expect_success 'undetected rename causes missed conflict' '
+ git checkout -q E^0 &&
+ test_must_fail git merge -s recursive D^0
+'
+
+test_done
--
1.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread