Skip to content

Commit 0e9ce17

Browse files
committed
Merge branch '0.4.x' of github.com:twaugh/patchutils
2 parents f8f5f99 + 9f5678c commit 0e9ce17

7 files changed

Lines changed: 251 additions & 76 deletions

File tree

Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ TESTS = tests/newline1/run-test \
412412
tests/whitespace-regression/run-test \
413413
tests/interdiff-whitespace-w/run-test \
414414
tests/interdiff-color-context/run-test \
415+
tests/interdiff-patch2-headers/run-test \
416+
tests/interdiff-mode-only/run-test \
415417
tests/patch-ignore-whitespace/run-test \
416418
tests/whitespace-w/run-test \
417419
tests/filterdiff-inplace1/run-test \

bash-completion-patchutils

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,3 +452,5 @@ complete -F _gitdiff gitdiff
452452
complete -F _svndiff svndiff
453453
complete -F _gitdiffview gitdiffview
454454
complete -F _svndiffview svndiffview
455+
complete -F _gitdiff gitshow
456+
complete -F _gitdiff gitshowview

doc/patchutils.xml

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -962,14 +962,7 @@ patch.file]]></screen></para>
962962

963963
<screen><![CDATA[filterdiff -v --format=unified context.diff]]></screen></para>
964964
<para>Git format diffs are fully supported, including binary files,
965-
file renames, and permission mode changes. For example, to extract
966-
only the renames from a git diff:
967-
968-
<screen><![CDATA[# With --git-prefixes=strip (matches bare filename)
969-
filterdiff --git-prefixes=strip -i '*/newname' git-patch-with-renames.patch
970-
971-
# With --git-prefixes=keep (default, matches with b/ prefix)
972-
filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]></screen></para>
965+
file renames, and permission mode changes.</para>
973966
</refsect1>
974967
<refsect1>
975968
<title>See also</title>
@@ -1086,6 +1079,8 @@ filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]></screen></para>
10861079
<arg choice="opt">--strip=<replaceable>n</replaceable></arg>
10871080
<arg choice="opt">--git-prefixes=<replaceable>strip|keep</replaceable></arg>
10881081
<arg choice="opt">--addprefix=<replaceable>PREFIX</replaceable></arg>
1082+
<arg choice="opt">--addoldprefix=<replaceable>PREFIX</replaceable></arg>
1083+
<arg choice="opt">--addnewprefix=<replaceable>PREFIX</replaceable></arg>
10891084
<group choice="opt">
10901085
<arg>-s</arg>
10911086
<arg>--status</arg>
@@ -1098,10 +1093,18 @@ filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]></screen></para>
10981093
<arg>-i <replaceable>PATTERN</replaceable></arg>
10991094
<arg>--include=<replaceable>PATTERN</replaceable></arg>
11001095
</group>
1096+
<group choice="opt">
1097+
<arg>-I <replaceable>FILE</replaceable></arg>
1098+
<arg>--include-from-file=<replaceable>FILE</replaceable></arg>
1099+
</group>
11011100
<group choice="opt">
11021101
<arg>-x <replaceable>PATTERN</replaceable></arg>
11031102
<arg>--exclude=<replaceable>PATTERN</replaceable></arg>
11041103
</group>
1104+
<group choice="opt">
1105+
<arg>-X <replaceable>FILE</replaceable></arg>
1106+
<arg>--exclude-from-file=<replaceable>FILE</replaceable></arg>
1107+
</group>
11051108
<group>
11061109
<arg>-z</arg>
11071110
<arg>--decompress</arg>
@@ -1269,6 +1272,22 @@ filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]></screen></para>
12691272
it.</para>
12701273
</listitem>
12711274
</varlistentry>
1275+
<varlistentry>
1276+
<term><option>--addoldprefix</option>=<replaceable>PREFIX</replaceable></term>
1277+
<listitem>
1278+
<para>Prefix pathnames for old files with
1279+
<replaceable>PREFIX</replaceable> before displaying
1280+
them.</para>
1281+
</listitem>
1282+
</varlistentry>
1283+
<varlistentry>
1284+
<term><option>--addnewprefix</option>=<replaceable>PREFIX</replaceable></term>
1285+
<listitem>
1286+
<para>Prefix pathnames for new files with
1287+
<replaceable>PREFIX</replaceable> before displaying
1288+
them.</para>
1289+
</listitem>
1290+
</varlistentry>
12721291
<varlistentry>
12731292
<term><option>-s</option>, <option>--status</option></term>
12741293
<listitem>
@@ -1298,6 +1317,14 @@ filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]></screen></para>
12981317
<replaceable>PATTERN</replaceable>.</para>
12991318
</listitem>
13001319
</varlistentry>
1320+
<varlistentry>
1321+
<term><option>-I</option><replaceable>FILE</replaceable>,
1322+
<option>--include-from-file=<replaceable>FILE</replaceable></option></term>
1323+
<listitem>
1324+
<para>Include only files matching any pattern listed in
1325+
<replaceable>FILE</replaceable>, one pattern per line.</para>
1326+
</listitem>
1327+
</varlistentry>
13011328
<varlistentry>
13021329
<term><option>-x</option><replaceable>PATTERN</replaceable>,
13031330
<option>--exclude=<replaceable>PATTERN</replaceable></option></term>
@@ -1306,6 +1333,14 @@ filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]></screen></para>
13061333
<replaceable>PATTERN</replaceable>.</para>
13071334
</listitem>
13081335
</varlistentry>
1336+
<varlistentry>
1337+
<term><option>-X</option><replaceable>FILE</replaceable>,
1338+
<option>--exclude-from-file=<replaceable>FILE</replaceable></option></term>
1339+
<listitem>
1340+
<para>Exclude files matching any pattern listed in
1341+
<replaceable>FILE</replaceable>, one pattern per line.</para>
1342+
</listitem>
1343+
</varlistentry>
13091344
<varlistentry>
13101345
<term><option>-z</option>,
13111346
<option>--decompress</option></term>
@@ -2022,6 +2057,7 @@ This is the same as gitdiff but uses git show instead of git diff.
20222057
<arg>-s</arg>
20232058
<arg>--status</arg>
20242059
</group>
2060+
<arg choice="opt">--empty-files-as-absent</arg>
20252061
<group choice="opt">
20262062
<arg>-i <replaceable>PATTERN</replaceable></arg>
20272063
<arg>--include=<replaceable>PATTERN</replaceable></arg>
@@ -2198,6 +2234,12 @@ This is the same as gitdiff but uses git show instead of git diff.
21982234
<quote>!</quote>.</para>
21992235
</listitem>
22002236
</varlistentry>
2237+
<varlistentry>
2238+
<term><option>--empty-files-as-absent</option></term>
2239+
<listitem>
2240+
<para>Treat empty files as absent when matching patterns.</para>
2241+
</listitem>
2242+
</varlistentry>
22012243
<varlistentry>
22022244
<term><option>-i</option><replaceable>PATTERN</replaceable>,
22032245
<option>--include=<replaceable>PATTERN</replaceable></option></term>

src/filterdiff.c

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,34 +1599,34 @@ const char * syntax_str =
15991599
" --lines=L include only hunks with (original) lines in range L, if range begins with x show all excluding range L\n"
16001600
" -F F, --files=F\n"
16011601
" include only files in range F, if range begins with x show all excluding range F\n"
1602-
" --annotate (filterdiff, patchview, grepdiff)\n"
1603-
" annotate each hunk with the filename and hunk number (filterdiff, patchview, grepdiff)\n"
1604-
" --as-numbered-lines=before|after|original-before|original-after (filterdiff, patchview, grepdiff)\n"
1605-
" display lines as they would look before, or after, the patch is applied;\n"
1606-
" or with original line numbers from the diff (original-before/original-after)\n"
1607-
" --format=context|unified (filterdiff, patchview, grepdiff)\n"
1608-
" set output format (filterdiff, patchview, grepdiff)\n"
1609-
" --output-matching=hunk|file (grepdiff)\n"
1610-
" show matching hunks or file-level diffs (grepdiff)\n"
1611-
" --only-match=rem|removals|add|additions|mod|modifications|all (grepdiff)\n"
1612-
" regex will only match removals, additions, modifications or (grepdiff)\n"
1613-
" the whole hunk (grepdiff)\n"
1614-
" --remove-timestamps (filterdiff, patchview, grepdiff)\n"
1615-
" don't show timestamps from output (filterdiff, patchview, grepdiff)\n"
1616-
" --clean (filterdiff)\n"
1617-
" remove all comments (non-diff lines) from output (filterdiff)\n"
1618-
" --in-place (filterdiff)\n"
1619-
" write output to the original input files (filterdiff)\n"
1602+
" --annotate {filterdiff, patchview, grepdiff}\n"
1603+
" annotate each hunk with the filename and hunk number {filterdiff, patchview, grepdiff}\n"
1604+
" --as-numbered-lines=before|after|original-before|original-after {filterdiff, patchview, grepdiff}\n"
1605+
" display lines as they would look before, or after, the patch is applied; {filterdiff, patchview, grepdiff}\n"
1606+
" or with original line numbers from the diff (original-before or original-after) {filterdiff, patchview, grepdiff}\n"
1607+
" --format=context|unified {filterdiff, patchview, grepdiff}\n"
1608+
" set output format {filterdiff, patchview, grepdiff}\n"
1609+
" --output-matching=hunk|file {grepdiff}\n"
1610+
" show matching hunks or file-level diffs {grepdiff}\n"
1611+
" --only-match=rem|removals|add|additions|mod|modifications|all {grepdiff}\n"
1612+
" regex will only match removals, additions, modifications or {grepdiff}\n"
1613+
" the whole hunk {grepdiff}\n"
1614+
" --remove-timestamps {filterdiff, patchview, grepdiff}\n"
1615+
" don't show timestamps from output {filterdiff, patchview, grepdiff}\n"
1616+
" --clean {filterdiff}\n"
1617+
" remove all comments (non-diff lines) from output {filterdiff}\n"
1618+
" --in-place {filterdiff}\n"
1619+
" write output to the original input files {filterdiff}\n"
16201620
" -z, --decompress\n"
16211621
" decompress .gz and .bz2 files\n"
1622-
" -n, --line-number (lsdiff, grepdiff)\n"
1623-
" show line numbers (lsdiff, grepdiff)\n"
1624-
" -N, --number-files (lsdiff, grepdiff)\n"
1625-
" show file numbers, for use with filterdiff's --files option (lsdiff, grepdiff)\n"
1626-
" -H, --with-filename (lsdiff, grepdiff)\n"
1627-
" show patch file names (lsdiff, grepdiff)\n"
1628-
" -h, --no-filename (lsdiff, grepdiff)\n"
1629-
" suppress patch file names (lsdiff, grepdiff)\n"
1622+
" -n, --line-number {lsdiff, grepdiff}\n"
1623+
" show line numbers {lsdiff, grepdiff}\n"
1624+
" -N, --number-files {lsdiff, grepdiff}\n"
1625+
" show file numbers, for use with filterdiff's --files option {lsdiff, grepdiff}\n"
1626+
" -H, --with-filename {lsdiff, grepdiff}\n"
1627+
" show patch file names {lsdiff, grepdiff}\n"
1628+
" -h, --no-filename {lsdiff, grepdiff}\n"
1629+
" suppress patch file names {lsdiff, grepdiff}\n"
16301630
" -p N, --strip-match=N\n"
16311631
" initial pathname components to ignore\n"
16321632
" --strip=N initial pathname components to strip\n"
@@ -1639,25 +1639,25 @@ const char * syntax_str =
16391639
" prefix pathnames in old files with PREFIX\n"
16401640
" --addnewprefix=PREFIX\n"
16411641
" prefix pathnames in new files with PREFIX\n"
1642-
" -s, --status (lsdiff, grepdiff)\n"
1643-
" show file additions (+), removals (-), and modifications (!) (lsdiff, grepdiff)\n"
1642+
" -s, --status {lsdiff, grepdiff}\n"
1643+
" show file additions (+), removals (-), and modifications (!) {lsdiff, grepdiff}\n"
16441644
" -v, --verbose\n"
16451645
" verbose output -- use more than once for extra verbosity\n"
1646-
" -E, --extended-regexp (grepdiff)\n"
1646+
" -E, --extended-regexp {grepdiff}\n"
16471647
#ifdef HAVE_PCRE2POSIX_H
1648-
" this option has no effect as PCRE regexes are used by default (grepdiff)\n"
1648+
" this option has no effect as PCRE regexes are used by default {grepdiff}\n"
16491649
#else
1650-
" use extended regexps, like egrep (grepdiff)\n"
1650+
" use extended regexps, like egrep {grepdiff}\n"
16511651
#endif
1652-
" -E, --empty-files-as-absent (lsdiff)\n"
1653-
" treat empty files as absent (lsdiff)\n"
1654-
" --empty-files-as-absent (grepdiff)\n"
1655-
" treat empty files as absent (grepdiff)\n"
1656-
" -f FILE, --file=FILE (grepdiff)\n"
1657-
" read regular expressions from FILE (grepdiff)\n"
1658-
" --filter run as 'filterdiff' (grepdiff, patchview, lsdiff)\n"
1659-
" --list run as 'lsdiff' (filterdiff, patchview, grepdiff)\n"
1660-
" --grep run as 'grepdiff' (filterdiff, patchview, lsdiff)\n"
1652+
" -E, --empty-files-as-absent {lsdiff}\n"
1653+
" treat empty files as absent {lsdiff}\n"
1654+
" --empty-files-as-absent {grepdiff}\n"
1655+
" treat empty files as absent {grepdiff}\n"
1656+
" -f FILE, --file=FILE {grepdiff}\n"
1657+
" read regular expressions from FILE {grepdiff}\n"
1658+
" --filter run as 'filterdiff' {grepdiff, patchview, lsdiff}\n"
1659+
" --list run as 'lsdiff' {filterdiff, patchview, grepdiff}\n"
1660+
" --grep run as 'grepdiff' {filterdiff, patchview, lsdiff}\n"
16611661
;
16621662

16631663
NORETURN
@@ -1676,8 +1676,8 @@ static void syntax (int err)
16761676
break;
16771677
endp = next;
16781678
*next++ = '\0';
1679-
if (*--endp == ')') {
1680-
char *begp = strrchr (p, '(');
1679+
if (*--endp == '}') {
1680+
char *begp = strrchr (p, '{');
16811681
char *comma;
16821682
if (!begp)
16831683
break;

src/interdiff.c

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,8 @@ trim_context (FILE *f /* positioned at start of @@ line */,
11361136
fwrite (line, (size_t) got, 1, out);
11371137
continue;
11381138
}
1139-
print_color (out, type, "%s", line);
1139+
print_color (out, type, "%.*s", (int) got - 1, line);
1140+
fputc ('\n', out);
11401141
}
11411142
}
11421143

@@ -1442,29 +1443,36 @@ index_patch_generic (FILE *patch_file, struct file_list **file_list, int need_sk
14421443

14431444
/* For patch2, we need to handle the @@ line and skip content */
14441445
if (need_skip_content) {
1445-
if (getline (&line, &linelen, patch_file) == -1) {
1446+
int found = 0;
1447+
1448+
while (!found &&
1449+
getline (&line, &linelen, patch_file) > 0) {
1450+
if (strncmp (line, "@@ ", 3))
1451+
continue;
1452+
1453+
p = strchr (line + 3, '+');
1454+
if (!p)
1455+
continue;
1456+
1457+
p = strchr (p, ',');
1458+
if (p) {
1459+
/* Like '@@ -1,3 +1,3 @@' */
1460+
p++;
1461+
skip = strtoul (p, &end, 10);
1462+
if (p == end)
1463+
continue;
1464+
} else
1465+
/* Like '@@ -1 +1 @@' */
1466+
skip = 1;
1467+
found = 1;
1468+
}
1469+
1470+
if (!found) {
14461471
free (names[0]);
14471472
free (names[1]);
14481473
break;
14491474
}
14501475

1451-
if (strncmp (line, "@@ ", 3))
1452-
goto try_next;
1453-
1454-
p = strchr (line + 3, '+');
1455-
if (!p)
1456-
goto try_next;
1457-
p = strchr (p, ',');
1458-
if (p) {
1459-
/* Like '@@ -1,3 +1,3 @@' */
1460-
p++;
1461-
skip = strtoul (p, &end, 10);
1462-
if (p == end)
1463-
goto try_next;
1464-
} else
1465-
/* Like '@@ -1 +1 @@' */
1466-
skip = 1;
1467-
14681476
add_to_list (file_list, best_name (2, names), pos);
14691477

14701478
while (skip--) {
@@ -1480,18 +1488,33 @@ index_patch_generic (FILE *patch_file, struct file_list **file_list, int need_sk
14801488
add_to_list (file_list, best_name (2, names), pos);
14811489
}
14821490

1483-
try_next:
14841491
free (names[0]);
14851492
free (names[1]);
14861493
}
14871494

14881495
if (line)
14891496
free (line);
14901497

1498+
/* Return success if the file is empty, has indexed files, or
1499+
* has no --- lines at all (merge commits, mode-only changes,
1500+
* notes-only commits, binary-only patches, etc.). */
14911501
if (file_is_empty || *file_list)
14921502
return 0;
1493-
else
1494-
return 1;
1503+
1504+
/* Check if the patch has any file-header --- lines (as
1505+
* opposed to commit-message separators or b4 tracking).
1506+
* If not, it simply has no diffable content. */
1507+
line = NULL;
1508+
linelen = 0;
1509+
rewind (patch_file);
1510+
while (getline (&line, &linelen, patch_file) != -1)
1511+
if (!strncmp (line, "--- a/", 6) ||
1512+
!strncmp (line, "--- /dev/null", 13)) {
1513+
free (line);
1514+
return 1;
1515+
}
1516+
free (line);
1517+
return 0;
14951518
}
14961519

14971520
static int
@@ -2113,11 +2136,15 @@ interdiff (FILE *p1, FILE *p2, const char *patch1, const char *patch2)
21132136

21142137
names[0] = filename_from_header (line + 4);
21152138

2116-
if (getline (&line, &linelen, p1) == -1)
2139+
if (getline (&line, &linelen, p1) == -1) {
2140+
free (names[0]);
21172141
break;
2142+
}
21182143

2119-
if (strncmp (line, "+++ ", 4))
2144+
if (strncmp (line, "+++ ", 4)) {
2145+
free (names[0]);
21202146
continue;
2147+
}
21212148

21222149
names[1] = filename_from_header (line + 4);
21232150

@@ -2150,8 +2177,21 @@ interdiff (FILE *p1, FILE *p2, const char *patch1, const char *patch2)
21502177
free (p);
21512178
}
21522179

2153-
if (!file_is_empty && !patch_found)
2154-
no_patch (patch1);
2180+
if (!file_is_empty && !patch_found) {
2181+
/* Don't warn for patches with no file-header --- lines
2182+
* (merge commits, mode-only, binary-only, etc.). */
2183+
int has_diff_content = 0;
2184+
2185+
rewind (p1);
2186+
while (getline (&line, &linelen, p1) != -1)
2187+
if (!strncmp (line, "--- a/", 6) ||
2188+
!strncmp (line, "--- /dev/null", 13)) {
2189+
has_diff_content = 1;
2190+
break;
2191+
}
2192+
if (has_diff_content)
2193+
no_patch (patch1);
2194+
}
21552195

21562196
copy_residue (p2, mode == mode_flip ? flip1 : stdout);
21572197

0 commit comments

Comments
 (0)