Friday, 5 February 2016

Diffs without noise

Over the last year or five I've been on a particular refactoring campaign in my gEDA fork. I'm trying to reduce the number of places where an object's forward and reverse pointers get accessed explicitly. To find all these places, I temporarily renamed these pointer fields to something unique so that I can reliably find and edit all these occurrences at any given time. So my working directory is full of noisy diff hunks like this one:

@@ -287,9 +287,9 @@ int f_open_flags(TOPLEVEL *toplevel, PAGE *page, const gchar *filename, o_read(toplevel, page->object_tail, full_filename, &tmp_err); } - for (o_current = page->object_tail->next; + for (o_current = page->object_tail->next_secret; o_current != NULL; - o_current = o_current->next) { + o_current = o_current->next_secret) { /* This would also be a place to emit page signals. */ s_conn_update_object(page, o_current); o_attrib_init_uuid(toplevel, o_current);

When I'm changing some code that doesn't explicitly use these forward and reverse pointers (yet is still required to complete the refactor) I want to see only the diffs from those changes. Without the diff pollution caused by renaming the pointer fields. If only there were a way to canonicalize each side of the diff before comparing them, so as to hide the uninteresting differences... So I wrote a way to do that, using git's external diff tool facility:

#!/bin/sh if test $# -ge 7; then a=`mktemp` b=`mktemp` sed "$GIT_DIFF_OPTS" "$2" >$a sed "$GIT_DIFF_OPTS" "$5" >$b diff -up --label "$1" --label "$5" $a $b rm -f $a $b else diff -up /dev/null "$1" fi true

(It isn't very robust to argument errors.) I invoke it like this:

GIT_DIFF_OPTS='s/_secret//g' GIT_EXTERNAL_DIFF=~/personal-utils/git-diff-sed git diff

Unfortunately diff colouring doesn't happen when using an external diff tool. Otherwise it works like a charm.