]> git.ipfire.org Git - thirdparty/git.git/commitdiff
line-log: show all line ranges touched by the same diff range
authorSZEDER Gábor <szeder.dev@gmail.com>
Mon, 18 Aug 2025 11:13:10 +0000 (13:13 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 20 Aug 2025 20:48:21 +0000 (13:48 -0700)
When line-level log is invoked with more than one disjoint line range
in the same file, and one of the commits happens to change that file
such that one diff range modifies more than one line range, then
changes to all modified line ranges should be shown, but only the
changes in the first modified line range are:

  $ git log --oneline -p
  80ca903 (HEAD -> master) Initial
  diff --git a/file b/file
  new file mode 100644
  index 0000000..00935f1
  --- /dev/null
  +++ b/file
  @@ -0,0 +1,10 @@
  +Line 1
  +Line 2
  +Line 3
  +Line 4
  +Line 5
  +Line 6
  +Line 7
  +Line 8
  +Line 9
  +Line 10
  $ git log --oneline -L1,2:file -L4,5:file -L7,8:file
  80ca903 (HEAD -> master) Initial

  diff --git a/file b/file
  --- /dev/null
  +++ b/file
  @@ -0,0 +1,2 @@
  +Line 1
  +Line 2

The line-log-specific diff printer is already clever enough to handle
the case when one line range covers multiple diff ranges, but the
possibility of one diff range touching multiple disjoint line ranges
was apparently overlooked.

Add the necessary condition to dump_diff_hacky_one() to handle this case
as well, and show all modified line ranges:

  $ git log --oneline -L1,2:file -L4,5:file -L7,8:file
  0f9a5b4 (HEAD -> master) Initial

  diff --git a/file b/file
  --- /dev/null
  +++ b/file
  @@ -0,0 +1,2 @@
  +Line 1
  +Line 2
  @@ -0,0 +4,2 @@
  +Line 4
  +Line 5
  @@ -0,0 +7,2 @@
  +Line 7
  +Line 8

This bug was already present in the initial line-log implementation
added in 2da1d1f6f (Implement line-history search (git log -L),
2013-03-28).  Interestingly, that commit already contained a canned
test case covering a similar scenario:

  "-L '/long f/',/^}/:a.c -L /main/,/^}/:a.c simple"

This test case looks for two line ranges in the same file, and both
trace back disjointly to the test repository's inital commit,
therefore changes to both line ranges should have been shown for the
initial commit, but only changes for the first line range are shown.
So this test case should have failed from the very beginning, but it
never did, because, unfortunately, the canned expected result is
incorrect, as it doesn't include changes for the second line range.

A similar test with a similarly incorrect canned expected result was
added later in 209618860c (log -L: fix overlapping input ranges,
2013-04-05).

Correct these two canned expected results to contain the changes for
the second line range for the initial commit as well.

Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
line-log.c
t/t4211/sha1/expect.multiple
t/t4211/sha1/expect.two-ranges
t/t4211/sha256/expect.multiple
t/t4211/sha256/expect.two-ranges

index 9cb8ea1484ae847ffef0b11222d54f7eef56f9de..9b75b4ac39a1eb7e62c16d580bc247c64e7ee355 100644 (file)
@@ -939,6 +939,15 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
                long t_cur = t_start;
                unsigned int j_last;
 
+               /*
+                * If a diff range touches multiple line ranges, then all
+                * those line ranges should be shown, so take a step back if
+                * the current line range is still in the previous diff range
+                * (even if only partially).
+                */
+               if (j > 0 && diff->target.ranges[j-1].end > t_start)
+                       j--;
+
                while (j < diff->target.nr && diff->target.ranges[j].end < t_start)
                        j++;
                if (j == diff->target.nr || diff->target.ranges[j].start >= t_end)
index 76ad5b598cb8ddac27b42e743db594241ba0fd57..1eee8a7801055d974a89e40adb7c22e65b19b8fb 100644 (file)
@@ -102,3 +102,9 @@ diff --git a/a.c b/a.c
 +              s++;
 +      }
 +}
+@@ -0,0 +16,5 @@
++int main ()
++{
++      printf("%d\n", f(15));
++      return 0;
++}
index 6109aa0dcee7599486ab83ff552986d3a738dc17..c5164f3be3a28715ad619b4d4ddde8a566abfe26 100644 (file)
@@ -100,3 +100,9 @@ diff --git a/a.c b/a.c
 +              s++;
 +      }
 +}
+@@ -0,0 +16,5 @@
++int main ()
++{
++      printf("%d\n", f(15));
++      return 0;
++}
index ca00409b9a39b2082d1fb216c3aebb42682c11f5..dbd987b74a451f26f9c8a6df267360538efc3b02 100644 (file)
@@ -102,3 +102,9 @@ diff --git a/a.c b/a.c
 +              s++;
 +      }
 +}
+@@ -0,0 +16,5 @@
++int main ()
++{
++      printf("%d\n", f(15));
++      return 0;
++}
index af57c8b9978383d0aedfc48946900d2ed835c137..6a94d3b9cba2dd9691437617904096492ba3c755 100644 (file)
@@ -100,3 +100,9 @@ diff --git a/a.c b/a.c
 +              s++;
 +      }
 +}
+@@ -0,0 +16,5 @@
++int main ()
++{
++      printf("%d\n", f(15));
++      return 0;
++}