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 @@ -315,6 +315,7 @@ TESTS = tests/newline1/run-test \
tests/git-rename-issue22/run-test \
tests/git-binary-issue57/run-test \
tests/git-binary-formats/run-test \
tests/git-extended-diffs-exclude/run-test \
tests/git-mode-issue59/run-test \
tests/git-exclude-issue27/run-test \
tests/git-prefixes-option/run-test \
Expand Down
11 changes: 11 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ Patchutils news

0.4.5 (stable)

Reverted incompatible behavior change from version 0.4.4. In 0.4.4,
Git diffs without content hunks (renames, copies, mode-only changes,
binary files) were included in output and file numbering, breaking
compatibility with 0.4.3 and earlier versions. This caused file numbers
to change for scripts using -N/-F options. The 0.4.3 behavior has been
restored as the default: these diffs are now excluded from output and
numbering. Added --git-extended-diffs option to control this behavior:
use --git-extended-diffs=include to get the 0.4.4 behavior if needed.
The default will change to 'include' in version 0.5.0 for modern Git
workflow support. Addresses GitHub issue #157.

Fixed grepdiff -s/--status to display correct file status indicators.
Previously, grepdiff -s incorrectly showed '!' (modification) for all
matching files regardless of whether they were additions, deletions,
Expand Down
48 changes: 48 additions & 0 deletions doc/patchutils.xml
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@
</group>
<arg choice="opt">--strip=<replaceable>n</replaceable></arg>
<arg choice="opt">--git-prefixes=<replaceable>strip|keep</replaceable></arg>
<arg choice="opt">--git-extended-diffs=<replaceable>exclude|include</replaceable></arg>
<arg choice="opt">--addprefix=<replaceable>PREFIX</replaceable></arg>
<arg choice="opt">--addoldprefix=<replaceable>PREFIX</replaceable></arg>
<arg choice="opt">--addnewprefix=<replaceable>PREFIX</replaceable></arg>
Expand Down Expand Up @@ -799,6 +800,17 @@
in version 0.5.0.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--git-extended-diffs</option>=<replaceable>exclude|include</replaceable></term>
<listitem>
<para>Controls whether to process Git diffs without traditional content hunks.
This includes renames, copies, mode-only changes, and binary files.
With <literal>exclude</literal> (default in 0.4.x), these diffs are
skipped. With <literal>include</literal> (default in 0.5.0+), these
diffs are processed normally. This option affects file numbering with
<option>-N</option> and file filtering with <option>-F</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--addprefix</option>=<replaceable>PREFIX</replaceable></term>
<listitem>
Expand Down Expand Up @@ -1078,6 +1090,7 @@ patch.file]]></screen></para>
</group>
<arg choice="opt">--strip=<replaceable>n</replaceable></arg>
<arg choice="opt">--git-prefixes=<replaceable>strip|keep</replaceable></arg>
<arg choice="opt">--git-extended-diffs=<replaceable>exclude|include</replaceable></arg>
<arg choice="opt">--addprefix=<replaceable>PREFIX</replaceable></arg>
<arg choice="opt">--addoldprefix=<replaceable>PREFIX</replaceable></arg>
<arg choice="opt">--addnewprefix=<replaceable>PREFIX</replaceable></arg>
Expand Down Expand Up @@ -1264,6 +1277,17 @@ patch.file]]></screen></para>
in version 0.5.0.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--git-extended-diffs</option>=<replaceable>exclude|include</replaceable></term>
<listitem>
<para>Controls whether to process Git diffs without traditional content hunks.
This includes renames, copies, mode-only changes, and binary files.
With <literal>exclude</literal> (default in 0.4.x), these diffs are
skipped. With <literal>include</literal> (default in 0.5.0+), these
diffs are processed normally. This option affects file numbering with
<option>-N</option> and file filtering with <option>-F</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--addprefix</option>=<replaceable>PREFIX</replaceable></term>
<listitem>
Expand Down Expand Up @@ -1457,6 +1481,7 @@ done)]]></screen></para>
</group>
<arg choice="opt">--strip=<replaceable>n</replaceable></arg>
<arg choice="opt">--git-prefixes=<replaceable>strip|keep</replaceable></arg>
<arg choice="opt">--git-extended-diffs=<replaceable>exclude|include</replaceable></arg>
<arg choice="opt">--addprefix=<replaceable>PREFIX</replaceable></arg>
<group choice="opt">
<arg>-s</arg>
Expand Down Expand Up @@ -1666,6 +1691,17 @@ This is the same as gitdiff but uses git show instead of git diff.
in version 0.5.0.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--git-extended-diffs</option>=<replaceable>exclude|include</replaceable></term>
<listitem>
<para>Controls whether to process Git diffs without traditional content hunks.
This includes renames, copies, mode-only changes, and binary files.
With <literal>exclude</literal> (default in 0.4.x), these diffs are
skipped. With <literal>include</literal> (default in 0.5.0+), these
diffs are processed normally. This option affects file numbering with
<option>-N</option> and file filtering with <option>-F</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--addprefix</option>=<replaceable>PREFIX</replaceable></term>
<listitem>
Expand Down Expand Up @@ -2050,6 +2086,7 @@ This is the same as gitdiff but uses git show instead of git diff.
</group>
<arg choice="opt">--strip=<replaceable>n</replaceable></arg>
<arg choice="opt">--git-prefixes=<replaceable>strip|keep</replaceable></arg>
<arg choice="opt">--git-extended-diffs=<replaceable>exclude|include</replaceable></arg>
<arg choice="opt">--addprefix=<replaceable>PREFIX</replaceable></arg>
<arg choice="opt">--addoldprefix=<replaceable>PREFIX</replaceable></arg>
<arg choice="opt">--addnewprefix=<replaceable>PREFIX</replaceable></arg>
Expand Down Expand Up @@ -2199,6 +2236,17 @@ This is the same as gitdiff but uses git show instead of git diff.
in version 0.5.0.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--git-extended-diffs</option>=<replaceable>exclude|include</replaceable></term>
<listitem>
<para>Controls whether to process Git diffs without traditional content hunks.
This includes renames, copies, mode-only changes, and binary files.
With <literal>exclude</literal> (default in 0.4.x), these diffs are
skipped. With <literal>include</literal> (default in 0.5.0+), these
diffs are processed normally. This option affects file numbering with
<option>-N</option> and file filtering with <option>-F</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--addprefix</option>=<replaceable>PREFIX</replaceable></term>
<listitem>
Expand Down
52 changes: 50 additions & 2 deletions src/filterdiff.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,33 @@ static unsigned long filecount=0;

static enum git_prefix_mode git_prefix_mode = GIT_PREFIX_KEEP;

enum git_extended_diffs_mode {
GIT_EXTENDED_DIFFS_EXCLUDE = 0, /* Skip extended diffs (0.4.3 behavior) */
GIT_EXTENDED_DIFFS_INCLUDE = 1 /* Process extended diffs (Git workflow) */
};

static enum git_extended_diffs_mode git_extended_diffs_mode = GIT_EXTENDED_DIFFS_EXCLUDE;

/* Helper function to check if a git diff type should be excluded based on mode */
static int
should_skip_git_extended_diff (enum git_diff_type git_type)
{
if (git_extended_diffs_mode == GIT_EXTENDED_DIFFS_INCLUDE)
return 0; /* Don't skip anything if include mode */

/* In exclude mode, skip all diffs without content hunks.
* This includes renames, copies, mode-only changes, binary files,
* and new/deleted files without content (e.g., binary files).
* This restores 0.4.3 behavior where only files with actual
* patch hunks were shown. */
switch (git_type) {
case GIT_DIFF_NORMAL:
return 0; /* Don't skip - has hunks */
default:
return 1; /* Skip all extended/special types */
}
}

/* Helper function to check if current patch is a Git patch */
static int
is_git_patch (char **headers, unsigned int num_headers)
Expand Down Expand Up @@ -1314,7 +1341,11 @@ static int filterdiff (FILE *f, const char *patchname)
/* Process as git diff without hunks and then exit */
enum git_diff_type git_type = detect_git_diff_type (header, num_headers);

if (git_type != GIT_DIFF_NORMAL) {

/* Skip extended diffs if in exclude mode */
if (should_skip_git_extended_diff (git_type))
goto eof;
if (git_type != GIT_DIFF_NORMAL) {
char *git_old_name = NULL, *git_new_name = NULL;
const char *p_stripped;
int match;
Expand Down Expand Up @@ -1391,7 +1422,11 @@ static int filterdiff (FILE *f, const char *patchname)
/* Check if this is a git diff without hunks or with content like Binary files */
enum git_diff_type git_type = detect_git_diff_type (header, num_headers);

if (git_type != GIT_DIFF_NORMAL) {

/* Skip extended diffs if in exclude mode */
if (should_skip_git_extended_diff (git_type))
goto flush_continue;
if (git_type != GIT_DIFF_NORMAL) {
/* This is a git diff without hunks - handle it */
char *git_old_name = NULL, *git_new_name = NULL;
const char *p_stripped;
Expand Down Expand Up @@ -1633,6 +1668,9 @@ const char * syntax_str =
" --git-prefixes=strip|keep\n"
" how to handle a/ and b/ prefixes in Git diffs for both filename\n"
" matching (-i/-x) and output (default: keep)\n"
" --git-extended-diffs=exclude|include\n"
" process Git diffs without hunks: renames, copies, mode-only\n"
" changes, binary files; default is exclude\n"
" --addprefix=PREFIX\n"
" prefix pathnames with PREFIX\n"
" --addoldprefix=PREFIX\n"
Expand Down Expand Up @@ -1893,6 +1931,7 @@ int main (int argc, char *argv[])
{"file", 1, 0, 'f'},
{"in-place", 0, 0, 1000 + 'w'},
{"git-prefixes", 1, 0, 1000 + 'G'},
{"git-extended-diffs", 1, 0, 1000 + 'D'},
{0, 0, 0, 0}
};
char *end;
Expand Down Expand Up @@ -2085,6 +2124,15 @@ int main (int argc, char *argv[])
error(EXIT_FAILURE, 0, "invalid argument to --git-prefixes: %s (expected 'strip' or 'keep')", optarg);
}
break;
case 1000 + 'D':
if (!strcmp(optarg, "exclude")) {
git_extended_diffs_mode = GIT_EXTENDED_DIFFS_EXCLUDE;
} else if (!strcmp(optarg, "include")) {
git_extended_diffs_mode = GIT_EXTENDED_DIFFS_INCLUDE;
} else {
error(EXIT_FAILURE, 0, "invalid argument to --git-extended-diffs: %s (expected 'exclude' or 'include')", optarg);
}
break;
default:
syntax(1);
}
Expand Down
3 changes: 2 additions & 1 deletion tests/filterdiff-binary-filtering/run-test
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ Binary files /dev/null and b/file2.bin differ
EOF

# Test -F2: should only show file #2 (file1.bin), NOT file2.bin
${FILTERDIFF} -F2 diff 2>errors >output || exit 1
# Note: using --git-extended-diffs=include to test binary file filtering
${FILTERDIFF} --git-extended-diffs=include -F2 diff 2>errors >output || exit 1
[ -s errors ] && exit 1

cat << 'EOF' | cmp - output || exit 1
Expand Down
8 changes: 4 additions & 4 deletions tests/git-binary-formats/run-test
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ EOF

# Test filtering binary files with GIT binary patch format - should include binary content
echo "Testing GIT binary patch format (include)..."
${FILTERDIFF} --git-prefixes=strip -i "file1.bin" git-binary-patch.patch 2>errors1 >result1 || exit 1
${FILTERDIFF} --git-extended-diffs=include --git-prefixes=strip -i "file1.bin" git-binary-patch.patch 2>errors1 >result1 || exit 1
[ -s errors1 ] && { echo "Unexpected errors in test 1:"; cat errors1; exit 1; }

cat << 'EOF' | cmp - result1 || { echo "Test 1 failed"; exit 1; }
Expand All @@ -78,7 +78,7 @@ EOF

# Test filtering binary files with literal format - should include binary content
echo "Testing literal format (include)..."
${FILTERDIFF} --git-prefixes=strip -i "file3.bin" literal-patch.patch 2>errors2 >result2 || exit 1
${FILTERDIFF} --git-extended-diffs=include --git-prefixes=strip -i "file3.bin" literal-patch.patch 2>errors2 >result2 || exit 1
[ -s errors2 ] && { echo "Unexpected errors in test 2:"; cat errors2; exit 1; }

cat << 'EOF' | cmp - result2 || { echo "Test 2 failed"; exit 1; }
Expand All @@ -93,7 +93,7 @@ EOF

# Test filtering binary files with delta format - should include binary content
echo "Testing delta format (include)..."
${FILTERDIFF} --git-prefixes=strip -i "file5.bin" delta-patch.patch 2>errors3 >result3 || exit 1
${FILTERDIFF} --git-extended-diffs=include --git-prefixes=strip -i "file5.bin" delta-patch.patch 2>errors3 >result3 || exit 1
[ -s errors3 ] && { echo "Unexpected errors in test 3:"; cat errors3; exit 1; }

cat << 'EOF' | cmp - result3 || { echo "Test 3 failed"; exit 1; }
Expand All @@ -108,7 +108,7 @@ EOF

# Test excluding binary files - should skip binary content
echo "Testing binary patch exclusion..."
${FILTERDIFF} --git-prefixes=strip -x "file1.bin" git-binary-patch.patch 2>errors4 >result4 || exit 1
${FILTERDIFF} --git-extended-diffs=include --git-prefixes=strip -x "file1.bin" git-binary-patch.patch 2>errors4 >result4 || exit 1
[ -s errors4 ] && { echo "Unexpected errors in test 4:"; cat errors4; exit 1; }

cat << 'EOF' | cmp - result4 || { echo "Test 4 failed"; exit 1; }
Expand Down
6 changes: 3 additions & 3 deletions tests/git-binary-issue57/run-test
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ index 0000000..abcdefg
EOF

# Test that filterdiff includes binary files when they match
${FILTERDIFF} --git-prefixes=strip -i binary-file git-binary.patch 2>errors >result || exit 1
${FILTERDIFF} --git-extended-diffs=include --git-prefixes=strip -i binary-file git-binary.patch 2>errors >result || exit 1
[ -s errors ] && exit 1

cat << EOF | cmp - result || exit 1
Expand All @@ -32,7 +32,7 @@ Binary files /dev/null and b/binary-file differ
EOF

# Test that lsdiff shows binary files
${LSDIFF} --git-prefixes=strip git-binary.patch 2>errors2 >result2 || exit 1
${LSDIFF} --git-extended-diffs=include --git-extended-diffs=include --git-prefixes=strip git-binary.patch 2>errors2 >result2 || exit 1
[ -s errors2 ] && exit 1

cat << EOF | cmp - result2 || exit 1
Expand All @@ -41,7 +41,7 @@ text-file.txt
EOF

# Test excluding binary files
${FILTERDIFF} --git-prefixes=strip -x binary-file git-binary.patch 2>errors3 >result3 || exit 1
${FILTERDIFF} --git-extended-diffs=include --git-prefixes=strip -x binary-file git-binary.patch 2>errors3 >result3 || exit 1
[ -s errors3 ] && exit 1

cat << EOF | cmp - result3 || exit 1
Expand Down
14 changes: 7 additions & 7 deletions tests/git-complex-mixed/run-test
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ index 111222..333444 100644
EOF

# Test 1: lsdiff should list all files correctly
${LSDIFF} complex-git.patch 2>errors1 >result1 || exit 1
${LSDIFF} --git-extended-diffs=include --git-extended-diffs=include complex-git.patch 2>errors1 >result1 || exit 1
[ -s errors1 ] && exit 1

cat << EOF | cmp - result1 || exit 1
Expand All @@ -79,7 +79,7 @@ a/regular-change.h
EOF

# Test 2: lsdiff with --git-prefixes=strip
${LSDIFF} --git-prefixes=strip complex-git.patch 2>errors2 >result2 || exit 1
${LSDIFF} --git-extended-diffs=include --git-extended-diffs=include --git-prefixes=strip complex-git.patch 2>errors2 >result2 || exit 1
[ -s errors2 ] && exit 1

cat << EOF | cmp - result2 || exit 1
Expand All @@ -93,7 +93,7 @@ regular-change.h
EOF

# Test 3: Filter only new files
${FILTERDIFF} -i "*/*.txt" complex-git.patch 2>errors3 >result3 || exit 1
${FILTERDIFF} --git-extended-diffs=include -i "*/*.txt" complex-git.patch 2>errors3 >result3 || exit 1
[ -s errors3 ] && exit 1

# Should include new-file.txt and new-name.txt (renamed file)
Expand All @@ -102,7 +102,7 @@ grep -q "new-name.txt" result3 || exit 1
grep -q "binary-data.bin" result3 && exit 1 # Should not include binary

# Test 4: Filter binary files specifically
${FILTERDIFF} -i "*/*.bin" complex-git.patch 2>errors4 >result4 || exit 1
${FILTERDIFF} --git-extended-diffs=include -i "*/*.bin" complex-git.patch 2>errors4 >result4 || exit 1
[ -s errors4 ] && exit 1

cat << EOF | cmp - result4 || exit 1
Expand All @@ -113,22 +113,22 @@ Binary files /dev/null and b/binary-data.bin differ
EOF

# Test 5: Exclude deleted files
${FILTERDIFF} -x "*/*.old" complex-git.patch 2>errors5 >result5 || exit 1
${FILTERDIFF} --git-extended-diffs=include -x "*/*.old" complex-git.patch 2>errors5 >result5 || exit 1
[ -s errors5 ] && exit 1

# Should not contain deleted-file.old
grep -q "deleted-file.old" result5 && exit 1

# Test 6: Test grepdiff on content changes only
${GREPDIFF} "NEW_VERSION" complex-git.patch 2>errors6 >result6 || exit 1
${GREPDIFF} --git-extended-diffs=include "NEW_VERSION" complex-git.patch 2>errors6 >result6 || exit 1
[ -s errors6 ] && exit 1

# Should only match regular-change.h
grep -q "regular-change.h" result6 || exit 1
grep -q "new-file.txt" result6 && exit 1 # Should not match files without the pattern

# Test 7: Test with -p strip on complex paths
${FILTERDIFF} --git-prefixes=strip -p0 --strip=0 complex-git.patch 2>errors7 >result7 || exit 1
${FILTERDIFF} --git-extended-diffs=include --git-prefixes=strip -p0 --strip=0 complex-git.patch 2>errors7 >result7 || exit 1
[ -s errors7 ] && exit 1

# Should preserve all content
Expand Down
Loading