# [PATCH] line-range: skip trailing empty lines in funcname range

4 messages from 2026-09-21 to 2026-09-25. Participants: Kristofer Karlsson via GitGitGadget, Junio C Hamano, Kristofer Karlsson.
Thread: https://gitlist.dev/t/66359

## Kristofer Karlsson via GitGitGadget, 2026-09-21 11:49

Subject: [PATCH] line-range: skip trailing empty lines in funcname range
Message-ID: <pull.2234.git.1789991377413.gitgitgadget@gmail.com>

```
From: Kristofer Karlsson <krka@spotify.com>

git log -L :funcname: includes trailing empty lines in the
function range. This boils down to parse_range_funcname()
extending the range forward until it either reaches end-of-file
or another function, without skipping empty lines at the
boundary. Including empty lines is inconsistent with how it
works for git grep -W.

Fix this by trimming trailing empty lines from the computed range,
with the same goal as this fix (though with a different approach):

    8e5dd94e68 (grep: -W: skip trailing empty lines at EOF, too,
    2024-07-30)

Reported-by: Nikita Makarov <n.makarov@yadro.com>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
---
    line-range: skip trailing empty lines in funcname range

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2234%2Fspkrka%2Fkrka%2Fline-range-trailing-blank-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2234/spkrka/krka/line-range-trailing-blank-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2234

 line-range.c                                  |  5 ++++
 t/t4211-line-log.sh                           | 26 +++++++++++++++++++
 t/t4211/sha1/expect.parallel-change-f-to-main | 18 +++++--------
 t/t4211/sha1/expect.simple-f-to-main          | 12 +++------
 .../sha256/expect.parallel-change-f-to-main   | 18 +++++--------
 t/t4211/sha256/expect.simple-f-to-main        | 12 +++------
 6 files changed, 51 insertions(+), 40 deletions(-)

diff --git a/line-range.c b/line-range.c
index b99f0d9895..44b52d4e34 100644
--- a/line-range.c
+++ b/line-range.c
@@ -233,6 +233,11 @@ static const char *parse_range_funcname(
 		(*end)++;
 	}
 
+	/* exclude trailing empty lines from the function range */
+	while (*end > *begin + 1 &&
+	       nth_line_cb(cb_data, *end - 1)[0] == '\n')
+		(*end)--;
+
 	regfree(&regexp);
 	if (xecfg)
 		xdiff_clear_find_func(xecfg);
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index d0a834ed8f..3f2a889e76 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -781,6 +781,32 @@ test_expect_success '--summary shows new file on root commit' '
 	test_grep "create mode 100644 file.c" actual
 '
 
+test_expect_success '-L :funcname: excludes trailing empty lines at EOF' '
+	git init trailing-empty &&
+	(
+		cd trailing-empty &&
+		test_commit --printf --no-tag "add func.py" \
+			func.py "def foo():\n    return 1\n" &&
+		test_commit --printf --no-tag "add trailing empty lines" \
+			func.py "def foo():\n    return 1\n\n\n\n" &&
+		git log -L :foo:func.py --format="%s" >actual &&
+		test_grep ! "add trailing empty lines" actual
+	)
+'
+
+test_expect_success '-L :funcname: excludes empty lines between functions' '
+	git init empty-between-funcs &&
+	(
+		cd empty-between-funcs &&
+		test_commit --printf --no-tag "add two funcs" \
+			func.py "def foo():\n    return 1\n\ndef bar():\n    return 2\n" &&
+		test_commit --printf --no-tag "add empty lines between" \
+			func.py "def foo():\n    return 1\n\n\n\ndef bar():\n    return 2\n" &&
+		git log -L :foo:func.py --format="%s" >actual &&
+		test_grep ! "add empty lines between" actual
+	)
+'
+
 test_expect_success 'get_commit_action() does not mutate a not-yet-walked commit' '
 	git init peek &&
 	(
diff --git a/t/t4211/sha1/expect.parallel-change-f-to-main b/t/t4211/sha1/expect.parallel-change-f-to-main
index 6d7a201036..cb2f6bcbac 100644
--- a/t/t4211/sha1/expect.parallel-change-f-to-main
+++ b/t/t4211/sha1/expect.parallel-change-f-to-main
@@ -15,7 +15,7 @@ diff --git a/b.c b/b.c
 index 5de3ea4..bf79c2f 100644
 --- a/b.c
 +++ b/b.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -30,7 +30,6 @@ index 5de3ea4..bf79c2f 100644
  /*
   * This is only an example!
   */
- 
 
 commit ba227c6632349700fbb957dec2b50f5e2358be3f
 Author: Thomas Rast <trast@inf.ethz.ch>
@@ -42,7 +41,7 @@ diff --git a/a.c b/a.c
 index 5de3ea4..01b5b65 100644
 --- a/a.c
 +++ b/a.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -57,7 +56,6 @@ index 5de3ea4..01b5b65 100644
 - * This is only an example!
 + * This is only a short example!
   */
- 
 
 commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -69,7 +67,7 @@ diff --git a/a.c b/a.c
 index e51de13..bdb2bb1 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -84,7 +82,6 @@ index e51de13..bdb2bb1 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -96,7 +93,7 @@ diff --git a/a.c b/a.c
 index 3233403..e51de13 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -111,7 +108,6 @@ index 3233403..e51de13 100644
  /*
   * A comment.
   */
- 
 
 commit f04fb20f2c77850996cba739709acc6faecc58f7
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -123,7 +119,7 @@ diff --git a/a.c b/a.c
 index 444e415..3233403 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -137,7 +133,6 @@ index 444e415..3233403 100644
  /*
   * A comment.
   */
- 
 
 commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -150,7 +145,7 @@ new file mode 100644
 index 0000000..444e415
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -163,4 +158,3 @@ index 0000000..444e415
 +/*
 + * A comment.
 + */
-+
diff --git a/t/t4211/sha1/expect.simple-f-to-main b/t/t4211/sha1/expect.simple-f-to-main
index cd92100dfc..99404cdc40 100644
--- a/t/t4211/sha1/expect.simple-f-to-main
+++ b/t/t4211/sha1/expect.simple-f-to-main
@@ -8,7 +8,7 @@ diff --git a/a.c b/a.c
 index e51de13..bdb2bb1 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -23,7 +23,6 @@ index e51de13..bdb2bb1 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -35,7 +34,7 @@ diff --git a/a.c b/a.c
 index 3233403..e51de13 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -50,7 +49,6 @@ index 3233403..e51de13 100644
  /*
   * A comment.
   */
- 
 
 commit f04fb20f2c77850996cba739709acc6faecc58f7
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -62,7 +60,7 @@ diff --git a/a.c b/a.c
 index 444e415..3233403 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -76,7 +74,6 @@ index 444e415..3233403 100644
  /*
   * A comment.
   */
- 
 
 commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -89,7 +86,7 @@ new file mode 100644
 index 0000000..444e415
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -102,4 +99,3 @@ index 0000000..444e415
 +/*
 + * A comment.
 + */
-+
diff --git a/t/t4211/sha256/expect.parallel-change-f-to-main b/t/t4211/sha256/expect.parallel-change-f-to-main
index c93e03bef4..49f1402e46 100644
--- a/t/t4211/sha256/expect.parallel-change-f-to-main
+++ b/t/t4211/sha256/expect.parallel-change-f-to-main
@@ -15,7 +15,7 @@ diff --git a/b.c b/b.c
 index 62c1fc2..69cb69c 100644
 --- a/b.c
 +++ b/b.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -30,7 +30,6 @@ index 62c1fc2..69cb69c 100644
  /*
   * This is only an example!
   */
- 
 
 commit b511694f5337663fbd697622993a5f8e1099eca84be4df313f2b3ee94a098b42
 Author: Thomas Rast <trast@inf.ethz.ch>
@@ -42,7 +41,7 @@ diff --git a/a.c b/a.c
 index 62c1fc2..e1e8475 100644
 --- a/a.c
 +++ b/a.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -57,7 +56,6 @@ index 62c1fc2..e1e8475 100644
 - * This is only an example!
 + * This is only a short example!
   */
- 
 
 commit 5a1b3989063d55e71e7685efa3392f133385b4034bddde530dcb5090d8b8b8ca
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -69,7 +67,7 @@ diff --git a/a.c b/a.c
 index 75c0119..3a78aaf 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -84,7 +82,6 @@ index 75c0119..3a78aaf 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit ccf97b9878189c40a981da50b15713bb80a35755326320ec80900caf22ced46f
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -96,7 +93,7 @@ diff --git a/a.c b/a.c
 index 7a296b9..75c0119 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -111,7 +108,6 @@ index 7a296b9..75c0119 100644
  /*
   * A comment.
   */
- 
 
 commit f6434acd34260a6c9f61e96d96bf9a323d330561df5b1ca2631104f82026dfed
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -123,7 +119,7 @@ diff --git a/a.c b/a.c
 index 9f550c3..7a296b9 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -137,7 +133,6 @@ index 9f550c3..7a296b9 100644
  /*
   * A comment.
   */
- 
 
 commit 1dd7e9b2b1699324b53b341e728653b913bc192a14dfea168c5b51f2b3d03592
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -150,7 +145,7 @@ new file mode 100644
 index 0000000..9f550c3
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -163,4 +158,3 @@ index 0000000..9f550c3
 +/*
 + * A comment.
 + */
-+
diff --git a/t/t4211/sha256/expect.simple-f-to-main b/t/t4211/sha256/expect.simple-f-to-main
index e67fa017a7..3dd225947e 100644
--- a/t/t4211/sha256/expect.simple-f-to-main
+++ b/t/t4211/sha256/expect.simple-f-to-main
@@ -8,7 +8,7 @@ diff --git a/a.c b/a.c
 index 75c0119..3a78aaf 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -23,7 +23,6 @@ index 75c0119..3a78aaf 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit ccf97b9878189c40a981da50b15713bb80a35755326320ec80900caf22ced46f
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -35,7 +34,7 @@ diff --git a/a.c b/a.c
 index 7a296b9..75c0119 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -50,7 +49,6 @@ index 7a296b9..75c0119 100644
  /*
   * A comment.
   */
- 
 
 commit f6434acd34260a6c9f61e96d96bf9a323d330561df5b1ca2631104f82026dfed
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -62,7 +60,7 @@ diff --git a/a.c b/a.c
 index 9f550c3..7a296b9 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -76,7 +74,6 @@ index 9f550c3..7a296b9 100644
  /*
   * A comment.
   */
- 
 
 commit 1dd7e9b2b1699324b53b341e728653b913bc192a14dfea168c5b51f2b3d03592
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -89,7 +86,7 @@ new file mode 100644
 index 0000000..9f550c3
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -102,4 +99,3 @@ index 0000000..9f550c3
 +/*
 + * A comment.
 + */
-+

base-commit: d38352cd43ab9745686d697872408bc3249a153f
-- 
gitgitgadget

```

## Junio C Hamano, 2026-09-21 17:30

Subject: Re: [PATCH] line-range: skip trailing empty lines in funcname range
Message-ID: <xmqqse32mrzm.fsf@gitster.g>
In-Reply-To: <pull.2234.git.1789991377413.gitgitgadget@gmail.com>

```
"Kristofer Karlsson via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> diff --git a/line-range.c b/line-range.c
> index b99f0d9895..44b52d4e34 100644
> --- a/line-range.c
> +++ b/line-range.c
> @@ -233,6 +233,11 @@ static const char *parse_range_funcname(
>  		(*end)++;
>  	}
>  
> +	/* exclude trailing empty lines from the function range */
> +	while (*end > *begin + 1 &&
> +	       nth_line_cb(cb_data, *end - 1)[0] == '\n')
> +		(*end)--;
> +

While the new behaviour may mean well, the implementation falls a
bit short of matching what "grep -W" did, doesn't it?  Over there we
treat a line with only whitespace characters on it as an empty line
that we want to ignore, but the above code does not allow anything
before the LF.  I do not know offhand if the above misbehaves on
CRLF text files, but if you treated a line with only whitespace
characters on it as an empty line, concerns on CRLF files would also
disappear ;-).



```

## Kristofer Karlsson, 2026-09-21 18:58

Subject: Re: [PATCH] line-range: skip trailing empty lines in funcname range
Message-ID: <CAL71e4OW7=WhkTtzifG2fBNp748HvipW5AJiTOPynwXyo-BFaQ@mail.gmail.com>
In-Reply-To: <xmqqse32mrzm.fsf@gitster.g>

```
On Mon, 21 Sept 2026 at 19:30, Junio C Hamano <gitster@pobox.com> wrote:
>
> "Kristofer Karlsson via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
>
> > diff --git a/line-range.c b/line-range.c
> > index b99f0d9895..44b52d4e34 100644
> > --- a/line-range.c
> > +++ b/line-range.c
> > @@ -233,6 +233,11 @@ static const char *parse_range_funcname(
> >               (*end)++;
> >       }
> >
> > +     /* exclude trailing empty lines from the function range */
> > +     while (*end > *begin + 1 &&
> > +            nth_line_cb(cb_data, *end - 1)[0] == '\n')
> > +             (*end)--;
> > +
>
> While the new behaviour may mean well, the implementation falls a
> bit short of matching what "grep -W" did, doesn't it?  Over there we
> treat a line with only whitespace characters on it as an empty line
> that we want to ignore, but the above code does not allow anything
> before the LF.  I do not know offhand if the above misbehaves on
> CRLF text files, but if you treated a line with only whitespace
> characters on it as an empty line, concerns on CRLF files would also
> disappear ;-).
>

Ah yes, a blank line is not the same as an empty line, good point.

I also noticed the old behavior is still in the documentation
for man git grep:

    -W, --function-context
        Show the surrounding text from the previous line
        containing a function name up to the one before
        the next function name, effectively showing the whole
        function in which the match was found.

And for man git log (in the -L section):

    If :<funcname> is given in place of <start> and <end>,
    it is a regular expression that denotes the range from
    the first funcname line that matches <funcname>, up to
    the next funcname line.  :<funcname> searches from the
    end of the previous -L range, if any, otherwise from the
    start of file.

So neither of these functions should do any blank-line trimming
according to the docs (but the docs can be changed).

So I suppose the question is what behavior we actually want,
and if these two use cases should be analogous or not.

Thanks,
Kristofer

```

## Kristofer Karlsson via GitGitGadget, 2026-09-25 10:35

Subject: [PATCH v2] line-range: skip trailing blank lines in funcname range
Message-ID: <pull.2234.v2.git.1790332529050.gitgitgadget@gmail.com>
In-Reply-To: <pull.2234.git.1789991377413.gitgitgadget@gmail.com>

```
From: Kristofer Karlsson <krka@spotify.com>

git log -L :funcname: includes trailing blank lines in the
function range. This boils down to parse_range_funcname()
extending the range forward until it either reaches end-of-file
or another function, without skipping blank lines at the
boundary. Including blank lines is inconsistent with how it
works for git grep -W.

Fix this by trimming trailing blank lines from the computed range,
with the same goal as this fix (though with a different approach):

    8e5dd94e68 (grep: -W: skip trailing empty lines at EOF, too,
    2024-07-30)

A blank line is one that contains only whitespace characters,
matching the definition used by grep -W.

Reported-by: Nikita Makarov <n.makarov@yadro.com>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
---
    line-range: skip trailing empty lines in funcname range
    
    cc: René Scharfe l.s.r@web.de cc: Nikita Makarov n.makarov@yadro.com cc:
    Kristofer Karlsson krka@spotify.com
    
    Changes since v1:
    
     * Filter out all blank lines (only whitespace characters) instead of
       only filtering empty lines to match how grep -W works. (This also
       makes CRLF line endings work.)
     * Updated tests to include whitespace-only lines (spaces, tabs) in
       addition to empty lines.
     * Rephrased from "empty" to "blank" throughout.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2234%2Fspkrka%2Fkrka%2Fline-range-trailing-blank-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2234/spkrka/krka/line-range-trailing-blank-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/2234

Range-diff vs v1:

 1:  f2e217d968 ! 1:  a55eadf639 line-range: skip trailing empty lines in funcname range
     @@ Metadata
      Author: Kristofer Karlsson <krka@spotify.com>
      
       ## Commit message ##
     -    line-range: skip trailing empty lines in funcname range
     +    line-range: skip trailing blank lines in funcname range
      
     -    git log -L :funcname: includes trailing empty lines in the
     +    git log -L :funcname: includes trailing blank lines in the
          function range. This boils down to parse_range_funcname()
          extending the range forward until it either reaches end-of-file
     -    or another function, without skipping empty lines at the
     -    boundary. Including empty lines is inconsistent with how it
     +    or another function, without skipping blank lines at the
     +    boundary. Including blank lines is inconsistent with how it
          works for git grep -W.
      
     -    Fix this by trimming trailing empty lines from the computed range,
     +    Fix this by trimming trailing blank lines from the computed range,
          with the same goal as this fix (though with a different approach):
      
              8e5dd94e68 (grep: -W: skip trailing empty lines at EOF, too,
              2024-07-30)
      
     +    A blank line is one that contains only whitespace characters,
     +    matching the definition used by grep -W.
     +
          Reported-by: Nikita Makarov <n.makarov@yadro.com>
          Signed-off-by: Kristofer Karlsson <krka@spotify.com>
      
     @@ line-range.c: static const char *parse_range_funcname(
       		(*end)++;
       	}
       
     -+	/* exclude trailing empty lines from the function range */
     -+	while (*end > *begin + 1 &&
     -+	       nth_line_cb(cb_data, *end - 1)[0] == '\n')
     ++	/* exclude trailing blank lines from the function range */
     ++	while (*end > *begin + 1) {
     ++		const char *bol = nth_line_cb(cb_data, *end - 1);
     ++		const char *eol = nth_line_cb(cb_data, *end);
     ++		while (bol < eol && isspace(*bol))
     ++			bol++;
     ++		if (bol < eol)
     ++			break;
      +		(*end)--;
     ++	}
      +
       	regfree(&regexp);
       	if (xecfg)
     @@ t/t4211-line-log.sh: test_expect_success '--summary shows new file on root commi
       	test_grep "create mode 100644 file.c" actual
       '
       
     -+test_expect_success '-L :funcname: excludes trailing empty lines at EOF' '
     -+	git init trailing-empty &&
     ++test_expect_success '-L :funcname: excludes trailing blank lines at EOF' '
     ++	git init trailing-blank &&
      +	(
     -+		cd trailing-empty &&
     ++		cd trailing-blank &&
      +		test_commit --printf --no-tag "add func.py" \
      +			func.py "def foo():\n    return 1\n" &&
     -+		test_commit --printf --no-tag "add trailing empty lines" \
     -+			func.py "def foo():\n    return 1\n\n\n\n" &&
     ++		test_commit --printf --no-tag "add trailing blank lines" \
     ++			func.py "def foo():\n    return 1\n\n  \n\t\n" &&
      +		git log -L :foo:func.py --format="%s" >actual &&
     -+		test_grep ! "add trailing empty lines" actual
     ++		test_grep ! "add trailing blank lines" actual
      +	)
      +'
      +
     -+test_expect_success '-L :funcname: excludes empty lines between functions' '
     -+	git init empty-between-funcs &&
     ++test_expect_success '-L :funcname: excludes blank lines between functions' '
     ++	git init blank-between-funcs &&
      +	(
     -+		cd empty-between-funcs &&
     ++		cd blank-between-funcs &&
      +		test_commit --printf --no-tag "add two funcs" \
      +			func.py "def foo():\n    return 1\n\ndef bar():\n    return 2\n" &&
     -+		test_commit --printf --no-tag "add empty lines between" \
     -+			func.py "def foo():\n    return 1\n\n\n\ndef bar():\n    return 2\n" &&
     ++		test_commit --printf --no-tag "add blank lines between" \
     ++			func.py "def foo():\n    return 1\n\n \n\t\ndef bar():\n    return 2\n" &&
      +		git log -L :foo:func.py --format="%s" >actual &&
     -+		test_grep ! "add empty lines between" actual
     ++		test_grep ! "add blank lines between" actual
      +	)
      +'
      +


 line-range.c                                  | 11 ++++++++
 t/t4211-line-log.sh                           | 26 +++++++++++++++++++
 t/t4211/sha1/expect.parallel-change-f-to-main | 18 +++++--------
 t/t4211/sha1/expect.simple-f-to-main          | 12 +++------
 .../sha256/expect.parallel-change-f-to-main   | 18 +++++--------
 t/t4211/sha256/expect.simple-f-to-main        | 12 +++------
 6 files changed, 57 insertions(+), 40 deletions(-)

diff --git a/line-range.c b/line-range.c
index b99f0d9895..2dceb1cc0c 100644
--- a/line-range.c
+++ b/line-range.c
@@ -233,6 +233,17 @@ static const char *parse_range_funcname(
 		(*end)++;
 	}
 
+	/* exclude trailing blank lines from the function range */
+	while (*end > *begin + 1) {
+		const char *bol = nth_line_cb(cb_data, *end - 1);
+		const char *eol = nth_line_cb(cb_data, *end);
+		while (bol < eol && isspace(*bol))
+			bol++;
+		if (bol < eol)
+			break;
+		(*end)--;
+	}
+
 	regfree(&regexp);
 	if (xecfg)
 		xdiff_clear_find_func(xecfg);
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index d0a834ed8f..0b5538b262 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -781,6 +781,32 @@ test_expect_success '--summary shows new file on root commit' '
 	test_grep "create mode 100644 file.c" actual
 '
 
+test_expect_success '-L :funcname: excludes trailing blank lines at EOF' '
+	git init trailing-blank &&
+	(
+		cd trailing-blank &&
+		test_commit --printf --no-tag "add func.py" \
+			func.py "def foo():\n    return 1\n" &&
+		test_commit --printf --no-tag "add trailing blank lines" \
+			func.py "def foo():\n    return 1\n\n  \n\t\n" &&
+		git log -L :foo:func.py --format="%s" >actual &&
+		test_grep ! "add trailing blank lines" actual
+	)
+'
+
+test_expect_success '-L :funcname: excludes blank lines between functions' '
+	git init blank-between-funcs &&
+	(
+		cd blank-between-funcs &&
+		test_commit --printf --no-tag "add two funcs" \
+			func.py "def foo():\n    return 1\n\ndef bar():\n    return 2\n" &&
+		test_commit --printf --no-tag "add blank lines between" \
+			func.py "def foo():\n    return 1\n\n \n\t\ndef bar():\n    return 2\n" &&
+		git log -L :foo:func.py --format="%s" >actual &&
+		test_grep ! "add blank lines between" actual
+	)
+'
+
 test_expect_success 'get_commit_action() does not mutate a not-yet-walked commit' '
 	git init peek &&
 	(
diff --git a/t/t4211/sha1/expect.parallel-change-f-to-main b/t/t4211/sha1/expect.parallel-change-f-to-main
index 6d7a201036..cb2f6bcbac 100644
--- a/t/t4211/sha1/expect.parallel-change-f-to-main
+++ b/t/t4211/sha1/expect.parallel-change-f-to-main
@@ -15,7 +15,7 @@ diff --git a/b.c b/b.c
 index 5de3ea4..bf79c2f 100644
 --- a/b.c
 +++ b/b.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -30,7 +30,6 @@ index 5de3ea4..bf79c2f 100644
  /*
   * This is only an example!
   */
- 
 
 commit ba227c6632349700fbb957dec2b50f5e2358be3f
 Author: Thomas Rast <trast@inf.ethz.ch>
@@ -42,7 +41,7 @@ diff --git a/a.c b/a.c
 index 5de3ea4..01b5b65 100644
 --- a/a.c
 +++ b/a.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -57,7 +56,6 @@ index 5de3ea4..01b5b65 100644
 - * This is only an example!
 + * This is only a short example!
   */
- 
 
 commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -69,7 +67,7 @@ diff --git a/a.c b/a.c
 index e51de13..bdb2bb1 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -84,7 +82,6 @@ index e51de13..bdb2bb1 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -96,7 +93,7 @@ diff --git a/a.c b/a.c
 index 3233403..e51de13 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -111,7 +108,6 @@ index 3233403..e51de13 100644
  /*
   * A comment.
   */
- 
 
 commit f04fb20f2c77850996cba739709acc6faecc58f7
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -123,7 +119,7 @@ diff --git a/a.c b/a.c
 index 444e415..3233403 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -137,7 +133,6 @@ index 444e415..3233403 100644
  /*
   * A comment.
   */
- 
 
 commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -150,7 +145,7 @@ new file mode 100644
 index 0000000..444e415
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -163,4 +158,3 @@ index 0000000..444e415
 +/*
 + * A comment.
 + */
-+
diff --git a/t/t4211/sha1/expect.simple-f-to-main b/t/t4211/sha1/expect.simple-f-to-main
index cd92100dfc..99404cdc40 100644
--- a/t/t4211/sha1/expect.simple-f-to-main
+++ b/t/t4211/sha1/expect.simple-f-to-main
@@ -8,7 +8,7 @@ diff --git a/a.c b/a.c
 index e51de13..bdb2bb1 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -23,7 +23,6 @@ index e51de13..bdb2bb1 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -35,7 +34,7 @@ diff --git a/a.c b/a.c
 index 3233403..e51de13 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -50,7 +49,6 @@ index 3233403..e51de13 100644
  /*
   * A comment.
   */
- 
 
 commit f04fb20f2c77850996cba739709acc6faecc58f7
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -62,7 +60,7 @@ diff --git a/a.c b/a.c
 index 444e415..3233403 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -76,7 +74,6 @@ index 444e415..3233403 100644
  /*
   * A comment.
   */
- 
 
 commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -89,7 +86,7 @@ new file mode 100644
 index 0000000..444e415
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -102,4 +99,3 @@ index 0000000..444e415
 +/*
 + * A comment.
 + */
-+
diff --git a/t/t4211/sha256/expect.parallel-change-f-to-main b/t/t4211/sha256/expect.parallel-change-f-to-main
index c93e03bef4..49f1402e46 100644
--- a/t/t4211/sha256/expect.parallel-change-f-to-main
+++ b/t/t4211/sha256/expect.parallel-change-f-to-main
@@ -15,7 +15,7 @@ diff --git a/b.c b/b.c
 index 62c1fc2..69cb69c 100644
 --- a/b.c
 +++ b/b.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -30,7 +30,6 @@ index 62c1fc2..69cb69c 100644
  /*
   * This is only an example!
   */
- 
 
 commit b511694f5337663fbd697622993a5f8e1099eca84be4df313f2b3ee94a098b42
 Author: Thomas Rast <trast@inf.ethz.ch>
@@ -42,7 +41,7 @@ diff --git a/a.c b/a.c
 index 62c1fc2..e1e8475 100644
 --- a/a.c
 +++ b/a.c
-@@ -4,14 +4,14 @@
+@@ -4,13 +4,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -57,7 +56,6 @@ index 62c1fc2..e1e8475 100644
 - * This is only an example!
 + * This is only a short example!
   */
- 
 
 commit 5a1b3989063d55e71e7685efa3392f133385b4034bddde530dcb5090d8b8b8ca
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -69,7 +67,7 @@ diff --git a/a.c b/a.c
 index 75c0119..3a78aaf 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -84,7 +82,6 @@ index 75c0119..3a78aaf 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit ccf97b9878189c40a981da50b15713bb80a35755326320ec80900caf22ced46f
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -96,7 +93,7 @@ diff --git a/a.c b/a.c
 index 7a296b9..75c0119 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -111,7 +108,6 @@ index 7a296b9..75c0119 100644
  /*
   * A comment.
   */
- 
 
 commit f6434acd34260a6c9f61e96d96bf9a323d330561df5b1ca2631104f82026dfed
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -123,7 +119,7 @@ diff --git a/a.c b/a.c
 index 9f550c3..7a296b9 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -137,7 +133,6 @@ index 9f550c3..7a296b9 100644
  /*
   * A comment.
   */
- 
 
 commit 1dd7e9b2b1699324b53b341e728653b913bc192a14dfea168c5b51f2b3d03592
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -150,7 +145,7 @@ new file mode 100644
 index 0000000..9f550c3
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -163,4 +158,3 @@ index 0000000..9f550c3
 +/*
 + * A comment.
 + */
-+
diff --git a/t/t4211/sha256/expect.simple-f-to-main b/t/t4211/sha256/expect.simple-f-to-main
index e67fa017a7..3dd225947e 100644
--- a/t/t4211/sha256/expect.simple-f-to-main
+++ b/t/t4211/sha256/expect.simple-f-to-main
@@ -8,7 +8,7 @@ diff --git a/a.c b/a.c
 index 75c0119..3a78aaf 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
  long f(long x)
  {
  	int s = 0;
@@ -23,7 +23,6 @@ index 75c0119..3a78aaf 100644
 - * A comment.
 + * This is only an example!
   */
- 
 
 commit ccf97b9878189c40a981da50b15713bb80a35755326320ec80900caf22ced46f
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -35,7 +34,7 @@ diff --git a/a.c b/a.c
 index 7a296b9..75c0119 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,14 +3,14 @@
+@@ -3,13 +3,13 @@
 -int f(int x)
 +long f(long x)
  {
@@ -50,7 +49,6 @@ index 7a296b9..75c0119 100644
  /*
   * A comment.
   */
- 
 
 commit f6434acd34260a6c9f61e96d96bf9a323d330561df5b1ca2631104f82026dfed
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -62,7 +60,7 @@ diff --git a/a.c b/a.c
 index 9f550c3..7a296b9 100644
 --- a/a.c
 +++ b/a.c
-@@ -3,13 +3,14 @@
+@@ -3,12 +3,13 @@
  int f(int x)
  {
  	int s = 0;
@@ -76,7 +74,6 @@ index 9f550c3..7a296b9 100644
  /*
   * A comment.
   */
- 
 
 commit 1dd7e9b2b1699324b53b341e728653b913bc192a14dfea168c5b51f2b3d03592
 Author: Thomas Rast <trast@student.ethz.ch>
@@ -89,7 +86,7 @@ new file mode 100644
 index 0000000..9f550c3
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +3,13 @@
+@@ -0,0 +3,12 @@
 +int f(int x)
 +{
 +	int s = 0;
@@ -102,4 +99,3 @@ index 0000000..9f550c3
 +/*
 + * A comment.
 + */
-+

base-commit: d38352cd43ab9745686d697872408bc3249a153f
-- 
gitgitgadget

```
