]> git.ipfire.org Git - thirdparty/git.git/commitdiff
grep: fix --column --only-match for 2nd and later matches
authorRené Scharfe <l.s.r@web.de>
Fri, 24 Apr 2026 21:04:27 +0000 (23:04 +0200)
committerJunio C Hamano <gitster@pobox.com>
Sat, 25 Apr 2026 10:23:23 +0000 (19:23 +0900)
"git grep --column --only-match" shows the 1-based column number of the
first match on each line, but confusing numbers for further matches.
Example:

   $ echo 123456789012345678901234567890 >file
   $ for d in 1 2 3 4 5 6 7 8 9 0
     do
       git grep --no-index --column --only-matching $d file |
       awk -v FS=: -v l=$d: '{l = l sprintf("%3s", $2)} END {print l}'
     done
   1:  1  2 12
   2:  2  4 14
   3:  3  6 16
   4:  4  8 18
   5:  5 10 20
   6:  6 12 22
   7:  7 14 24
   8:  8 16 26
   9:  9 18 28
   0: 10 20 30

Report the column number of each match instead:

   $ for d in 1 2 3 4 5 6 7 8 9 0
     do
       ./git grep --no-index --column --only-matching $d file |
       awk -v FS=: -v l=$d: '{l = l sprintf("%3s", $2)} END {print l}'
     done
   1:  1 11 21
   2:  2 12 22
   3:  3 13 23
   4:  4 14 24
   5:  5 15 25
   6:  6 16 26
   7:  7 17 27
   8:  8 18 28
   9:  9 19 29
   0: 10 20 30

We need to adjust the test in t7810 as well.  The file it uses has the
following five lines; I add a line highlighting the matches and a ruler
at the bottom here, to make it easier to see that the second "mmap"
indeed starts at column 14:

foo mmap bar
foo_mmap bar
foo_mmap bar mmap
foo mmap bar_mmap
foo_mmap bar mmap baz
    ====     ====
123456789 123456789 1

Reported-by: Brandon Chinn <brandonchinn178@gmail.com>
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
grep.c
t/t7810-grep.sh

diff --git a/grep.c b/grep.c
index c7e1dc1e0ee4fea88f9e768ea04401320a497ea9..a54e5d86a96cfdfd100d061a8ceb6165a7cc6b82 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1267,6 +1267,7 @@ static void show_line(struct grep_opt *opt,
                regmatch_t match;
                enum grep_context ctx = GREP_CONTEXT_BODY;
                int eflags = 0;
+               const char *start = bol;
 
                if (want_color(opt->color)) {
                        if (sign == ':')
@@ -1285,6 +1286,7 @@ static void show_line(struct grep_opt *opt,
                        if (match.rm_so == match.rm_eo)
                                break;
 
+                       cno = bol - start + match.rm_so + 1;
                        if (opt->only_matching)
                                show_line_header(opt, name, lno, cno, sign);
                        else
@@ -1294,7 +1296,6 @@ static void show_line(struct grep_opt *opt,
                        if (opt->only_matching)
                                opt->output(opt, "\n", 1);
                        bol += match.rm_eo;
-                       cno += match.rm_eo;
                        rest -= match.rm_eo;
                        eflags = REG_NOTBOL;
                }
index 64ac4f04ee97ad5ec51a17f240ad3fccb17c559f..bd439563d6f149399e513a9aab80002a764561db 100755 (executable)
@@ -322,11 +322,11 @@ do
                ${HC}file:1:5:mmap
                ${HC}file:2:5:mmap
                ${HC}file:3:5:mmap
-               ${HC}file:3:13:mmap
+               ${HC}file:3:14:mmap
                ${HC}file:4:5:mmap
-               ${HC}file:4:13:mmap
+               ${HC}file:4:14:mmap
                ${HC}file:5:5:mmap
-               ${HC}file:5:13:mmap
+               ${HC}file:5:14:mmap
                EOF
                git grep --column -n -o -e mmap $H >actual &&
                test_cmp expected actual