1. 21 Jan, 2018 1 commit
  2. 14 Oct, 2017 1 commit
  3. 03 Oct, 2016 1 commit
    • xdiff: rename "struct group" to "struct xdlgroup" · b28825a1
      Commit a49895b5 (xdl_change_compact(): introduce the concept
      of a change group, 2016-08-22) added a "struct group" type
      to xdiff/xdiffi.c. But the POSIX system header "grp.h"
      already defines "struct group" (it is part of the getgrnam
      interface).
      
      Let's resolve by giving the xdiff variant a scoped name,
      which is closer to other xdiff types anyway (e.g.,
      xdlfile_t, though note that xdiff is fond if typedefs when
      Git usually is not).
      Jeff King committed
  4. 29 Sep, 2016 4 commits
    • diff: improve positioning of add/delete blocks in diffs · 19f1a8e6
      Some groups of added/deleted lines in diffs can be slid up or down,
      because lines at the edges of the group are not unique. Picking good
      shifts for such groups is not a matter of correctness but definitely has
      a big effect on aesthetics. For example, consider the following two
      diffs. The first is what standard Git emits:
      
          --- a/9c572b21dd090a1e5c5bb397053bf8043ffe7fb4:git-send-email.perl
          +++ b/6dcfa306f2b67b733a7eb2d7ded1bc9987809edb:git-send-email.perl
          @@ -231,6 +231,9 @@ if (!defined $initial_reply_to && $prompting) {
           }
      
           if (!$smtp_server) {
          +       $smtp_server = $repo->config('sendemail.smtpserver');
          +}
          +if (!$smtp_server) {
                  foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
                          if (-x $_) {
                                  $smtp_server = $_;
      
      The following diff is equivalent, but is obviously preferable from an
      aesthetic point of view:
      
          --- a/9c572b21dd090a1e5c5bb397053bf8043ffe7fb4:git-send-email.perl
          +++ b/6dcfa306f2b67b733a7eb2d7ded1bc9987809edb:git-send-email.perl
          @@ -230,6 +230,9 @@ if (!defined $initial_reply_to && $prompting) {
                  $initial_reply_to =~ s/(^\s+|\s+$)//g;
           }
      
          +if (!$smtp_server) {
          +       $smtp_server = $repo->config('sendemail.smtpserver');
          +}
           if (!$smtp_server) {
                  foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
                          if (-x $_) {
      
      This patch teaches Git to pick better positions for such "diff sliders"
      using heuristics that take the positions of nearby blank lines and the
      indentation of nearby lines into account.
      
      The existing Git code basically always shifts such "sliders" as far down
      in the file as possible. The only exception is when the slider can be
      aligned with a group of changed lines in the other file, in which case
      Git favors depicting the change as one add+delete block rather than one
      add and a slightly offset delete block. This naive algorithm often
      yields ugly diffs.
      
      Commit d634d61ed6 improved the situation somewhat by preferring to
      position add/delete groups to make their last line a blank line, when
      that is possible. This heuristic does more good than harm, but (1) it
      can only help if there are blank lines in the right places, and (2)
      always picks the last blank line, even if there are others that might be
      better. The end result is that it makes perhaps 1/3 as many errors as
      the default Git algorithm, but that still leaves a lot of ugly diffs.
      
      This commit implements a new and much better heuristic for picking
      optimal "slider" positions using the following approach: First observe
      that each hypothetical positioning of a diff slider introduces two
      splits: one between the context lines preceding the group and the first
      added/deleted line, and the other between the last added/deleted line
      and the first line of context following it. It tries to find the
      positioning that creates the least bad splits.
      
      Splits are evaluated based only on the presence and locations of nearby
      blank lines, and the indentation of lines near the split. Basically, it
      prefers to introduce splits adjacent to blank lines, between lines that
      are indented less, and between lines with the same level of indentation.
      In more detail:
      
      1. It measures the following characteristics of a proposed splitting
         position in a `struct split_measurement`:
      
         * the number of blank lines above the proposed split
         * whether the line directly after the split is blank
         * the number of blank lines following that line
         * the indentation of the nearest non-blank line above the split
         * the indentation of the line directly below the split
         * the indentation of the nearest non-blank line after that line
      
      2. It combines the measured attributes using a bunch of
         empirically-optimized weighting factors to derive a `struct
         split_score` that measures the "badness" of splitting the text at
         that position.
      
      3. It combines the `split_score` for the top and the bottom of the
         slider at each of its possible positions, and selects the position
         that has the best `split_score`.
      
      I determined the initial set of weighting factors by collecting a corpus
      of Git histories from 29 open-source software projects in various
      programming languages. I generated many diffs from this corpus, and
      determined the best positioning "by eye" for about 6600 diff sliders. I
      used about half of the repositories in the corpus (corresponding to
      about 2/3 of the sliders) as a training set, and optimized the weights
      against this corpus using a crude automated search of the parameter
      space to get the best agreement with the manually-determined values.
      Then I tested the resulting heuristic against the full corpus. The
      results are summarized in the following table, in column `indent-1`:
      
      | repository            | count |      Git 2.9.0 |     compaction | compaction-fixed |       indent-1 |       indent-2 |
      | --------------------- | ----- | -------------- | -------------- | ---------------- | -------------- | -------------- |
      | afnetworking          |   109 |    89  (81.7%) |    37  (33.9%) |      37  (33.9%) |     2   (1.8%) |     2   (1.8%) |
      | alamofire             |    30 |    18  (60.0%) |    14  (46.7%) |      15  (50.0%) |     0   (0.0%) |     0   (0.0%) |
      | angular               |   184 |   127  (69.0%) |    39  (21.2%) |      23  (12.5%) |     5   (2.7%) |     5   (2.7%) |
      | animate               |   313 |     2   (0.6%) |     2   (0.6%) |       2   (0.6%) |     2   (0.6%) |     2   (0.6%) |
      | ant                   |   380 |   356  (93.7%) |   152  (40.0%) |     148  (38.9%) |    15   (3.9%) |    15   (3.9%) | *
      | bugzilla              |   306 |   263  (85.9%) |   109  (35.6%) |      99  (32.4%) |    14   (4.6%) |    15   (4.9%) | *
      | corefx                |   126 |    91  (72.2%) |    22  (17.5%) |      21  (16.7%) |     6   (4.8%) |     6   (4.8%) |
      | couchdb               |    78 |    44  (56.4%) |    26  (33.3%) |      28  (35.9%) |     6   (7.7%) |     6   (7.7%) | *
      | cpython               |   937 |   158  (16.9%) |    50   (5.3%) |      49   (5.2%) |     5   (0.5%) |     5   (0.5%) | *
      | discourse             |   160 |    95  (59.4%) |    42  (26.2%) |      36  (22.5%) |    18  (11.2%) |    13   (8.1%) |
      | docker                |   307 |   194  (63.2%) |   198  (64.5%) |     253  (82.4%) |     8   (2.6%) |     8   (2.6%) | *
      | electron              |   163 |   132  (81.0%) |    38  (23.3%) |      39  (23.9%) |     6   (3.7%) |     6   (3.7%) |
      | git                   |   536 |   470  (87.7%) |    73  (13.6%) |      78  (14.6%) |    16   (3.0%) |    16   (3.0%) | *
      | gitflow               |   127 |     0   (0.0%) |     0   (0.0%) |       0   (0.0%) |     0   (0.0%) |     0   (0.0%) |
      | ionic                 |   133 |    89  (66.9%) |    29  (21.8%) |      38  (28.6%) |     1   (0.8%) |     1   (0.8%) |
      | ipython               |   482 |   362  (75.1%) |   167  (34.6%) |     169  (35.1%) |    11   (2.3%) |    11   (2.3%) | *
      | junit                 |   161 |   147  (91.3%) |    67  (41.6%) |      66  (41.0%) |     1   (0.6%) |     1   (0.6%) | *
      | lighttable            |    15 |     5  (33.3%) |     0   (0.0%) |       2  (13.3%) |     0   (0.0%) |     0   (0.0%) |
      | magit                 |    88 |    75  (85.2%) |    11  (12.5%) |       9  (10.2%) |     1   (1.1%) |     0   (0.0%) |
      | neural-style          |    28 |     0   (0.0%) |     0   (0.0%) |       0   (0.0%) |     0   (0.0%) |     0   (0.0%) |
      | nodejs                |   781 |   649  (83.1%) |   118  (15.1%) |     111  (14.2%) |     4   (0.5%) |     5   (0.6%) | *
      | phpmyadmin            |   491 |   481  (98.0%) |    75  (15.3%) |      48   (9.8%) |     2   (0.4%) |     2   (0.4%) | *
      | react-native          |   168 |   130  (77.4%) |    79  (47.0%) |      81  (48.2%) |     0   (0.0%) |     0   (0.0%) |
      | rust                  |   171 |   128  (74.9%) |    30  (17.5%) |      27  (15.8%) |    16   (9.4%) |    14   (8.2%) |
      | spark                 |   186 |   149  (80.1%) |    52  (28.0%) |      52  (28.0%) |     2   (1.1%) |     2   (1.1%) |
      | tensorflow            |   115 |    66  (57.4%) |    48  (41.7%) |      48  (41.7%) |     5   (4.3%) |     5   (4.3%) |
      | test-more             |    19 |    15  (78.9%) |     2  (10.5%) |       2  (10.5%) |     1   (5.3%) |     1   (5.3%) | *
      | test-unit             |    51 |    34  (66.7%) |    14  (27.5%) |       8  (15.7%) |     2   (3.9%) |     2   (3.9%) | *
      | xmonad                |    23 |    22  (95.7%) |     2   (8.7%) |       2   (8.7%) |     1   (4.3%) |     1   (4.3%) | *
      | --------------------- | ----- | -------------- | -------------- | ---------------- | -------------- | -------------- |
      | totals                |  6668 |  4391  (65.9%) |  1496  (22.4%) |    1491  (22.4%) |   150   (2.2%) |   144   (2.2%) |
      | totals (training set) |  4552 |  3195  (70.2%) |  1053  (23.1%) |    1061  (23.3%) |    86   (1.9%) |    88   (1.9%) |
      | totals (test set)     |  2116 |  1196  (56.5%) |   443  (20.9%) |     430  (20.3%) |    64   (3.0%) |    56   (2.6%) |
      
      In this table, the numbers are the count and percentage of human-rated
      sliders that the corresponding algorithm got *wrong*. The columns are
      
      * "repository" - the name of the repository used. I used the diffs
        between successive non-merge commits on the HEAD branch of the
        corresponding repository.
      
      * "count" - the number of sliders that were human-rated. I chose most,
        but not all, sliders to rate from those among which the various
        algorithms gave different answers.
      
      * "Git 2.9.0" - the default algorithm used by `git diff` in Git 2.9.0.
      
      * "compaction" - the heuristic used by `git diff --compaction-heuristic`
        in Git 2.9.0.
      
      * "compaction-fixed" - the heuristic used by `git diff
        --compaction-heuristic` after the fixes from earlier in this patch
        series. Note that the results are not dramatically different than
        those for "compaction". Both produce non-ideal diffs only about 1/3 as
        often as the default `git diff`.
      
      * "indent-1" - the new `--indent-heuristic` algorithm, using the first
        set of weighting factors, determined as described above.
      
      * "indent-2" - the new `--indent-heuristic` algorithm, using the final
        set of weighting factors, determined as described below.
      
      * `*` - indicates that repo was part of training set used to determine
        the first set of weighting factors.
      
      The fact that the heuristic performed nearly as well on the test set as
      on the training set in column "indent-1" is a good indication that the
      heuristic was not over-trained. Given that fact, I ran a second round of
      optimization, using the entire corpus as the training set. The resulting
      set of weights gave the results in column "indent-2". These are the
      weights included in this patch.
      
      The final result gives consistently and significantly better results
      across the whole corpus than either `git diff` or `git diff
      --compaction-heuristic`. It makes only about 1/30 as many errors as the
      former and about 1/10 as many errors as the latter. (And a good fraction
      of the remaining errors are for diffs that involve weirdly-formatted
      code, sometimes apparently machine-generated.)
      
      The tools that were used to do this optimization and analysis, along
      with the human-generated data values, are recorded in a separate project
      [1].
      
      [1] https://github.com/mhagger/diff-slider-tools
      
      Original Git commit: 433860f3d0beb0c6f205290bd16cda413148f098
      Michael Haggerty committed
    • xdl_change_compact(): introduce the concept of a change group · a49895b5
      The idea of xdl_change_compact() is fairly simple:
      
      * Proceed through groups of changed lines in the file to be compacted,
        keeping track of the corresponding location in the "other" file.
      
      * If possible, slide the group up and down to try to give the most
        aesthetically pleasing diff. Whenever it is slid, the current location
        in the other file needs to be adjusted.
      
      But these simple concepts are obfuscated by a lot of index handling that
      is written in terse, subtle, and varied patterns. I found it very hard
      to convince myself that the function was correct.
      
      So introduce a "struct group" that represents a group of changed lines
      in a file. Add some functions that perform elementary operations on
      groups:
      
      * Initialize a group to the first group in a file
      * Move to the next or previous group in a file
      * Slide a group up or down
      
      Even though the resulting code is longer, I think it is easier to
      understand and review. Its performance is not changed
      appreciably (though it would be if `group_next()` and `group_previous()`
      were not inlined).
      
      ...and in fact, the rewriting helped me discover another bug in the
      --compaction-heuristic code: The update of blank_lines was never done
      for the highest possible position of the group. This means that it could
      fail to slide the group to its highest possible position, even if that
      position had a blank line as its last line. So for example, it yielded
      the following diff:
      
          $ git diff --no-index --compaction-heuristic a.txt b.txt
          diff --git a/a.txt b/b.txt
          index e53969f..0d60c5fe 100644
          --- a/a.txt
          +++ b/b.txt
          @@ -1,3 +1,7 @@
           1
           A
          +
          +B
          +
          +A
           2
      
      when in fact the following diff is better (according to the rules of
      --compaction-heuristic):
      
          $ git diff --no-index --compaction-heuristic a.txt b.txt
          diff --git a/a.txt b/b.txt
          index e53969f..0d60c5fe 100644
          --- a/a.txt
          +++ b/b.txt
          @@ -1,3 +1,7 @@
           1
          +A
          +
          +B
          +
           A
           2
      
      The new code gives the bottom answer.
      
      Original Git commit: e8adf23d1ee97b57c8aea32ee8365203b77c0e42
      Michael Haggerty committed
    • recs_match(): take two xrecord_t pointers as arguments · 09fb5b2a
      There is no reason for it to take an array and two indexes as argument,
      as it only accesses two elements of the array.
      
      Original Git commit: 152598cbb667471c8f5be16e199922a41452b2d5
      Michael Haggerty committed
    • xdiff: add recs_match helper function · 506bf09d
      It is a common pattern in xdl_change_compact to check that hashes and
      strings match. The resulting code to perform this change causes very
      long lines and makes it hard to follow the intention. Introduce a helper
      function recs_match which performs both checks to increase
      code readability.
      
      Original Git commit: 92e5b62fec0e9b647429e8d3736c571c434dd375
      Jacob Keller committed
  5. 31 Mar, 2016 3 commits
    • xdiff/xprepare: fix a memory leak · 6045afd3
      The xdl_prepare_env() function may initialise an xdlclassifier_t
      data structure via xdl_init_classifier(), which allocates memory
      to several fields, for example 'rchash', 'rcrecs' and 'ncha'.
      If this function later exits due to the failure of xdl_optimize_ctxs(),
      then this xdlclassifier_t structure, and the memory allocated to it,
      is not cleaned up.
      
      In order to fix the memory leak, insert a call to xdl_free_classifier()
      before returning.
      
      This patch was originally written by Ramsay Jones (see commit
      87f16258367a3b9a62663b11f898a4a6f3c19d31 in git.git).
      Patrick Steinhardt committed
    • xdiff/xprepare: use the XDF_DIFF_ALG() macro to access flag bits · 1bce1487
      Commit 307ab20b3 ("xdiff: PATIENCE/HISTOGRAM are not independent option
      bits", 19-02-2012) introduced the XDF_DIFF_ALG() macro to access the
      flag bits used to represent the diff algorithm requested. In addition,
      code which had used explicit manipulation of the flag bits was changed
      to use the macros.
      
      However, one example of direct manipulation remains. Update this code to
      use the XDF_DIFF_ALG() macro.
      
      This patch was originally written by Ramsay Jones (see commit
      5cd6978a9cfef58de061a9525f3678ade479564d in git.git).
      Patrick Steinhardt committed
  6. 01 Mar, 2016 1 commit
  7. 23 Feb, 2016 1 commit
  8. 22 Oct, 2015 1 commit
  9. 05 Oct, 2015 2 commits
  10. 10 Jul, 2015 1 commit
  11. 07 Jul, 2015 1 commit
    • xdiff: upgrade to core git 2.4.5 · 234ca40a
      Upgrade xdiff to version used in core git 2.4.5 (0df0541).
      
      Corrects an issue where an LF is added at EOF while applying
      an unrelated change (ba31180), cleans up some unused code (be89977 and
      e5b0662), and provides an improved callback to avoid leaking internal
      (to xdiff) structures (467d348).
      
      This also adds some additional functionality that we do not yet take
      advantage of, namely the ability to ignore changes whose lines are
      all blank (36617af).
      Edward Thomson committed
  12. 05 Dec, 2014 1 commit
  13. 21 Apr, 2012 1 commit
  14. 20 Apr, 2012 1 commit
  15. 17 Apr, 2012 1 commit
  16. 02 Mar, 2012 4 commits
    • Update diff to use iterators · 74fa4bfa
      This is a major reorganization of the diff code.  This changes
      the diff functions to use the iterators for traversing the
      content.  This allowed a lot of code to be simplified.  Also,
      this moved the functions relating to outputting a diff into a
      new file (diff_output.c).
      
      This includes a number of other changes - adding utility
      functions, extending iterators, etc. plus more tests for the
      diff code.  This also takes the example diff.c program much
      further in terms of emulating git-diff command line options.
      Russell Belfer committed
    • Initial implementation of git_diff_blob · cd33323b
      This gets the basic plumbing in place for git_diff_blob.
      There is a known issue where additional parameters like
      the number of lines of context to display on the diff
      are not working correctly (which leads one of the new
      unit tests to fail).
      Russell Belfer committed
    • Eliminate xdiff compiler warnings · 8b75f7f3
      This cleans up the various GCC compiler warnings with the
      xdiff code that was copied in.
      Russell Belfer committed
    • Import xdiff library from git · 3a5ad90a
      This is the initial import of the xdiff code (LGPL) from
      core git as of rev f349b562086e2b7595d8a977d2734ab2ef9e71ef
      Russell Belfer committed