From d3621de789ab57739f48b065751089d828b50240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Tue, 31 May 2016 22:00:38 +0200 Subject: t4051: rewrite, add more tests Remove the tests that checked against a fixed result and replace them with more focused checks of desired properties of the created diffs. That way we get more detailed and meaningful diagnostics. Store test file contents in files in a subdirectory in order to avoid cluttering the test script with them. Use tagged commits to store the changes to test diff -W against instead of using changes to the worktree. Use the worktree instead to try and apply the generated patch in order to validate it. Document unwanted features: trailing empty lines, too much context for appended functions, insufficient context at the end with -U0. Helped-by: Junio C Hamano Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh index 001d678..ca01725 100755 --- a/t/t4051-diff-function-context.sh +++ b/t/t4051-diff-function-context.sh @@ -3,90 +3,158 @@ test_description='diff function context' . ./test-lib.sh -. "$TEST_DIRECTORY"/diff-lib.sh +dir="$TEST_DIRECTORY/t4051" -cat <<\EOF >hello.c -#include - -static int a(void) -{ - /* - * Dummy. - */ +commit_and_tag () { + tag=$1 && + shift && + git add "$@" && + test_tick && + git commit -m "$tag" && + git tag "$tag" } -static int hello_world(void) -{ - /* Classic. */ - printf("Hello world.\n"); - - /* Success! */ - return 0; +first_context_line () { + awk ' + found {print; exit} + /^@@/ {found = 1} + ' } -static int b(void) -{ - /* - * Dummy, too. - */ + +last_context_line () { + sed -ne \$p } -int main(int argc, char **argv) -{ - a(); - b(); - return hello_world(); +check_diff () { + name=$1 + desc=$2 + options="-W $3" + + test_expect_success "$desc" ' + git diff $options "$name^" "$name" >"$name.diff" + ' + + test_expect_success ' diff applies' ' + test_when_finished "git reset --hard" && + git checkout --detach "$name^" && + git apply --index "$name.diff" && + git diff --exit-code "$name" + ' } -EOF test_expect_success 'setup' ' - git add hello.c && - test_tick && - git commit -m initial && - - grep -v Classic hello.c.new && - mv hello.c.new hello.c -' - -cat <<\EOF >expected -diff --git a/hello.c b/hello.c ---- a/hello.c -+++ b/hello.c -@@ -10,8 +10,7 @@ static int a(void) - static int hello_world(void) - { -- /* Classic. */ - printf("Hello world.\n"); - - /* Success! */ - return 0; - } -EOF - -test_expect_success 'diff -U0 -W' ' - git diff -U0 -W >actual && - compare_diff_patch actual expected -' - -cat <<\EOF >expected -diff --git a/hello.c b/hello.c ---- a/hello.c -+++ b/hello.c -@@ -9,9 +9,8 @@ static int a(void) - - static int hello_world(void) - { -- /* Classic. */ - printf("Hello world.\n"); - - /* Success! */ - return 0; - } -EOF - -test_expect_success 'diff -W' ' - git diff -W >actual && - compare_diff_patch actual expected + cat "$dir/includes.c" "$dir/dummy.c" "$dir/dummy.c" "$dir/hello.c" \ + "$dir/dummy.c" "$dir/dummy.c" >file.c && + commit_and_tag initial file.c && + + grep -v "delete me from hello" file.c.new && + mv file.c.new file.c && + commit_and_tag changed_hello file.c && + + grep -v "delete me from includes" file.c.new && + mv file.c.new file.c && + commit_and_tag changed_includes file.c && + + cat "$dir/appended1.c" >>file.c && + commit_and_tag appended file.c && + + cat "$dir/appended2.c" >>file.c && + commit_and_tag extended file.c && + + grep -v "Begin of second part" file.c.new && + mv file.c.new file.c && + commit_and_tag long_common_tail file.c +' + +check_diff changed_hello 'changed function' + +test_expect_success ' context includes begin' ' + grep "^ .*Begin of hello" changed_hello.diff +' + +test_expect_success ' context includes end' ' + grep "^ .*End of hello" changed_hello.diff +' + +test_expect_success ' context does not include other functions' ' + test $(grep -c "^[ +-].*Begin" changed_hello.diff) -le 1 +' + +test_expect_success ' context does not include preceding empty lines' ' + test "$(first_context_line = 0; + i--) { + printf("%d bottles of beer on the wall\n", i); + } + + printf("End of first part\n"); diff --git a/t/t4051/appended2.c b/t/t4051/appended2.c new file mode 100644 index 0000000..e651f71 --- /dev/null +++ b/t/t4051/appended2.c @@ -0,0 +1,35 @@ + printf("Begin of second part\n"); + + /* + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + */ + + return 0; +} // End of second part diff --git a/t/t4051/dummy.c b/t/t4051/dummy.c new file mode 100644 index 0000000..a43016e --- /dev/null +++ b/t/t4051/dummy.c @@ -0,0 +1,7 @@ + +static int dummy(void) // Begin of dummy +{ + int rc = 0; + + return rc; +} // End of dummy diff --git a/t/t4051/hello.c b/t/t4051/hello.c new file mode 100644 index 0000000..63b1a1e --- /dev/null +++ b/t/t4051/hello.c @@ -0,0 +1,21 @@ + +static void hello(void) // Begin of hello +{ + /* + * Classic. + */ + putchar('H'); + putchar('e'); + putchar('l'); + putchar('l'); + putchar('o'); + putchar(' '); + /* delete me from hello */ + putchar('w'); + putchar('o'); + putchar('r'); + putchar('l'); + putchar('d'); + putchar('.'); + putchar('\n'); +} // End of hello diff --git a/t/t4051/includes.c b/t/t4051/includes.c new file mode 100644 index 0000000..efc68f8 --- /dev/null +++ b/t/t4051/includes.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include +#include +#include +#include +/* delete me from includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -- cgit v0.10.2-6-g49f6 From ff2981f724c617d377229666e6deae257de5e239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 28 May 2016 16:58:47 +0200 Subject: xdiff: factor out match_func_rec() Add match_func_rec(), a helper that wraps accessing a record and calling the appropriate function for checking if it contains a function line. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 993724b..0c87637 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -120,6 +120,16 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) return -1; } +static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri, + char *buf, long sz) +{ + const char *rec; + long len = xdl_get_rec(xdf, ri, &rec); + if (!xecfg->find_func) + return def_ff(rec, len, buf, sz, xecfg->find_func_priv); + return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv); +} + struct func_line { long len; char buf[80]; @@ -128,7 +138,6 @@ struct func_line { static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, struct func_line *func_line, long start, long limit) { - find_func_t ff = xecfg->find_func ? xecfg->find_func : def_ff; long l, size, step = (start > limit) ? -1 : 1; char *buf, dummy[1]; @@ -136,9 +145,7 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, size = func_line ? sizeof(func_line->buf) : sizeof(dummy); for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) { - const char *rec; - long reclen = xdl_get_rec(&xe->xdf1, l, &rec); - long len = ff(rec, reclen, buf, size, xecfg->find_func_priv); + long len = match_func_rec(&xe->xdf1, xecfg, l, buf, size); if (len >= 0) { if (func_line) func_line->len = len; -- cgit v0.10.2-6-g49f6 From 6d5badb2389d5d1d0752a230cd7ee74bb4043893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 28 May 2016 17:00:28 +0200 Subject: xdiff: handle appended chunks better with -W If lines are added at the end of a file, diff -W shows the whole file. That's because get_func_line() only considers the pre-image and gives up if it sees a record index beyond its end. Consider the post-image as well to see if the added lines already make up a full function. If it doesn't then search for the previous function line by starting from the bottom of the pre-image, thereby avoiding to confuse get_func_line(). Reuse the existing label called "again", as it's exactly where we need to jump to when we're done handling the pre-context, but rename it to "post_context_calculation" in order to document its new purpose better. Reported-by: Junio C Hamano Initial-patch-by: Junio C Hamano Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh index ca01725..4cff119 100755 --- a/t/t4051-diff-function-context.sh +++ b/t/t4051-diff-function-context.sh @@ -131,7 +131,7 @@ test_expect_success ' context includes end' ' grep "^[+].*End of second part" extended.diff ' -test_expect_failure ' context does not include other functions' ' +test_expect_success ' context does not include other functions' ' test $(grep -c "^[ +-].*Begin" extended.diff) -le 2 ' diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 0c87637..969100d 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -171,7 +171,28 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { - long fs1 = get_func_line(xe, xecfg, NULL, xch->i1, -1); + long fs1, i1 = xch->i1; + + /* Appended chunk? */ + if (i1 >= xe->xdf1.nrec) { + char dummy[1]; + + /* + * We don't need additional context if + * a whole function was added. + */ + if (match_func_rec(&xe->xdf2, xecfg, xch->i2, + dummy, sizeof(dummy)) >= 0) + goto post_context_calculation; + + /* + * Otherwise get more context from the + * pre-image. + */ + i1 = xe->xdf1.nrec - 1; + } + + fs1 = get_func_line(xe, xecfg, NULL, i1, -1); if (fs1 < 0) fs1 = 0; if (fs1 < s1) { @@ -180,7 +201,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, } } - again: + post_context_calculation: lctx = xecfg->ctxlen; lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1)); lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2)); @@ -209,7 +230,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, if (l <= e1 || get_func_line(xe, xecfg, NULL, l, e1) < 0) { xche = xche->next; - goto again; + goto post_context_calculation; } } } -- cgit v0.10.2-6-g49f6 From 392f6d316623e8ecd6210248ba9ae2cabf07352b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 28 May 2016 17:02:24 +0200 Subject: xdiff: ignore empty lines before added functions with -W If a new function and a preceding empty line is appended, diff -W shows the previous function in full in order to provide context for that empty line. In most languages empty lines between sections are not interesting in and off themselves and showing a whole extra function for them is not what we want. Skip empty lines when checking of the appended chunk starts with a function line, thereby avoiding to extend the context just for them. Helped-by: Ramsay Jones Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh index 4cff119..f7126fc 100755 --- a/t/t4051-diff-function-context.sh +++ b/t/t4051-diff-function-context.sh @@ -117,7 +117,7 @@ test_expect_success ' context includes end' ' grep "^[+].*End of first part" appended.diff ' -test_expect_failure ' context does not include other functions' ' +test_expect_success ' context does not include other functions' ' test $(grep -c "^[ +-].*Begin" appended.diff) -le 1 ' diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 969100d..29cec12 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -155,6 +155,18 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, return -1; } +static int is_empty_rec(xdfile_t *xdf, long ri) +{ + const char *rec; + long len = xdl_get_rec(xdf, ri, &rec); + + while (len > 0 && XDL_ISSPACE(*rec)) { + rec++; + len--; + } + return !len; +} + int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { long s1, s2, e1, e2, lctx; @@ -176,12 +188,18 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, /* Appended chunk? */ if (i1 >= xe->xdf1.nrec) { char dummy[1]; + long i2 = xch->i2; /* * We don't need additional context if - * a whole function was added. + * a whole function was added, possibly + * starting with empty lines. */ - if (match_func_rec(&xe->xdf2, xecfg, xch->i2, + while (i2 < xe->xdf2.nrec && + is_empty_rec(&xe->xdf2, i2)) + i2++; + if (i2 < xe->xdf2.nrec && + match_func_rec(&xe->xdf2, xecfg, i2, dummy, sizeof(dummy)) >= 0) goto post_context_calculation; -- cgit v0.10.2-6-g49f6 From 9e6a4cfc38aa81055d0b7d6fb94dc7b31809daa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 28 May 2016 17:03:16 +0200 Subject: xdiff: -W: don't include common trailing empty lines in context Empty lines between functions are shown by diff -W, as it considers them to be part of the function preceding them. They are not interesting in most languages. The previous patch stopped showing them in the special case of a function added at the end of a file. Stop extending context to those empty lines by skipping back over them from the start of the next function. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh index f7126fc..17616fe 100755 --- a/t/t4051-diff-function-context.sh +++ b/t/t4051-diff-function-context.sh @@ -85,7 +85,7 @@ test_expect_success ' context does not include preceding empty lines' ' test "$(first_context_line i1 + xche->chg1, xe->xdf1.nrec); + while (fe1 > 0 && is_empty_rec(&xe->xdf1, fe1 - 1)) + fe1--; if (fe1 < 0) fe1 = xe->xdf1.nrec; if (fe1 > e1) { -- cgit v0.10.2-6-g49f6 From e0876bca4de44638a1cb51b03bdf0a40df631a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 28 May 2016 17:04:31 +0200 Subject: xdiff: don't trim common tail with -W The function trim_common_tail() exits early if context lines are requested. If -U0 and -W are specified together then it can still trim context lines that might belong to a changed function. As a result that function is shown incompletely. Fix that by calling trim_common_tail() only if no function context or fixed context is requested. The parameter ctx is no longer needed now; remove it. While at it fix an outdated comment as well. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh index 17616fe..b6bb04a 100755 --- a/t/t4051-diff-function-context.sh +++ b/t/t4051-diff-function-context.sh @@ -145,7 +145,7 @@ test_expect_success ' context includes begin' ' grep "^ .*Begin of first part" long_common_tail.diff ' -test_expect_failure ' context includes end' ' +test_expect_success ' context includes end' ' grep "^ .*End of second part" long_common_tail.diff ' diff --git a/xdiff-interface.c b/xdiff-interface.c index 54236f2..f34ea76 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -100,9 +100,9 @@ static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) /* * Trim down common substring at the end of the buffers, - * but leave at least ctx lines at the end. + * but end on a complete line. */ -static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx) +static void trim_common_tail(mmfile_t *a, mmfile_t *b) { const int blk = 1024; long trimmed = 0, recovered = 0; @@ -110,9 +110,6 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx) char *bp = b->ptr + b->size; long smaller = (a->size < b->size) ? a->size : b->size; - if (ctx) - return; - while (blk + trimmed <= smaller && !memcmp(ap - blk, bp - blk, blk)) { trimmed += blk; ap -= blk; @@ -134,7 +131,8 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co if (mf1->size > MAX_XDIFF_SIZE || mf2->size > MAX_XDIFF_SIZE) return -1; - trim_common_tail(&a, &b, xecfg->ctxlen); + if (!xecfg->ctxlen && !(xecfg->flags & XDL_EMIT_FUNCCONTEXT)) + trim_common_tail(&a, &b); return xdl_diff(&a, &b, xpp, xecfg, xecb); } -- cgit v0.10.2-6-g49f6 From 799e09e5fb9e23e2baae164ddc84a03879db6a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 28 May 2016 17:05:41 +0200 Subject: t7810: add test for grep -W and trailing empty context lines Add a test demonstrating that git grep -W prints empty lines following the function context we're actually interested in. The modified test file makes it necessary to adjust three unrelated test cases. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index b540944..c42b82a 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -9,7 +9,9 @@ test_description='git grep various. . ./test-lib.sh cat >hello.c < #include + int main(int argc, const char **argv) { printf("Hello world.\n"); @@ -715,6 +717,7 @@ test_expect_success 'grep -p' ' cat >expected < +hello.c- hello.c=int main(int argc, const char **argv) hello.c-{ hello.c- printf("Hello world.\n"); @@ -741,6 +744,16 @@ test_expect_success 'grep -W' ' ' cat >expected < +hello.c:#include +EOF + +test_expect_failure 'grep -W shows no trailing empty lines' ' + git grep -W stdio >actual && + test_cmp expected actual +' + +cat >expected <expected <hello.c -2:int main(int argc, const char **argv) -6: /* char ?? */ +4:int main(int argc, const char **argv) +8: /* char ?? */ hello_world 3:Hello_world @@ -1313,7 +1326,7 @@ test_expect_success 'grep --color -e A --and --not -e B with context' ' ' cat >expected < +hello.c- hello.c=int main(int argc, const char **argv) hello.c-{ hello.c: printf("Hello world.\n"); -- cgit v0.10.2-6-g49f6 From 4aa2c4753d152aef810eaf3f3f4fa1df7035d9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 28 May 2016 17:06:19 +0200 Subject: grep: -W: don't extend context to trailing empty lines Empty lines between functions are shown by grep -W, as it considers them to be part of the function preceding them. They are not interesting in most languages. The previous patches stopped showing them for diff -W. Stop showing empty lines trailing a function with grep -W. Grep scans the lines of a buffer from top to bottom and prints matching lines immediately. Thus we need to peek ahead in order to determine if an empty line is part of a function body and worth showing or not. Remember how far ahead we peeked in order to avoid having to do so repeatedly when handling multiple consecutive empty lines. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/grep.c b/grep.c index 528b652..fafb8b5 100644 --- a/grep.c +++ b/grep.c @@ -1396,9 +1396,17 @@ static int fill_textconv_grep(struct userdiff_driver *driver, return 0; } +static int is_empty_line(const char *bol, const char *eol) +{ + while (bol < eol && isspace(*bol)) + bol++; + return bol == eol; +} + static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int collect_hits) { char *bol; + char *peek_bol = NULL; unsigned long left; unsigned lno = 1; unsigned last_hit = 0; @@ -1543,8 +1551,24 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle show_function = 1; goto next_line; } - if (show_function && match_funcname(opt, gs, bol, eol)) - show_function = 0; + if (show_function && (!peek_bol || peek_bol < bol)) { + unsigned long peek_left = left; + char *peek_eol = eol; + + /* + * Trailing empty lines are not interesting. + * Peek past them to see if they belong to the + * body of the current function. + */ + peek_bol = bol; + while (is_empty_line(peek_bol, peek_eol)) { + peek_bol = peek_eol + 1; + peek_eol = end_of_line(peek_bol, &peek_left); + } + + if (match_funcname(opt, gs, peek_bol, peek_eol)) + show_function = 0; + } if (show_function || (last_hit && lno <= last_hit + opt->post_context)) { /* If the last hit is within the post context, diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index c42b82a..befbde4 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -748,7 +748,7 @@ hello.c-#include hello.c:#include EOF -test_expect_failure 'grep -W shows no trailing empty lines' ' +test_expect_success 'grep -W shows no trailing empty lines' ' git grep -W stdio >actual && test_cmp expected actual ' -- cgit v0.10.2-6-g49f6 From 6f8d9bccb2c3694c62d14225976689c1e8c50fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Thu, 9 Jun 2016 23:54:48 +0200 Subject: xdiff: fix merging of appended hunk with -W When -W is given we search the lines between the end of the current context and the next change for a function line. If there is none then we merge those two hunks as they must be part of the same function. If the next change is an appended chunk we abort the search early in get_func_line(), however, because its line number is out of range. Fix that by searching from the end of the pre-image in that case instead. Reported-by: Junio C Hamano Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh index b6bb04a..b79b877 100755 --- a/t/t4051-diff-function-context.sh +++ b/t/t4051-diff-function-context.sh @@ -64,7 +64,13 @@ test_expect_success 'setup' ' grep -v "Begin of second part" file.c.new && mv file.c.new file.c && - commit_and_tag long_common_tail file.c + commit_and_tag long_common_tail file.c && + + git checkout initial && + grep -v "delete me from hello" file.c.new && + mv file.c.new file.c && + cat "$dir/appended1.c" >>file.c && + commit_and_tag changed_hello_appended file.c ' check_diff changed_hello 'changed function' @@ -157,4 +163,20 @@ test_expect_success ' context does not include preceding empty lines' ' test "$(first_context_line next) { - long l = xche->next->i1; + long l = XDL_MIN(xche->next->i1, + xe->xdf1.nrec - 1); if (l <= e1 || get_func_line(xe, xecfg, NULL, l, e1) < 0) { xche = xche->next; -- cgit v0.10.2-6-g49f6