Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ TESTS = tests/newline1/run-test \
tests/grepdiff7/run-test \
tests/grepdiff8/run-test \
tests/grepdiff9/run-test \
tests/grepdiff-original-line-numbers/run-test \
tests/number1/run-test \
tests/number2/run-test \
tests/number3/run-test \
Expand Down
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Patchutils news
warnings, unused result warnings, and locale-related test failures.
Updated documentation and example spec file.

Added new --as-numbered-lines options: original-before and original-after.
These preserve original line numbers from the diff context, useful for
CI/CD systems that need to report errors on exact line numbers from the
original diff. Addresses GitHub issue #55.

0.4.2 (stable)

Build system improvements: only run xmlto once during documentation
Expand Down
4 changes: 2 additions & 2 deletions bash-completion-patchutils
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ _filterdiff() {
return 0
;;
--as-numbered-lines)
COMPREPLY=($(compgen -W "before after" -- "$cur"))
COMPREPLY=($(compgen -W "before after original-before original-after" -- "$cur"))
return 0
;;
--format)
Expand Down Expand Up @@ -141,7 +141,7 @@ _grepdiff() {
return 0
;;
--as-numbered-lines)
COMPREPLY=($(compgen -W "before after" -- "$cur"))
COMPREPLY=($(compgen -W "before after original-before original-after" -- "$cur"))
return 0
;;
--format)
Expand Down
24 changes: 22 additions & 2 deletions doc/patchutils.xml
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@
</varlistentry>

<varlistentry>
<term><option>--as-numbered-lines</option>=before|after</term>
<term><option>--as-numbered-lines</option>=before|after|original-before|original-after</term>
<listitem>
<para>Instead of a patch fragment, display the lines of
the selected hunks with the line number of the file
Expand All @@ -897,6 +897,13 @@
beginning of each line. Each hunk except the first
will have a line consisting of <quote>...</quote>
before it.</para>
<para>The <literal>before</literal> and <literal>after</literal>
options show line numbers adjusted for any skipped hunks.
The <literal>original-before</literal> and <literal>original-after</literal>
options show line numbers as they appear in the original diff,
preserving the original line number context. This is useful for
CI/CD systems that need to report errors on the exact line numbers
from the original diff.</para>
</listitem>
</varlistentry>

Expand Down Expand Up @@ -1022,6 +1029,12 @@
<screen><![CDATA[filterdiff --as-numbered-lines=before
patch.file]]></screen></para>

<para>For CI/CD systems that need line numbers matching the original
diff context (useful for error reporting), use the original-* variants:

<screen><![CDATA[grepdiff pattern --output-matching=hunk \
--as-numbered-lines=original-after patch.file]]></screen></para>

<para>Filterdiff can also be used to convert between unified
and context format diffs:

Expand Down Expand Up @@ -2458,7 +2471,7 @@ will pipe patch of file #2 to vim - -R
</varlistentry>

<varlistentry>
<term><option>--as-numbered-lines</option>=before|after</term>
<term><option>--as-numbered-lines</option>=before|after|original-before|original-after</term>
<listitem>
<para>Instead of a patch fragment, display the lines of
the selected hunks with the line number of the file
Expand All @@ -2467,6 +2480,13 @@ will pipe patch of file #2 to vim - -R
beginning of each line. Each hunk except the first
will have a line consisting of <quote>...</quote>
before it.</para>
<para>The <literal>before</literal> and <literal>after</literal>
options show line numbers adjusted for any skipped hunks.
The <literal>original-before</literal> and <literal>original-after</literal>
options show line numbers as they appear in the original diff,
preserving the original line number context. This is useful for
CI/CD systems that need to report errors on the exact line numbers
from the original diff.</para>
</listitem>
</varlistentry>

Expand Down
78 changes: 64 additions & 14 deletions src/filterdiff.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ struct range {
enum line_numbering {
None = 0,
Before,
After
After,
OriginalBefore,
OriginalAfter
};

enum {
Expand Down Expand Up @@ -443,9 +445,9 @@ do_unified (FILE *f, char **header, unsigned int num_headers,
unsigned int i;
for (i = 0; i < num_headers - 2; i++)
output_header_line (header[i]);
if (number_lines != After)
if (number_lines != After && number_lines != OriginalAfter)
output_header_line (header[num_headers - 2]);
if (number_lines != Before)
if (number_lines != Before && number_lines != OriginalBefore)
output_header_line (header[num_headers - 1]);
header_displayed = 1;
}
Expand Down Expand Up @@ -497,6 +499,22 @@ do_unified (FILE *f, char **header, unsigned int num_headers,
hunknum > 1))
fputs ("...\n", output_to);
break;
case OriginalBefore:
// Note the initial line number (original, no munge)
track_linenum = orig_offset;
if (!first_hunk ||
(output_matching == output_file &&
hunknum > 1))
fputs ("...\n", output_to);
break;
case OriginalAfter:
// Note the initial line number (original, no munge)
track_linenum = new_offset;
if (!first_hunk ||
(output_matching == output_file &&
hunknum > 1))
fputs ("...\n", output_to);
break;
}
} else if (mode == mode_filter)
// We are missing this hunk out, but
Expand Down Expand Up @@ -542,9 +560,9 @@ do_unified (FILE *f, char **header, unsigned int num_headers,
unsigned int i;
for (i = 0; i < num_headers - 2; i++)
output_header_line (header[i]);
if (number_lines != After)
if (number_lines != After && number_lines != OriginalAfter)
output_header_line (header[num_headers - 2]);
if (number_lines != Before)
if (number_lines != Before && number_lines != OriginalBefore)
output_header_line (header[num_headers - 1]);
header_displayed = 1;
}
Expand Down Expand Up @@ -573,7 +591,9 @@ do_unified (FILE *f, char **header, unsigned int num_headers,
// Just display each line.
fwrite (*line, (size_t) got, 1, output_to);
else if ((number_lines == Before && **line != '+') ||
(number_lines == After && **line != '-')) {
(number_lines == After && **line != '-') ||
(number_lines == OriginalBefore && **line != '+') ||
(number_lines == OriginalAfter && **line != '-')) {
// Numbered line.
const char *rest = *line;
if (rest[0] != '\n')
Expand Down Expand Up @@ -759,9 +779,9 @@ do_context (FILE *f, char **header, unsigned int num_headers,
unsigned int i;
for (i = 0; i < num_headers - 2; i++)
output_header_line (header[i]);
if (number_lines != After)
if (number_lines != After && number_lines != OriginalAfter)
output_header_line (header[num_headers - 2]);
if (number_lines != Before)
if (number_lines != Before && number_lines != OriginalBefore)
output_header_line (header[num_headers - 1]);
header_displayed = 1;
}
Expand Down Expand Up @@ -820,6 +840,30 @@ do_context (FILE *f, char **header, unsigned int num_headers,
hunknum > 1))
fputs ("...\n", output_to);
break;

case OriginalBefore:
if (i != 0)
break;

// Note the initial line number (original, no munge).
track_linenum = line_start;
if (!first_hunk ||
(output_matching == output_file &&
hunknum > 1))
fputs ("...\n", output_to);
break;

case OriginalAfter:
if (i != 1)
break;

// Note the initial line number (original, no munge).
track_linenum = line_start;
if (!first_hunk ||
(output_matching == output_file &&
hunknum > 1))
fputs ("...\n", output_to);
break;
}
}

Expand Down Expand Up @@ -866,9 +910,9 @@ do_context (FILE *f, char **header, unsigned int num_headers,
unsigned int i;
for (i = 0; i < num_headers - 2; i++)
output_header_line (header[i]);
if (number_lines != After)
if (number_lines != After && number_lines != OriginalAfter)
output_header_line (header[num_headers - 2]);
if (number_lines != Before)
if (number_lines != Before && number_lines != OriginalBefore)
output_header_line (header[num_headers - 1]);
header_displayed = 1;
}
Expand Down Expand Up @@ -927,7 +971,9 @@ do_context (FILE *f, char **header, unsigned int num_headers,
fwrite (*line, (size_t) got,
1, output_to);
else if ((number_lines == Before && !i) ||
(number_lines == After && i)) {
(number_lines == After && i) ||
(number_lines == OriginalBefore && !i) ||
(number_lines == OriginalAfter && i)) {
fprintf (output_to, "%lu\t:",
track_linenum++);
fwrite (2 + *line, (size_t) got - 2,
Expand Down Expand Up @@ -1217,9 +1263,9 @@ const char * syntax_str =
" include only files in range F, if range begins with x show all excluding range F\n"
" --annotate (filterdiff, patchview, grepdiff)\n"
" annotate each hunk with the filename and hunk number (filterdiff, patchview, grepdiff)\n"
" --as-numbered-lines=before|after (filterdiff, patchview, grepdiff)\n"
" display lines as they would look before, or after, the (filterdiff, patchview, grepdiff)\n"
" patch is applied (filterdiff, patchview, grepdiff)\n"
" --as-numbered-lines=before|after|original-before|original-after (filterdiff, patchview, grepdiff)\n"
" display lines as they would look before, or after, the patch is applied;\n"
" or with original line numbers from the diff (original-before/original-after)\n"
" --format=context|unified (filterdiff, patchview, grepdiff)\n"
" set output format (filterdiff, patchview, grepdiff)\n"
" --output-matching=hunk|file (grepdiff)\n"
Expand Down Expand Up @@ -1632,6 +1678,10 @@ int main (int argc, char *argv[])
number_lines = Before;
else if (!strcmp (optarg, "after"))
number_lines = After;
else if (!strcmp (optarg, "original-before"))
number_lines = OriginalBefore;
else if (!strcmp (optarg, "original-after"))
number_lines = OriginalAfter;
else syntax (1);
break;
case 1000 + 'a':
Expand Down
75 changes: 75 additions & 0 deletions tests/grepdiff-original-line-numbers/run-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/sh

# Test for grepdiff --as-numbered-lines=original-* options
# Tests the new original-before and original-after options that preserve
# original line numbers from the diff (useful for CI/CD error reporting)
# Addresses GitHub issue #55

. ${top_srcdir-.}/tests/common.sh

# Create a test diff that reproduces the issue from the GitHub issue
cat << EOF > diff
diff --git a/foobar.txt b/foobar.txt
index 8a19eed..ae745cf 100644
--- a/foobar.txt
+++ b/foobar.txt
@@ -0,0 +1,4 @@
+# pre-comment
+# spread over
+# three lines
+
@@ -8 +12 @@
-foo()
+foo(bar)
EOF

# Test --output-matching=hunk (shows adjusted line numbers in hunk headers)
${GREPDIFF} foo --output-matching=hunk diff 2>errors >hunk_output || exit 1
[ -s errors ] && exit 1

# The hunk output shows adjusted line numbers (this is the existing behavior)
cat << EOF | cmp - hunk_output || exit 1
diff --git a/foobar.txt b/foobar.txt
index 8a19eed..ae745cf 100644
--- a/foobar.txt
+++ b/foobar.txt
@@ -8 +8 @@
-foo()
+foo(bar)
EOF

# Test --as-numbered-lines=original-after (the new option for this use case)
${GREPDIFF} foo --output-matching=hunk --only-match=additions --as-numbered-lines=original-after diff 2>errors2 >numbered_output || exit 1
[ -s errors2 ] && exit 1

# The expected output should show line 12 (original line number from diff)
cat << EOF | cmp - numbered_output || exit 1
diff --git a/foobar.txt b/foobar.txt
index 8a19eed..ae745cf 100644
+++ b/foobar.txt
12 :foo(bar)
EOF

# Test --as-numbered-lines=original-before
${GREPDIFF} foo --output-matching=hunk --only-match=additions --as-numbered-lines=original-before diff 2>errors3 >numbered_before_output || exit 1
[ -s errors3 ] && exit 1

# This should show line 8 for the "before" version (original line number from diff)
cat << EOF | cmp - numbered_before_output || exit 1
diff --git a/foobar.txt b/foobar.txt
index 8a19eed..ae745cf 100644
--- a/foobar.txt
8 :foo()
EOF

# Test that regular --as-numbered-lines=after still works with adjusted line numbers
${GREPDIFF} foo --output-matching=hunk --only-match=additions --as-numbered-lines=after diff 2>errors4 >numbered_adjusted_output || exit 1
[ -s errors4 ] && exit 1

# This should show line 8 (adjusted line number, old behavior)
cat << EOF | cmp - numbered_adjusted_output || exit 1
diff --git a/foobar.txt b/foobar.txt
index 8a19eed..ae745cf 100644
+++ b/foobar.txt
8 :foo(bar)
EOF