51

Is it possible to configure git diff to respect indentation and syntax? I am not talking about ignoring indentation and spaces, but rather to use blank lines, indentation levels and possibly brackets, to help matching the old lines to new lines.

E.g. git diff often cuts through functions and their docblock, like this:

 class C {

   /**
+   * Goes to the bar.
+   */
+  function bar() {
+    return 'bar';
+  }
+
+  /**
    * Gets your foo up to date.
    */
   function foo() {

When I would prefer

 class C {
+
+  /**
+   * Goes to the bar.
+   */
+  function bar() {
+    return 'bar';
+  }

   /**
    * Gets your foo up to date.
    */
   function foo() {

In this example it is still quite harmless, but there are examples where functions and their docblock are really ripped apart due to the greedy and naive diff implementation.

Note: I already configured *.php diff=php in ~/.gitattributes.

EDIT: Another example: Here git diff mixes a property docblock with a method docblock:

   /**
-   * @var int
+   * @param string $str
    */
donquixote
  • 4,877
  • 3
  • 31
  • 54
  • I have a suspicion the answer will be in which diff algorithm you pick, but I couldn't find one that worked in the way you want. – sevenseacat Jun 11 '14 at 12:35
  • 1
    How do you pick an algorithm? – donquixote Jun 11 '14 at 12:55
  • 2
    Does --patience have anything to do with it? – donquixote Jun 13 '14 at 23:25
  • 2
    Good info toward an answer here: http://fabiensanglard.net/git_code_review/diff.php http://stackoverflow.com/questions/4045017/what-is-git-diff-patience-for?rq=1 – minopret Jun 19 '14 at 03:13
  • 2
    I just tested this out using the `--patience` option, but it doesn't work in this case (`--patience` will sometimes work, but not always). –  Jun 22 '14 at 02:36
  • 1
    [This is a similar question](http://stackoverflow.com/q/18116221/456814), so this might be a duplicate. –  Jun 22 '14 at 02:37
  • 1
    To help people answer this, [here is a list of resources](https://gist.github.com/coldhawaiian/23caff0573aa8f53b61b) that I created. –  Jun 22 '14 at 02:47
  • so, it seems the current answer is either "don't know" or "git can't do that (yet).". The similar question may go in the same direction, although the question itself is not directly focused on a git algorithm, even dismisses the --patience as "seems to just be for git diff". And I like my question better :) – donquixote Jun 24 '14 at 03:38
  • Maybe the first answer in the following topic will explain some of the mechanics going on: [How to apply diff rules of the languages in gitattributes](http://stackoverflow.com/questions/21096188/how-to-apply-diff-rules-of-the-languages-in-gitattributes) – smoes Jun 26 '14 at 07:40
  • Interesting search keyword: "semantic diff". See also http://stackoverflow.com/questions/523307/semantic-diff-utilities. I was not necessarily looking for a 100% language-aware algorithm, but if that's what it takes then why not. – donquixote Jul 02 '14 at 16:45

2 Answers2

5

I do not know how to do that in git alone, but there is at least one commercial tool (i.e. it costs money) which deals with that kind of problems, called SemanticMerge.

It can handle quite a lot of cool cases, and supports C#, Java, and partially C. You can configure git to use it as merge tool.

(I'm not affiliated.)

henko
  • 763
  • 7
  • 16
  • 3
    Still it would be nice to have something in git that is based on indentation levels or some other kind of cheating, that pretends to be language-aware but really is not. – donquixote Jul 11 '14 at 15:02
  • @donquixote You can probably set up SemanticMerge as a git difftool so that it would be "in git" – slebetman Nov 13 '18 at 01:11
  • @donquixote: Googling around a bit it looks like you can use SemanticMerge as a git diff tool (algorithm) - https://users.semanticmerge.com/documentation/how-to-configure/semanticmerge-configuration-guide.shtml – slebetman Nov 13 '18 at 01:13
  • @donquixote: once you set it up like in the link above all you need to do is change your own behaviour to type `git difftool` instead of `git diff` – slebetman Nov 13 '18 at 01:14
  • It seems this tool has been retired and made unavailable by its owner. Is there another similar tool? – osiris Jun 22 '22 at 11:43
2

First of all use a more sophisticated diff algorithm like:

git config --global diff.algorithm histogram

Then there are also semantic diff tools like https://github.com/GumTreeDiff/gumtree whose algorithm has also been implemented in clang-diff: https://github.com/krobelus/clang-diff-playground

Trass3r
  • 5,858
  • 2
  • 30
  • 45