repara2 repara2 - 1 month ago 13
Git Question

GIT: how to configure the hunks recognition

I am investigating the the git interactive features, from which the most important for me is the hunks merging and selection. It works very good but I need the hunks to be smaller. When working with source code files, very often the hunk contains two different changes that are not related (normally a few lines apart from each other).
This is probably because git recognizes the hunks with a given configuration, like lines apart, or ammount of chars or something like that.

Is this correct, and if so, is there any way to change / reconfigure this behavior?

Thanks a lot,

Answer

If you are referring to just plain git diff, the hunk context size is configurable: it is set via the -U option, if specified, otherwise from your diff.context setting, if set. If all of those fail the default is three lines of context (both above and below).

Hence:

$ git config --global diff.context 1

reduces the diff context to one line in each direction, instead of 3. There is also an --inter-hunk-context option value (with no corresponding configuration item) that you can use to fuse more hunks together (this is the opposite of what you want so I mention it only for completeness; see also --function-context aka -W).

However, git add --interactive runs git diff-files or git diff-index rather than plain git diff, and as the git config documentation cleverly hides:

diff.autoRefreshIndex

       When using git diff to compare with work tree files, do not consider stat-only change as changed. Instead, silently run git update-index --refreshto update the cached stat information for paths whose contents in the work tree match the contents in the index. This option defaults to true. Note that this affects only git diff Porcelain, and not lower level diff commands such as git diff-files.

Although this talks about the diff.autoRefreshIndex setting, it applies to all of the configurable items: git diff reads and obeys your configuration, but git diff-index and git diff-files and so on do not (intentionally, so that scripts, which should use plumbing commands rather than porcelain, can get the correct behavior regardless of newly added options).

What this means in the end is that if you are referring specifically to git add --interactive, the answer is no, or rather, not without a little bit of work. The interactive add Perl script uses the plumbing commands, not the porcelain git diff, so it must obtain and use any such setting itself. It does obtain and use your diff.algorithm and diff.compactionHeuristic settings, but it does not use your diff.context setting.

Making it do so is easy but requires modifying Git slightly:

diff --git a/usr/local/libexec/git-core/git-add--interactive b/tmp/git-add--interactive
index 235fb88..ba001a1 100755
--- a/usr/local/libexec/git-core/git-add--interactive
+++ b/tmp/git-add--interactive
@@ -47,2 +47,3 @@ my $normal_color = $repo->get_color("", "reset");

+my $diff_context_size = $repo->config('diff.context');
 my $diff_algorithm = $repo->config('diff.algorithm');
@@ -753,2 +754,6 @@ sub parse_diff {
        }
+       if (defined $diff_context_size) {
+               my $Uarg = sprintf("-U%d", $diff_context_size);
+               splice @diff_cmd, 1, 0, "$Uarg";
+       }
        if ($diff_compaction_heuristic) {

(there may be a better way to set up the -U argument; my Perl is clumsy). The interactive patch (or git add -p) mode needs this snippet added if it is to obey your diff.context setting.

Of course, you can simply split (s) a hunk during interactive add, as pedrorijo91 reminded us in a comment linking to Can I modify git-add's hunk size?, so there's no real need for this. It might be nice if it were included, though.

Comments