#! /usr/bin/env perl use v5.16; use warnings; # Take a unified diff (perhaps from "git diff" or similar) on stdin, and # delete hunks where (a) every "ins" line in the hunk also appears in a # "del" line somewhere in the diff, and (b) every "del" line in the hunk # also appears in an "ins" line somewhere in the diff. die "Usage: diff ... | nontrivdiff\n" if @ARGV; sub break_before (&@) { my $predicate = shift; my (@curr, @groups); for (@_) { push @groups, [splice @curr] if @curr && $predicate->($_); push @curr, $_; } push @groups, \@curr if @curr; return @groups; } my @all_lines = <>; my @head; push @head, shift @all_lines while @all_lines && $all_lines[0] =~ /^diff |^index |^--- |^\+\+\+ /; die "Can't handle multi-file diffs\n" if grep /^--- |^\+\+\+ /, @all_lines; my (%ins, %del); for (@all_lines) { next if /^\@\@ |^ /; my ($c, $line) = /([-+])(.*)/s or die "can't parse: $_"; $line =~ s/[ \t]+/ /g; my $h = $c eq '-' ? \%del : \%ins; $h->{$line}++; } my @out; for my $hunk (break_before { /^\@\@ / } @all_lines) { push @out, @$hunk if any_changes_missing($hunk); } print @head, @out if @out; sub any_changes_missing { my ($hunk) = @_; my %lins = %ins; my %ldel = %del; for (@$hunk) { next if /^\@\@ |^ /; my ($c, $line) = /([-+])(.*)/s or die "can't parse: $_"; $line =~ s/[ \t]+/ /g; my $h = $c eq '-' ? \%lins : \%ldel; return 1 if !$h->{$line}; $h->{$line}--; } %ins = %lins; %del = %ldel; return 0; }