v0.16.0 924eaca

routes.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package ermitegit
4
5// DefaultRoutes returns the routes of production.
6//
7// The rule: a method is routed to ermite-git when it passes the shared
8// conformance table (TestConformance, TestCompareWithCLI) and its benchmark
9// beats the CLI adapter WARM in time AND in bytes per call, on the generated
10// fixture AND on lazygit (BenchmarkRepoReader, ERMITE_GIT_BENCH_REPO), and its
11// COLD run does not lose in time by more than the open itself (about 65 µs,
12// paid once per open, see below). Allocation counts are reported but do not
13// decide: the repository cache (cache.go) keeps up to 64 repositories open for
14// ten minutes, so nearly every request is warm, and the CLI's own cost (a
15// process per call, absent from the Go counters) is not in its numbers. Where
16// a method has several shapes that behave differently, each has its own
17// constant: GetTree, GetTreeLastCommits (root), GetTreeSubdirLastCommits,
18// ResolveRevisionAbbrev and ListCommitsPath. A method that does not win stays
19// on the CLI. GetCommit is not routable: the diff stays on git. ListPaths has
20// one shape: the fixture lists 131 files and lazygit 2,180.
21//
22// Warm is a repository that is open; cold closes it before every call, the
23// price of the first read after the idle TTL, an eviction or a restart (a
24// cold ermite-git call opens the packs and the commit-graph: about 65 µs and
25// 130 allocations before the call itself). The CLI keeps nothing open, so its
26// cold run is its warm run. Only the allocations of the Go process are
27// counted, which favours the CLI (its work happens in git processes). The
28// parallel runs (b.RunParallel) were also made: they agree with the warm runs
29// and widen the time gap.
30//
31// The numbers are the median of six runs of `go test -bench RepoReader
32// -benchmem -benchtime 500ms` on an AMD Ryzen 9 7900X3D, git 2.56, ermite-git
33// 5228465, as "time bytes allocations per call", CLI against ermite-git (K and
34// M are KiB and MiB). The fixture has 220 commits, 8 directories of 40 files
35// and a 10 MiB blob; lazygit has 7,550 commits. "loses" names what the
36// library does not win: t time, b bytes, a allocations.
37//
38//	shape                   repo     mode  cli                  ermite-git           verdict
39//	ListRefs                fixture  warm  905µs 116.3K 125     24µs 19.0K 73        win
40//	ListRefs                fixture  cold  904µs 116.3K 125     88µs 35.2K 203       loses a
41//	ListRefs                lazygit  warm  901µs 105.2K 88      15µs 2.2K 27         win
42//	ListRefs                lazygit  cold  908µs 105.4K 88      88µs 14.2K 163       loses a
43//	ResolveRevision/branch  fixture  warm  22µs 0.9K 19         4µs 0.4K 8           win
44//	ResolveRevision/branch  fixture  cold  22µs 0.9K 19         68µs 16.6K 138       loses tba
45//	ResolveRevision/branch  lazygit  warm  22µs 1.0K 19         4µs 0.5K 8           win
46//	ResolveRevision/branch  lazygit  cold  23µs 1.0K 19         72µs 12.4K 144       loses tba
47//	ResolveRevision/fullid  fixture  warm  9µs 1.3K 22          2µs 0.4K 6           win
48//	ResolveRevision/fullid  fixture  cold  9µs 1.3K 22          65µs 16.6K 136       loses tba
49//	ResolveRevision/fullid  lazygit  warm  9µs 1.3K 22          2µs 0.4K 6           win
50//	ResolveRevision/fullid  lazygit  cold  9µs 1.3K 22          70µs 12.3K 142       loses tba
51//	ResolveRevision/abbrev  fixture  warm  63µs 1.5K 31         9µs 0.7K 11          win
52//	ResolveRevision/abbrev  fixture  cold  64µs 1.5K 31         71µs 16.8K 141       loses tba
53//	ResolveRevision/abbrev  lazygit  warm  63µs 1.5K 31         9µs 0.6K 11          win
54//	ResolveRevision/abbrev  lazygit  cold  63µs 1.5K 31         76µs 12.6K 147       loses tba
55//	ResolveRefPath          fixture  warm  104µs 2.4K 59        15µs 0.8K 22         win
56//	ResolveRefPath          fixture  cold  105µs 2.4K 59        78µs 17.0K 152       loses ba
57//	ResolveRefPath          lazygit  warm  150µs 4.1K 79        22µs 1.4K 29         win
58//	ResolveRefPath          lazygit  cold  148µs 4.1K 79        89µs 13.4K 165       loses ba
59//	GetTree/root            fixture  warm  717µs 108.4K 114     13µs 5.8K 24         win
60//	GetTree/root            fixture  cold  725µs 108.4K 114     78µs 22.4K 154       loses a
61//	GetTree/root            lazygit  warm  827µs 121.4K 167     29µs 18.2K 56        win
62//	GetTree/root            lazygit  cold  831µs 121.5K 167     376µs 1.6M 200       loses ba
63//	GetTree/dir             fixture  warm  742µs 109.5K 141     16µs 9.2K 26         win
64//	GetTree/dir             fixture  cold  745µs 109.5K 141     109µs 75.8K 158      loses a
65//	GetTree/dir             lazygit  warm  1.4ms 267.9K 1058    193µs 318.4K 73      loses b
66//	GetTree/dir             lazygit  cold  1.4ms 268.0K 1058    4.2ms 2.0M 2490      loses tba
67//	GetTree/root+last       fixture  warm  4.0ms 1.2M 1023      70µs 108.3K 107      win
68//	GetTree/root+last       fixture  cold  4.0ms 1.2M 1024      165µs 127.8K 249     win
69//	GetTree/root+last       lazygit  warm  20.2ms 3.8M 3072     6.1ms 367.0K 510     win
70//	GetTree/root+last       lazygit  cold  20.3ms 3.8M 3073     8.5ms 3.4M 4204      loses a
71//	GetTree/dir+last        fixture  warm  5.3ms 1.8M 1454      190µs 166.1K 142     win
72//	GetTree/dir+last        fixture  cold  5.4ms 1.8M 1455      316µs 247.6K 323     win
73//	GetTree/dir+last        lazygit  warm  195.2ms 20.5M 17116  7.9ms 1.5M 855       win
74//	GetTree/dir+last        lazygit  cold  195.9ms 20.5M 17107  14.8ms 5.1M 6989     win
75//	ListPaths               fixture  warm  760µs 118.4K 225     41µs 37.9K 30         win
76//	ListPaths               fixture  cold  771µs 118.4K 225     107µs 54.7K 160       win
77//	ListPaths               lazygit  warm  1.8ms 432.9K 2280    842µs 250.3K 477      win
78//	ListPaths               lazygit  cold  1.8ms 432.9K 2280    1.2ms 298.7K 749      win
79//	OpenBlob/small          fixture  warm  46µs 6.1K 25         17µs 5.8K 14         win
80//	OpenBlob/small          fixture  cold  47µs 6.1K 25         87µs 27.7K 147       loses tba
81//	OpenBlob/small          lazygit  warm  51µs 5.4K 25         29µs 7.0K 42         loses ba
82//	OpenBlob/small          lazygit  cold  50µs 5.4K 25         131µs 25.1K 184      loses tba
83//	OpenBlob/largest        fixture  warm  21.4ms 69.7K 64      52.5ms 9.0K 13       loses t
84//	OpenBlob/largest        fixture  cold  21.6ms 70.0K 64      51.4ms 26.2K 143     loses ta
85//	OpenBlob/largest        lazygit  warm  3.3ms 69.9K 64       5.7ms 16.3K 123      loses ta
86//	OpenBlob/largest        lazygit  cold  3.3ms 69.9K 64       5.8ms 31.6K 283      loses ta
87//	ListCommits/page1       fixture  warm  1.0ms 122.5K 404     61µs 19.1K 108       win
88//	ListCommits/page1       fixture  cold  1.0ms 122.5K 404     134µs 36.9K 244      win
89//	ListCommits/page1       lazygit  warm  1.3ms 157.2K 415     361µs 120.1K 224     win
90//	ListCommits/page1       lazygit  cold  1.3ms 157.2K 415     503µs 136.2K 377     win
91//	ListCommits/deep        fixture  warm  1.0ms 122.1K 404     71µs 19.3K 108       win
92//	ListCommits/deep        fixture  cold  1.0ms 122.1K 404     136µs 36.1K 238      win
93//	ListCommits/deep        lazygit  warm  2.0ms 123.2K 404     424µs 23.9K 112      win
94//	ListCommits/deep        lazygit  cold  2.0ms 123.2K 404     544µs 36.3K 248      win
95//	ListCommits/path        fixture  warm  1.6ms 108.8K 138     443µs 25.4K 42       win
96//	ListCommits/path        fixture  cold  1.6ms 108.9K 138     594µs 93.6K 360      loses a
97//	ListCommits/path        lazygit  warm  12.9ms 108.7K 118    6.0ms 29.2K 58       win
98//	ListCommits/path        lazygit  cold  12.8ms 107.7K 118    9.5ms 2.4M 6498      loses ba
99//	ListCommits/dirpath     fixture  warm  1.3ms 123.0K 403     199µs 33.8K 113      win
100//	ListCommits/dirpath     fixture  cold  1.3ms 123.0K 403     277µs 55.4K 268      win
101//	ListCommits/dirpath     lazygit  warm  6.7ms 127.8K 403     2.0ms 50.2K 181      win
102//	ListCommits/dirpath     lazygit  cold  6.7ms 127.8K 403     3.3ms 887.1K 2019    loses ba
103//
104// The "verdict" column is the strict reading, every line of the table won;
105// the routes follow the rule above. What decides them, with ermite-git 5228465
106// (zlib reader with a reused adler32, header-size cache, Refresh and
107// LookupRefID without allocations):
108//
109//   - ListRefs (every repository page, through loadRepo): 905 µs against 24 µs
110//     warm, 120 KiB against 19 KiB (fixture), 960 against 16 µs and 108 KiB
111//     against 2 KiB (lazygit). Cold it is still 4 to 10 times faster
112//     (93 µs); only its allocation count loses. Routed.
113//   - ResolveRevision (name, full id, abbreviation) and ResolveRefPath: 4 to 8
114//     times faster warm, with fewer bytes. Cold they lose 45 µs of time to the
115//     open, but the ListRefs of the same page has opened the repository
116//     already, so the open is paid by a call that wins it back. Routed.
117//   - GetTree with last commits: root listing 4.1 ms against 68 µs on the
118//     fixture, 20.5 ms against 6.2 ms on lazygit (cold 8.7 ms; its 4,206
119//     allocations against 3,082 are the only line lost); a subdirectory of
120//     lazygit 195-199 ms against 8-9 ms warm, 15-17 ms cold, 20 MiB against
121//     1.5 MiB. They are two constants so that either can be flipped back on
122//     its own. Both routed.
123//   - GetTree without last commits wins warm in time everywhere (13 µs against
124//     0.7 ms at the root), but a large directory of lazygit loses warm bytes
125//     (325 KiB against 275 KiB) and, cold, 4.0 ms against 1.4 ms in time. It
126//     stays on the CLI.
127//   - ListCommits of a revision wins every line and stays routed.
128//     ListCommitsPath wins warm and cold in time (lazygit file: 12.9 ms against
129//     6.0 ms warm), only its cold bytes lose (2.4 MiB): it is a candidate, not
130//     flipped here, to be decided with its own conformance review.
131//   - OpenBlob by size: below 1 MiB the small blob loses warm bytes and
132//     allocations on lazygit; above, it loses time (inflate speed: 52 ms
133//     against 21 ms). No size makes it win, so there is no size-based route.
134//   - ListPaths (the recursive path list of the finder) wins every line, even
135//     cold, because one walk replaces a process and the parsing of its output
136//     (the bytes of the paths are kept in 32 KiB blocks, which is what brought
137//     the lazygit bytes under the CLI's: a single growing buffer lost them,
138//     699K against 433K). Routed.
139func DefaultRoutes() Routes {
140	return Routes{
141		ListRefs:                 ErmiteGit,
142		ResolveRevision:          ErmiteGit,
143		ResolveRevisionAbbrev:    ErmiteGit,
144		ResolveRefPath:           ErmiteGit,
145		GetTree:                  CLI,
146		GetTreeLastCommits:       ErmiteGit,
147		GetTreeSubdirLastCommits: ErmiteGit,
148		OpenBlob:                 CLI,
149		ListCommits:              ErmiteGit,
150		ListCommitsPath:          CLI,
151		ListPaths:                ErmiteGit,
152	}
153}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 45

↑↓ moveenter openesc close