Subject: [PATCH] git apply: do not match beginning in special unidiff-zero case

From: Clemens Buchacher <[email-masked]>
Date: Sat, 30 Aug 2008 21:03:02 +0200

If a unidiff patch without any context modifies the second line, it does
not match the beginning, even though oldpos == 1.

Signed-off-by: Clemens Buchacher <[email-masked]>
---

On Sat, Aug 30, 2008 at 10:53:15AM -0700, Junio C Hamano wrote:
> Clemens Buchacher <[email-masked]> writes:
> 
> > echo a > victim
> > git add victim
> > echo b >> victim
> > git diff -U0 | git apply --cached --unidiff-zero
> > git diff
> 
> I think "diff -U0" there would say "@@ -1,0 +2 @@", iow "add this one line
> after the first line", and "apply" has an off-by-one in this case.

Indeed. This appears to fix problems with staging hunks in git gui, even
with zero context lines. Staging individual lines still doesn't work,
though.

Clemens

 builtin-apply.c           |    9 ++++-----
 t/t4104-apply-boundary.sh |   15 ++++++++++++---
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/builtin-apply.c b/builtin-apply.c
index 2216a0b..8402f9d 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -1994,16 +1994,15 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
 	trailing = frag->trailing;
 
 	/*
-	 * A hunk to change lines at the beginning would begin with
+	 * Unless the patch was generated with unidiff without any context, a
+	 * hunk to change lines at the beginning would begin with
 	 * @@ -1,L +N,M @@
 	 *
 	 * And a hunk to add to an empty file would begin with
 	 * @@ -0,0 +N,M @@
-	 *
-	 * In other words, a hunk that is (frag->oldpos <= 1) with or
-	 * without leading context must match at the beginning.
 	 */
-	match_beginning = frag->oldpos <= 1;
+	match_beginning = frag->oldpos == 0 ||
+		(!unidiff_zero && frag->oldpos == 1);
 
 	/*
 	 * A hunk without trailing lines must match at the end.
diff --git a/t/t4104-apply-boundary.sh b/t/t4104-apply-boundary.sh
index e7e2913..0e3ce36 100755
--- a/t/t4104-apply-boundary.sh
+++ b/t/t4104-apply-boundary.sh
@@ -27,6 +27,15 @@ test_expect_success setup '
 	git diff victim >add-a-patch.with &&
 	git diff --unified=0 >add-a-patch.without &&
 
+	: insert at line two
+	for i in b a '"$L"' y
+	do
+		echo $i
+	done >victim &&
+	cat victim >insert-a-expect &&
+	git diff victim >insert-a-patch.with &&
+	git diff --unified=0 >insert-a-patch.without &&
+
 	: modify at the head
 	for i in a '"$L"' y
 	do
@@ -55,7 +64,7 @@ test_expect_success setup '
 	git diff --unified=0 >add-z-patch.without &&
 
 	: modify at the tail
-	for i in a '"$L"' y
+	for i in b '"$L"' z
 	do
 		echo $i
 	done >victim &&
@@ -81,7 +90,7 @@ do
 	with) u= ;;
 	without) u='--unidiff-zero ' ;;
 	esac
-	for kind in add-a add-z mod-a mod-z del-a del-z
+	for kind in add-a add-z insert-a mod-a mod-z del-a del-z
 	do
 		test_expect_success "apply $kind-patch $with context" '
 			cat original >victim &&
@@ -95,7 +104,7 @@ do
 	done
 done
 
-for kind in add-a add-z mod-a mod-z del-a del-z
+for kind in add-a add-z insert-a mod-a mod-z del-a del-z
 do
 	rm -f $kind-ng.without
 	sed	-e "s/^diff --git /diff /" \
-- 
1.6.0