-
-
-
-
@servicedesk it would be worth providing additional guidance with respect to whatever underlying Git engine/pager you are using and its capability to display this context per hunk.
-
@zaakiy, the relevant implementation detail is that OneDev code-review diffs do not go through a Git pager or consume Git-produced patch hunks. JGit 6.10 is used to identify changed files, but the web diff then loads the old and new blobs, computes line blocks with OneDev
DiffUtils/diff-match-patch, and renders them inBlobTextDiffPanel.Native Git can append one
TEXTvalue to a hunk header via.gitattributesanddiff.<driver>.xfuncname, and--function-contextuses the same mechanism. That is useful for command-line patches, but it is not sufficient for this design: a patch hunk has only one context field, while this issue requires independent old/new contexts, nested symbol names, and sticky updates. JGitDiffFormatter.writeHunkHeaderlikewise writes ranges only and is not the source of the review UI hunks.The best fit is therefore to implement this above the diff engine using OneDev existing
commons-jsymbolinfrastructure.CodeSearchService.getSymbols(...)can retrieve symbols separately for the old blob ID/path and new blob ID/path; each symbol exposesgetScope(),getParent(), andgetFQN(). For each rendered hunk, OneDev can resolve the narrowest scope containing that side hunk anchor, walk its parent chain for the label, and attach the old/new labels to the rendered hunk metadata. The browser can then update the two sticky labels from that metadata while scrolling. Symbol lookup should be cached per blob during rendering, and a side should remain unlabeled when its language has no extractor or no containing scope.References: Git custom hunk headers and JGit DiffFormatter API. This captures the engine constraints and the recommended integration point for implementation.
-
I'm wondering how much extra processing needs to happen on the OneDev server. Since OneDev is iterating through the symbols, it's almost as if it might be quite computationally intensive. What are your thoughts on how computationally intensive this would be?
The goal here is to keep OneDev highly performant. But also give the user the context they need. What would this mean for a file with a very large number of changes, in terms of server performance impact? One might surmise that the intention of the way that OneDev uses Git is to keep everything lightweight, and what we are doing here seems to negate that design intention.
At the same time, I really want this feature!!!
-
@zaakiy, that performance concern is valid. I checked the current symbol-loading and diff-display paths, and the important distinction is that
CodeSearchService.getSymbols(...)reads a pre-extracted symbol list from the Lucene code index, keyed by blob hash and path. It does not need to parse the source again while rendering the diff. The incremental server work is therefore an index lookup, deserialization, and mapping hunk anchors to symbol ranges.I would tighten the implementation around these guardrails:
- Fetch symbols only for textual diffs that are actually displayed and have a registered extractor.
- Fetch at most once per unique old/new blob in the request. Do not call
getSymbolsper hunk. If profiling shows cluster round trips matter, batch the blob-side lookups. - Build a sorted interval/index structure once per blob, then resolve each hunk by binary search or a linear sweep. That makes mapping roughly
O(S log S + H log S)(orO(S + H)with a sweep), notO(S * H), whereSis symbols andHis hunks. - Use indexed symbols only for this feature; do not synchronously fall back to extracting symbols during a diff request. A missing/stale index, excessive symbol count, or exceeded time budget should simply mean no context label for that side.
- Add timing/serialized-size metrics and benchmark cold and warm requests against synthetic symbol-heavy files before enabling it by default.
The current diff UI already bounds the workload: at most 200 changed files are considered, a single displayed diff is capped at 2,000 changed lines, total displayed changed lines at 5,000, and textual diffs above 65,535 combined old/new lines are rejected. Those limits prevent change volume from growing without bound. They do not directly cap symbol count, so generated or highly fragmented files remain the case to benchmark and protect with a symbol/time budget.
With those constraints, I would expect the symbol-context cost to be modest compared with blob loading, line diffing, and rendering. The expensive version would be reparsing each revision on demand or scanning every symbol for every hunk; neither is necessary for this design.
| Type |
New Feature
|
| Priority |
Normal
|
| Assignee | |
| Labels |
No labels
|
Originated from and supersedes issue #3089 after the desired UX was clarified with @zaakiy, @servicedesk, and @robin.
Motivation
A diff currently shows changed and surrounding lines, but it does not identify the function, method, or class containing those lines. In a large file, readers must expand or scroll through unchanged code to discover where a change belongs. This increases review time and makes similar-looking changes harder to distinguish.
For example, this pseudocode contains two nearly identical changes:
Without enclosing-symbol context, a diff fragment such as
check(account.email)does not tell the reviewer which function changed. A context label makes that distinction immediately visible.Current UX
Proposed UX
Provide both per-hunk context and sticky context. Old and new revisions must have independent context because a changed line can move between different symbols.
Split view:
Unified view:
Expected behavior
This issue captures the finalized product direction. Language-specific symbol extraction and edge-case fallback behavior can be decided during implementation.