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!