11

So, I've run into this problem a few times. During a round of changes, I remove functionA() and add functionB() in the same place. When I run a diff, I end up with a hideous muddled set of changes where it tries matching the two functions up on their common braces rather than showing all of functionA as a removal and all of functionB as an addition. For a simplified example:

int functionA(int a, bool b)
{
    int c;
    bool d;
    if (a == b)
    {
        //do stuff
    }
    //do more stuff
}

replaced with

void functionB()
{
    // do different stuff
    for (int x=0; x<10; x++)
    {
        //do more different stuff
    }
    //do even more different stuff
}

the diff might yield

-int functionA(int a, bool b)
+void functionB()
 {
-    int c;
-    bool d;
-    if (a == b)
+    // do different stuff
+    for (int x=0; x<10; x++)
     {
-        //do stuff
+        //do more different stuff
     }
-    //do more stuff
+    //do even more different stuff
 }

Which is useless and difficult to read, since there's really no commonality besides the braces. It will even skip braces that don't align until it finds ones that do, which is common enough. And in one case I'm looking at now, I removed 7 consecutive functions and added 3, which do roughly the same thing a much more easily readable/maintainable manner. The diff algorithm disburses the additions in a scattered way through all 7 removed functions, making an unreadable and confusing mess.

Is there any way to tweak git diff to ignore cases where the only commonality is a brace?

If it matters, my system currently has git 1.9.0 and diff (GNU difftools) 2.8.1 I tagged C++ because the system I work on is (mostly C-style) C++, but this should apply to a number of other languages.

While looking for existing questions, the nearest I could find was What is git diff --patience for? However, this had very little impact on my diff. (It is different, but not visibly clearer)

I also see in the git diff man page the --break-rewrites option, which does what I want, but only at the file level, not the function level.

If nothing else, I guess I can try making a habit in the future of putting new logic in a completely different part of the file from any removals in cases where I want the diff to show the addition in one block, but I'd prefer to keep related logic together.

Community
  • 1
  • 1
Bryon
  • 373
  • 2
  • 8

1 Answers1

1

Git currently1 offers four diff algorithms, known as myers (the default), minimal, patience, and histogram. The last one is a slight tweak to patience. These were all in Git version 1.9.0, though. If none of them does what you want, you can tell Git to use an external diff. See the "Generating diff text" section of the gitattributes documentation (which refers back to the main git documentation) for details. It's a bit complicated, but to summarize, you use gitattributes to force Git to run the external diff program, and you define the external diff program by writing a script (usually sh/bash) and configuring it in your global or per-repository settings.


1As of version 2.8.x anyway; 2.9 is almost out and does not have any new ones.

torek
  • 448,244
  • 59
  • 642
  • 775
  • 2
    interesting.but doesn't really answer the question.. do you know of any external diff programs that DO do what was asked? or is it a case of writing your own? – ShoeLace Oct 25 '17 at 05:22
  • @ShoeLace: As far as I know there are none, meaning "yes, writing your own". [Ira Baxter's syntax-aware one](https://stackoverflow.com/a/3452129/1256452) might do the trick, too. You would hook this into Git as an external diff. (I don't have that program and cannot advise further.) – torek Oct 25 '17 at 13:37