threads / patch / 7562

patch, 5 partst3030: merge-recursive backend test.

Subject: [PATCH 5/5] t3030: merge-recursive backend test.

## tl;dr

2 messages between Apr 7, 2007 and Apr 8, 2007. Diffs are folded; open one to read it.

replies: 1people: 1as markdown or json

Junio C Hamano· Apr 7, 2007, 14:43 UTC · lore

We have fairly extensive coverage of read-tree 3-way machinery, and many Porcelain-ish tests use git-merge front-end tests, but we did not have good basic test for merge-recursive, which made it very hard to hack on it.

I used this during the recent work to teach D/F conflicts to merge-recursive.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 t/t3030-merge-recursive.sh |  528 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 528 insertions(+), 0 deletions(-)
 create mode 100755 t/t3030-merge-recursive.sh
Show changes to t/t3030-merge-recursive.sh +528 −0
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
new file mode 100755
index 0000000..aef92b9
--- /dev/null
+++ b/t/t3030-merge-recursive.sh
@@ -0,0 +1,528 @@
+#!/bin/sh
+
+test_description='merge-recursive backend test'
+
+. ./test-lib.sh
+
+test_expect_success 'setup 1' '
+
+	echo hello >a &&
+	o0=$(git hash-object a) &&
+	cp a b &&
+	cp a A &&
+	mkdir d &&
+	cp a d/e &&
+
+	test_tick &&
+	git add a b A d/e &&
+	git commit -m initial &&
+	c0=$(git rev-parse --verify HEAD) &&
+	git branch side &&
+	git branch df-1 &&
+	git branch df-2 &&
+	git branch df-3 &&
+	git branch remove &&
+
+	echo hello >>a &&
+	cp a d/e &&
+	o1=$(git hash-object a) &&
+
+	git add a d/e &&
+
+	test_tick &&
+	git commit -m "master modifies a and d/e" &&
+	c1=$(git rev-parse --verify HEAD) &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o1	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o1	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o1 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+'
+
+test_expect_success 'setup 2' '
+
+	rm -rf [Aabd] &&
+	git checkout side &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o0	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual &&
+
+	echo goodbye >>a &&
+	o2=$(git hash-object a) &&
+
+	git add a &&
+
+	test_tick &&
+	git commit -m "side modifies a" &&
+	c2=$(git rev-parse --verify HEAD) &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o2	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o2 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+'
+
+test_expect_success 'setup 3' '
+
+	rm -rf [Aabd] &&
+	git checkout df-1 &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o0	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual &&
+
+	rm -f b && mkdir b && echo df-1 >b/c && git add b/c &&
+	o3=$(git hash-object b/c) &&
+
+	test_tick &&
+	git commit -m "df-1 makes b/c" &&
+	c3=$(git rev-parse --verify HEAD) &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o0	a"
+		echo "100644 blob $o3	b/c"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	a"
+		echo "100644 $o3 0	b/c"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+'
+
+test_expect_success 'setup 4' '
+
+	rm -rf [Aabd] &&
+	git checkout df-2 &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o0	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual &&
+
+	rm -f a && mkdir a && echo df-2 >a/c && git add a/c &&
+	o4=$(git hash-object a/c) &&
+
+	test_tick &&
+	git commit -m "df-2 makes a/c" &&
+	c4=$(git rev-parse --verify HEAD) &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o4	a/c"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o4 0	a/c"
+		echo "100644 $o0 0	b"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+'
+
+test_expect_success 'setup 5' '
+
+	rm -rf [Aabd] &&
+	git checkout remove &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o0	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual &&
+
+	rm -f b &&
+	echo remove-conflict >a &&
+
+	git add a &&
+	git rm b &&
+	o5=$(git hash-object a) &&
+
+	test_tick &&
+	git commit -m "remove removes b and modifies a" &&
+	c5=$(git rev-parse --verify HEAD) &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o5	a"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o5 0	a"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'setup 6' '
+
+	rm -rf [Aabd] &&
+	git checkout df-3 &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o0	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o0	d/e"
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o0 0	d/e"
+	) >expected &&
+	git diff -u expected actual &&
+
+	rm -fr d && echo df-3 >d && git add d &&
+	o6=$(git hash-object d) &&
+
+	test_tick &&
+	git commit -m "df-3 makes d" &&
+	c6=$(git rev-parse --verify HEAD) &&
+	( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+	(
+		echo "100644 blob $o0	A"
+		echo "100644 blob $o0	a"
+		echo "100644 blob $o0	b"
+		echo "100644 blob $o6	d"
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o6 0	d"
+	) >expected &&
+	git diff -u expected actual
+'
+
+test_expect_success 'merge-recursive simple' '
+
+	rm -fr [Aabd] &&
+	git checkout -f "$c2" &&
+
+	git-merge-recursive "$c0" -- "$c2" "$c1"
+	status=$?
+	case "$status" in
+	1)
+		: happy
+		;;
+	*)
+		echo >&2 "why status $status!!!"
+		false
+		;;
+	esac
+'
+
+test_expect_success 'merge-recursive result' '
+
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 1	a"
+		echo "100644 $o2 2	a"
+		echo "100644 $o1 3	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'merge-recursive remove conflict' '
+
+	rm -fr [Aabd] &&
+	git checkout -f "$c1" &&
+
+	git-merge-recursive "$c0" -- "$c1" "$c5"
+	status=$?
+	case "$status" in
+	1)
+		: happy
+		;;
+	*)
+		echo >&2 "why status $status!!!"
+		false
+		;;
+	esac
+'
+
+test_expect_success 'merge-recursive remove conflict' '
+
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 1	a"
+		echo "100644 $o1 2	a"
+		echo "100644 $o5 3	a"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'merge-recursive d/f simple' '
+	rm -fr [Aabd] &&
+	git reset --hard &&
+	git checkout -f "$c1" &&
+
+	git-merge-recursive "$c0" -- "$c1" "$c3"
+'
+
+test_expect_success 'merge-recursive result' '
+
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o1 0	a"
+		echo "100644 $o3 0	b/c"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'merge-recursive d/f conflict' '
+
+	rm -fr [Aabd] &&
+	git reset --hard &&
+	git checkout -f "$c1" &&
+
+	git-merge-recursive "$c0" -- "$c1" "$c4"
+	status=$?
+	case "$status" in
+	1)
+		: happy
+		;;
+	*)
+		echo >&2 "why status $status!!!"
+		false
+		;;
+	esac
+'
+
+test_expect_success 'merge-recursive d/f conflict result' '
+
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 1	a"
+		echo "100644 $o1 2	a"
+		echo "100644 $o4 0	a/c"
+		echo "100644 $o0 0	b"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'merge-recursive d/f conflict the other way' '
+
+	rm -fr [Aabd] &&
+	git reset --hard &&
+	git checkout -f "$c4" &&
+
+	git-merge-recursive "$c0" -- "$c4" "$c1"
+	status=$?
+	case "$status" in
+	1)
+		: happy
+		;;
+	*)
+		echo >&2 "why status $status!!!"
+		false
+		;;
+	esac
+'
+
+test_expect_success 'merge-recursive d/f conflict result the other way' '
+
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 1	a"
+		echo "100644 $o1 3	a"
+		echo "100644 $o4 0	a/c"
+		echo "100644 $o0 0	b"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'merge-recursive d/f conflict' '
+
+	rm -fr [Aabd] &&
+	git reset --hard &&
+	git checkout -f "$c1" &&
+
+	git-merge-recursive "$c0" -- "$c1" "$c6"
+	status=$?
+	case "$status" in
+	1)
+		: happy
+		;;
+	*)
+		echo >&2 "why status $status!!!"
+		false
+		;;
+	esac
+'
+
+test_expect_success 'merge-recursive d/f conflict result' '
+
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o1 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o6 3	d"
+		echo "100644 $o0 1	d/e"
+		echo "100644 $o1 2	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'merge-recursive d/f conflict' '
+
+	rm -fr [Aabd] &&
+	git reset --hard &&
+	git checkout -f "$c6" &&
+
+	git-merge-recursive "$c0" -- "$c6" "$c1"
+	status=$?
+	case "$status" in
+	1)
+		: happy
+		;;
+	*)
+		echo >&2 "why status $status!!!"
+		false
+		;;
+	esac
+'
+
+test_expect_success 'merge-recursive d/f conflict result' '
+
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o1 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o6 2	d"
+		echo "100644 $o0 1	d/e"
+		echo "100644 $o1 3	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_expect_success 'reset and 3-way merge' '
+
+	git reset --hard "$c2" &&
+	git read-tree -m "$c0" "$c2" "$c1"
+
+'
+
+test_expect_success 'reset and bind merge' '
+
+	git reset --hard master &&
+	git read-tree --prefix=M/ master &&
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	M/A"
+		echo "100644 $o1 0	M/a"
+		echo "100644 $o0 0	M/b"
+		echo "100644 $o1 0	M/d/e"
+		echo "100644 $o1 0	a"
+		echo "100644 $o0 0	b"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual &&
+
+	git read-tree --prefix=a1/ master &&
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	M/A"
+		echo "100644 $o1 0	M/a"
+		echo "100644 $o0 0	M/b"
+		echo "100644 $o1 0	M/d/e"
+		echo "100644 $o1 0	a"
+		echo "100644 $o0 0	a1/A"
+		echo "100644 $o1 0	a1/a"
+		echo "100644 $o0 0	a1/b"
+		echo "100644 $o1 0	a1/d/e"
+		echo "100644 $o0 0	b"
+		echo "100644 $o1 0	d/e"
+	) >expected &&
+	git diff -u expected actual
+
+	git read-tree --prefix=z/ master &&
+	git ls-files -s >actual &&
+	(
+		echo "100644 $o0 0	A"
+		echo "100644 $o0 0	M/A"
+		echo "100644 $o1 0	M/a"
+		echo "100644 $o0 0	M/b"
+		echo "100644 $o1 0	M/d/e"
+		echo "100644 $o1 0	a"
+		echo "100644 $o0 0	a1/A"
+		echo "100644 $o1 0	a1/a"
+		echo "100644 $o0 0	a1/b"
+		echo "100644 $o1 0	a1/d/e"
+		echo "100644 $o0 0	b"
+		echo "100644 $o1 0	d/e"
+		echo "100644 $o0 0	z/A"
+		echo "100644 $o1 0	z/a"
+		echo "100644 $o0 0	z/b"
+		echo "100644 $o1 0	z/d/e"
+	) >expected &&
+	git diff -u expected actual
+
+'
+
+test_done
+
-- 
1.5.1.81.gee969
Junio C Hamano· Apr 8, 2007, 05:17 UTC · re: Junio C Hamano · lore

Re: [PATCH 5/5] t3030: merge-recursive backend test.

Junio C Hamano <junkio@cox.net> writes:
Show 14 quoted lines
> +test_expect_success 'merge-recursive d/f conflict result' '
> +
> +	git ls-files -s >actual &&
> +	(
> +		echo "100644 $o0 0	A"
> +		echo "100644 $o0 1	a"
> +		echo "100644 $o1 2	a"
> +		echo "100644 $o4 0	a/c"
> +		echo "100644 $o0 0	b"
> +		echo "100644 $o1 0	d/e"
> +	) >expected &&
> +	git diff -u expected actual
> +
> +'

The expected result of this test is what I find very iffy. The input trees are:

 * Ancestor has a file "a"
 * Our tree has a file "a", which was modified from the
   ancestor's
 * The other tree has a file "a/c"

merge-recursive.c::git_merge_trees() calls unpack_trees() using the threeway_merge function and what it gets back are stage 1 and 2 entries for "a", and stage 3 entry for "a/c" (you can see it by running "git-read-tree -m $c0 $c1 $c4" instead). But the output from merge-recursive has "a/c" resolved down to stage 0.

The problem is that process_entry() finds that there is only stage 3 entry for that path and decides to resolve it. I think it should do the D/F check and leave "a/c" in stage 3.

Looking at the D/F conflict detection code in merge-recursive.c makes my head hurt, and I do not quite follow the logic there, but it seems to be doing the following to me.

 * current_directory_set is initialized to be union of all
   directories that appear in our tree and the other tree (I am
   not sure if that set is updated and if so how);
 * when a path is about to be resolved to a blob, this set is
   consulted, and if there is a directory there, declare D/F
   conflict and blob is added under a name that does not
   conflict with the directory;
 * otherwise the path is resolved down to stage 0.

However, in this case, there is no such directory "a/c" but the code forgets that adding a blob at "a/c" requires that there is no file "a" at all. I am not sure if this is deliberate or just a simple oversight.

Also I suspect this can be done more easily with just checking
the index.  We know blob "a" is in the index, unresolved, when
we try to resolve path "a/c".
 

← back to recent threads