git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [RFC PATCH v7 0/10] diff: add provider interface and initial providers

From
Michael Montalbo <mmontalbo@gmail.com>
Date
Aug 23, 2026, 19:38 UTC
Message-ID
<CAC2Qwm+kzT_3_GKrpay=JLGYsxS10oWCg2MJPHrCVogFHA0OdA@mail.gmail.com>
In-Reply-To
<1f8fe709-ef19-496e-9857-8c2d24b29c56@gmail.com>
On Tue, Aug 4, 2026 at 6:52 AM Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> Hi Michael
>

Hi Phillip, apologies for the delayed response, and thank you for taking a look!

Show 29 quoted lines
> On 01/08/2026 18:41, Michael Montalbo wrote:
> > Every in-process diff in Git reduces, at one point, to a single
> > question: given two blobs and the settings the diff runs under, which
> > line ranges changed?  The answer is the diff's hunks: for each change,
> > the position and length of the range on the old side and on the new.
> > Each consumer asks in its own shape:
> >
> > - blame diffs each suspect's blob against its parent's, taking only the
> >    coordinates through xdiff's hunk callback;
> > - the stat formats keep only the added and deleted counts;
> > - patch output emits from the hunks, with xdiff interleaving context and
> >    content around them;
> > - log -L maps the tracked range across each commit from the coordinates.
> >
> > In every case the answer is computed the same way: load both blobs and
> > run xdiff.  That is the only source, so nothing that already holds the
> > answer, or that would answer differently on purpose, can supply it
> > instead.  Sometimes that is what we want, which is why patch-id and
> > format-patch stay on the builtin computation throughout: patch-id needs
> > identical hashes on every machine, and a format-patch must apply for
> > recipients who share none of the sender's configuration.  Other times
> > another source would be useful.
>
> This explains the mechanics of the existing implementation, but doesn't
> really explain what the advantage of the change is beyond having a
> unified interface. What are things that are unlocked by this change? Are
> we doing it purely to cache the hunk headers or does it (as I suspect)
> unlock other features?
>
After thinking more about this feedback...
Show 13 quoted lines
> > This RFC sketches a direction.  The unified series shows one interface
> > carrying two example providers and their interaction; it is not shaped
> > to merge as one topic.  If the direction holds, the work returns as
> > separate reviewable series (see Roadmap).  The two examples are
> > demonstrations, each an RFC on its own: diff.<driver>.process, the RFC
> > cooking as mm/diff-process-hunks, lets a configured external process
> > answer with its own notion of which lines changed, and the diff-hunks
> > store, new in this thread, remembers what xdiff computed and serves it
> > back.  One is authoritative and external, one a cache and in-process.
>
> What does it mean to be authoritative? Why isn't the xdiff code
> authoritative?
>
...
> > Chain order is the authority,
> I'm not sure what that phrase means
>

...and the concept I was trying to express here, I realize the abstraction introduced in the latest v7, a "diff provider", is not ultimately helpful and shoehorns several concepts together that should be addressed separately. The "chain order is authority" was (poorly) trying to describe that diff_providers occurring earlier in the list of providers would "override" the default "authority" of xdiff. The concept "authority" in these terms is unclear, though, it could mean "who gets to answer first" or "who gets to answer differently than xdiff." It also could paper over how each current caller uses xdiff in its own control flow with a "chain" of providers.

Show 14 quoted lines
> >    terminal provider is the builtin computation itself, so the interface
> >    never exists without an implementor: patch 02 ships it answering every
> >    request the way the consumers did before.  A consumer states its
> >    request in one struct and reads one set of outcomes (answered,
> >    unanswered, or failed); it never names a provider, and a provider>    added later maps onto those outcomes inside the interface, so consumer
> >    code is written once.  Because every diff now walks the chain even
> >    with no store or process configured, the default path was measured
> >    against the pre-series base and runs within noise (a 5000-commit
> >    log --stat and a long-history blame, ratio 1.00 either way).
>
> So we can configure a provider for a particular file type via
> .gitattributes and diff.<driver>.process and then it is used
> automatically, if there is no provider configured we use xdiff?
>
Yes, that was the original intent.
Show 23 quoted lines
> > - The diff-hunks store shows the non-authoritative side: an in-process
> >    cache at $GIT_DIR/objects/info/diff-hunks that may only reproduce the
> >    builtin diff, so serving from it never changes a command's output.  It
> >    is read by default and written only when a repository owner opts in,
> >    warming it as a side effect of diff work the command already does:
> >
> >        GIT_DIFF_HUNKS_WRITE=1 git log --all --stat >/dev/null
> >
> >    A warmed store then serves the stat formats and blame from stored
> >    coordinates instead of a fresh diff: on git.git a 5000-commit log
> >    --stat runs about 1.9x faster, and blame reads the same entries
> >    opportunistically (full numbers in [1]).  Its format and keying, what
> >    it may not serve, and how it handles corruption and staleness are in
> >    git-diff-hunks(1), gitformat-diff-hunks(5), and [2].  The interface
> >    point is small: a cache drops in as the provider that stands aside
> >    wherever an authoritative one answers.
>
> I had a very quick look at the documentation in patch that implements
> this. Am I right in thinking it stores xdl_opts directly so that we
> cannot change the in-memory representation without breaking the cache?
> Are there plans to garbage collect cache entries when the corresponding
> blobs are removed?
>

Yes, you are right regarding the in-memory representation breaking the cache. On a separate branch where I was working on diff-hunks more, I had a prune command that removed entries based on time as a maintenance task, but nothing more intelligent.

Show 20 quoted lines
> > - diff.<driver>.process shows the authoritative side: an external
> >    process, configured per driver, whose answers may deliberately differ
> >    from the builtin diff and outrank the store.  Git asks it for a pair by
> >    object names alone, so it answers before any blob is read, which suits
> >    a cache or a process that fetches the blobs itself.  Consulting is
> >    opt-in per command, following the allow_textconv precedent, and a pair
> >    the process cannot answer falls back to the builtin diff.  The
> >    protocol, the per-command gate, how failures are handled, and the
> >    versioning that lets it grow are in gitattributes(5) and footnotes [3]
> >    and [4].  The interface point, again, is small: an external,
> >    authoritative provider joins the same chain ahead of the cache, and
> >    neither consumer learns it is there.  A later content-carrying request
> >    would extend it to the pairs and consumers this identity-only form
> >    leaves on the builtin diff.
> >
> > The series stops at the coordinates.
>
> Does this mean the offsets and lengths in the hunk header? I can't see
> any reference to "coordinates" in the existing code.
>

Right, "coordinates" is a term I invented to refer to offsets and lengths, but I can see why it is unclear and do not think it needs to be coined. I will replace the use of that term with more explicit / already established terminology.

Show 13 quoted lines
> > A consumer that needs the changed
> > text, such as patch output, would have only its hunk selection replaced,
> > with xdiff still emitting content from the blobs; that machinery is the
> > content enrichment sketched in the Roadmap.  Establishing the framework
> > on coordinates first keeps this series one design: the question, the
> > interface, and two providers answering by identity.
>
> This seems like an interesting proposal and the diff headers seem like a
> good place for initial phase to stop. It would be helpful to have a
> clearer explanation of the features this interface would support (i.e.
> what's the motivation for these changes) and a lot less jargon in the
> interface description.
>
I really appreciate your feedback on this. I spent some time thinking about
the most straightforward way to express what I am going for. My goals are to:
  - add a "cousin" interface to xdiff-interface that allows users to
    configure their own alternative to xdiff. Among other things, this would
    enable users to install their own more intelligent diffing mechanisms
    while composing (to some extent) with surrounding Git diff functionality
    rather than replacing it wholesale.
  - still use xdiff in the end for its content rendering features so the
    alternative diff hunk provider composes with Git's existing diff
    features. Meaning, this "cousin" would stage hunks and then xdiff
    would render in the end.
  - provide the additional feature of allowing current xdiff-interface
    callers to potentially operate with oid's only and no content loading to
    save time dealing with content when only hunk header info is needed.
  - somehow make a consistent/easy interface for users to plug in their
    own xdiff alternatives, which has been via pkt-line.

I think returning to the v6 line of the topic for future re-rolls and focusing on the framing of a "cousin" interface to xdiff-interface, makes more sense, rather than the "diff provider" concept introduced in v7. Accordingly, I am inclined to eject the diff-hunks patches for now and focus on the "pkt-line xdiff-interface" line. The diff-hunks example was meant to show an in-process xdiff alternate / complement that cannot occur over pkt-line, but I think it makes a lot less sense to include in this RFC now that the "diff providers" concept would be dropped.

> Thanks
>
> Phillip
>
Thank you!
Previous: Phillip WoodNext: Michael Montalbo
Message 80 of 81 in “[RFC] diff: add diff.<driver>.process for external hunk providers”
  1. 0/5 [RFC] diff: add diff.<driver>.process for external hunk providersMichael Montalbo via GitGitGadget, May 22, 2026
  2. 1/5 xdiff: support external hunks via xpparam_tMichael Montalbo via GitGitGadget, May 22, 2026
  3. Junio C HamanoMay 22, 2026
  4. Michael MontalboMay 22, 2026
  5. Junio C HamanoMay 24, 2026
  6. Michael MontalboMay 24, 2026
  7. 2/5 userdiff: add diff.<driver>.process configMichael Montalbo via GitGitGadget, May 22, 2026
  8. 3/5 diff: add long-running diff process via diff.<driver>.processMichael Montalbo via GitGitGadget, May 22, 2026
  9. 4/5 blame: consult diff process for zero-hunk detectionMichael Montalbo via GitGitGadget, May 22, 2026
  10. 5/5 diff-process-normalize: add built-in whitespace normalizerMichael Montalbo via GitGitGadget, May 22, 2026
  11. Junio C HamanoMay 22, 2026
  12. Michael MontalboMay 22, 2026
  13. 0/4 [RFC] diff: add diff.<driver>.process for external hunk providersMichael Montalbo via GitGitGadget, May 25, 2026
  14. 1/4 xdiff: support external hunks via xpparam_tMichael Montalbo via GitGitGadget, May 25, 2026
  15. 2/4 userdiff: add diff.<driver>.process configMichael Montalbo via GitGitGadget, May 25, 2026
  16. 3/4 diff: add long-running diff process via diff.<driver>.processMichael Montalbo via GitGitGadget, May 25, 2026
  17. Junio C HamanoMay 26, 2026
  18. Michael MontalboMay 29, 2026
  19. Junio C HamanoMay 26, 2026
  20. Michael MontalboMay 29, 2026
  21. 4/4 blame: consult diff process for zero-hunk detectionMichael Montalbo via GitGitGadget, May 25, 2026
  22. 0/6 [RFC] diff: add diff.<driver>.process for external hunk providersMichael Montalbo via GitGitGadget, May 29, 2026
  23. 1/6 xdiff: support external hunks via xpparam_tMichael Montalbo via GitGitGadget, May 29, 2026
  24. 2/6 userdiff: add diff.<driver>.process configMichael Montalbo via GitGitGadget, May 29, 2026
  25. 3/6 sub-process: separate process lifecycle from hashmap managementMichael Montalbo via GitGitGadget, May 29, 2026
  26. 4/6 diff: add long-running diff process via diff.<driver>.processMichael Montalbo via GitGitGadget, May 29, 2026
  27. Johannes SchindelinJun 7, 2026
  28. Michael MontalboJun 7, 2026
  29. Junio C HamanoJun 8, 2026
  30. Michael MontalboJun 7, 2026
  31. Junio C HamanoJun 8, 2026
  32. Junio C HamanoJun 8, 2026
  33. 5/6 diff: bypass diff process with --no-ext-diff and in format-patchMichael Montalbo via GitGitGadget, May 29, 2026
  34. 6/6 blame: consult diff process for no-hunk detectionMichael Montalbo via GitGitGadget, May 29, 2026
  35. Junio C HamanoMay 31, 2026
  36. Michael MontalboJun 1, 2026
  37. 0/6 [RFC] diff: add diff.<driver>.process for external hunk providersMichael Montalbo via GitGitGadget, Jun 14, 2026
  38. 1/6 xdiff: support external hunks via xpparam_tMichael Montalbo via GitGitGadget, Jun 14, 2026
  39. 2/6 userdiff: add diff.<driver>.process configMichael Montalbo via GitGitGadget, Jun 14, 2026
  40. 3/6 sub-process: separate process lifecycle from hashmap managementMichael Montalbo via GitGitGadget, Jun 14, 2026
  41. 4/6 diff: add long-running diff process via diff.<driver>.processMichael Montalbo via GitGitGadget, Jun 14, 2026
  42. 5/6 diff: bypass diff process with --no-ext-diff and in format-patchMichael Montalbo via GitGitGadget, Jun 14, 2026
  43. 6/6 blame: consult diff process for no-hunk detectionMichael Montalbo via GitGitGadget, Jun 14, 2026
  44. 0/9 [RFC] diff: add diff.<driver>.process for external hunk providersMichael Montalbo via GitGitGadget, Jul 15, 2026
  45. 1/9 gitattributes: document how external diff drivers relate to diff featuresMichael Montalbo via GitGitGadget, Jul 15, 2026
  46. 2/9 xdiff: support external hunks via xpparam_tMichael Montalbo via GitGitGadget, Jul 15, 2026
  47. 3/9 userdiff: add diff.<driver>.process configMichael Montalbo via GitGitGadget, Jul 15, 2026
  48. 4/9 sub-process: separate process lifecycle from hashmap managementMichael Montalbo via GitGitGadget, Jul 15, 2026
  49. 5/9 diff: add long-running diff process via diff.<driver>.processMichael Montalbo via GitGitGadget, Jul 15, 2026
  50. 6/9 diff: bypass diff process with --no-ext-diff and in format-patchMichael Montalbo via GitGitGadget, Jul 15, 2026
  51. 7/9 blame: consult diff process for no-hunk detectionMichael Montalbo via GitGitGadget, Jul 15, 2026
  52. 8/9 diff: consult diff process for --stat countsMichael Montalbo via GitGitGadget, Jul 15, 2026
  53. 9/9 line-log: consult diff process for range trackingMichael Montalbo via GitGitGadget, Jul 15, 2026
  54. Junio C HamanoJul 16, 2026
  55. Michael MontalboJul 16, 2026
  56. 0/9 [RFC] diff: add diff.<driver>.process for external hunk providersMichael Montalbo via GitGitGadget, Jul 26, 2026
  57. 1/9 gitattributes: document how external diff drivers relate to diff featuresMichael Montalbo via GitGitGadget, Jul 26, 2026
  58. 2/9 xdiff: support external hunks via xpparam_tMichael Montalbo via GitGitGadget, Jul 26, 2026
  59. 3/9 userdiff: add diff.<driver>.process configMichael Montalbo via GitGitGadget, Jul 26, 2026
  60. 4/9 sub-process: separate process lifecycle from hashmap managementMichael Montalbo via GitGitGadget, Jul 26, 2026
  61. 5/9 diff: add long-running diff process via diff.<driver>.processMichael Montalbo via GitGitGadget, Jul 26, 2026
  62. 6/9 diff: bypass diff process with --no-ext-diff and in format-patchMichael Montalbo via GitGitGadget, Jul 26, 2026
  63. 7/9 blame: consult diff process for no-hunk detectionMichael Montalbo via GitGitGadget, Jul 26, 2026
  64. 8/9 diff: consult diff process for --stat countsMichael Montalbo via GitGitGadget, Jul 26, 2026
  65. 9/9 line-log: consult diff process for range trackingMichael Montalbo via GitGitGadget, Jul 26, 2026
  66. 0/10 diff: add provider interface and initial providersMichael Montalbo, Aug 1, 2026
  67. 01/10 gitattributes: document how external diff drivers relate to diff featuresMichael Montalbo, Aug 1, 2026
  68. 02/10 diff: introduce a hunk provider interfaceMichael Montalbo, Aug 1, 2026
  69. 03/10 diff-hunks: add the store format, library, and commandMichael Montalbo, Aug 1, 2026
  70. 04/10 diff: record precomputed hunks during stat outputMichael Montalbo, Aug 1, 2026
  71. 05/10 diff: read precomputed hunks for stat outputMichael Montalbo, Aug 1, 2026
  72. 06/10 blame: read precomputed hunksMichael Montalbo, Aug 1, 2026
  73. 07/10 sub-process: separate process lifecycle from hashmap managementMichael Montalbo, Aug 1, 2026
  74. 08/10 sub-process: add a gentle status readMichael Montalbo, Aug 1, 2026
  75. 09/10 userdiff: add diff.<driver>.process configMichael Montalbo, Aug 1, 2026
  76. 10/10 diff: consult oid-only hunk providers via diff.<driver>.processMichael Montalbo, Aug 1, 2026
  77. Michael MontalboAug 4, 2026
  78. Junio C HamanoAug 13, 2026
  79. Phillip WoodAug 4, 2026
  80. Michael MontalboAug 23, 2026
  81. Michael MontalboJun 15, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.