v0.3.0 9fdf386

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 only when it passes the shared
8// conformance table (TestConformance, TestCompareWithCLI) and its benchmark
9// beats the CLI adapter in time, in bytes AND in allocations per call, warm
10// AND cold, on the generated fixture AND on lazygit (BenchmarkRepoReader,
11// ERMITE_GIT_BENCH_REPO). Where a method has several shapes, every shape must
12// win: the constants GetTree, GetTreeLastCommits, ResolveRevisionAbbrev and
13// ListCommitsPath cover directories of any size and files of any history. A
14// method that does not win stays on the CLI. GetCommit is not routable: the
15// diff stays on git.
16//
17// Warm is a repository that is open; cold closes it before every call, the
18// price of the first read after the idle TTL, an eviction or a restart (a
19// cold ermite-git call opens the packs and the commit-graph: about 65 µs and
20// 130 allocations before the call itself). The CLI keeps nothing open, so its
21// cold run is its warm run. Only the allocations of the Go process are
22// counted, which favours the CLI (its work happens in git processes). The
23// parallel runs (b.RunParallel) were also made: they agree with the warm runs
24// and widen the time gap.
25//
26// The numbers are the median of six runs of `go test -bench RepoReader
27// -benchmem -benchtime 500ms` on an AMD Ryzen 9 7900X3D, git 2.56, ermite-git
28// 5228465, as "time bytes allocations per call", CLI against ermite-git (K and
29// M are KiB and MiB). The fixture has 220 commits, 8 directories of 40 files
30// and a 10 MiB blob; lazygit has 7,550 commits. "loses" names what the
31// library does not win: t time, b bytes, a allocations.
32//
33//	shape                   repo     mode  cli                  ermite-git           verdict
34//	ListRefs                fixture  warm  905µs 116.3K 125     24µs 19.0K 73        win
35//	ListRefs                fixture  cold  904µs 116.3K 125     88µs 35.2K 203       loses a
36//	ListRefs                lazygit  warm  901µs 105.2K 88      15µs 2.2K 27         win
37//	ListRefs                lazygit  cold  908µs 105.4K 88      88µs 14.2K 163       loses a
38//	ResolveRevision/branch  fixture  warm  22µs 0.9K 19         4µs 0.4K 8           win
39//	ResolveRevision/branch  fixture  cold  22µs 0.9K 19         68µs 16.6K 138       loses tba
40//	ResolveRevision/branch  lazygit  warm  22µs 1.0K 19         4µs 0.5K 8           win
41//	ResolveRevision/branch  lazygit  cold  23µs 1.0K 19         72µs 12.4K 144       loses tba
42//	ResolveRevision/fullid  fixture  warm  9µs 1.3K 22          2µs 0.4K 6           win
43//	ResolveRevision/fullid  fixture  cold  9µs 1.3K 22          65µs 16.6K 136       loses tba
44//	ResolveRevision/fullid  lazygit  warm  9µs 1.3K 22          2µs 0.4K 6           win
45//	ResolveRevision/fullid  lazygit  cold  9µs 1.3K 22          70µs 12.3K 142       loses tba
46//	ResolveRevision/abbrev  fixture  warm  63µs 1.5K 31         9µs 0.7K 11          win
47//	ResolveRevision/abbrev  fixture  cold  64µs 1.5K 31         71µs 16.8K 141       loses tba
48//	ResolveRevision/abbrev  lazygit  warm  63µs 1.5K 31         9µs 0.6K 11          win
49//	ResolveRevision/abbrev  lazygit  cold  63µs 1.5K 31         76µs 12.6K 147       loses tba
50//	ResolveRefPath          fixture  warm  104µs 2.4K 59        15µs 0.8K 22         win
51//	ResolveRefPath          fixture  cold  105µs 2.4K 59        78µs 17.0K 152       loses ba
52//	ResolveRefPath          lazygit  warm  150µs 4.1K 79        22µs 1.4K 29         win
53//	ResolveRefPath          lazygit  cold  148µs 4.1K 79        89µs 13.4K 165       loses ba
54//	GetTree/root            fixture  warm  717µs 108.4K 114     13µs 5.8K 24         win
55//	GetTree/root            fixture  cold  725µs 108.4K 114     78µs 22.4K 154       loses a
56//	GetTree/root            lazygit  warm  827µs 121.4K 167     29µs 18.2K 56        win
57//	GetTree/root            lazygit  cold  831µs 121.5K 167     376µs 1.6M 200       loses ba
58//	GetTree/dir             fixture  warm  742µs 109.5K 141     16µs 9.2K 26         win
59//	GetTree/dir             fixture  cold  745µs 109.5K 141     109µs 75.8K 158      loses a
60//	GetTree/dir             lazygit  warm  1.4ms 267.9K 1058    193µs 318.4K 73      loses b
61//	GetTree/dir             lazygit  cold  1.4ms 268.0K 1058    4.2ms 2.0M 2490      loses tba
62//	GetTree/root+last       fixture  warm  4.0ms 1.2M 1023      70µs 108.3K 107      win
63//	GetTree/root+last       fixture  cold  4.0ms 1.2M 1024      165µs 127.8K 249     win
64//	GetTree/root+last       lazygit  warm  20.2ms 3.8M 3072     6.1ms 367.0K 510     win
65//	GetTree/root+last       lazygit  cold  20.3ms 3.8M 3073     8.5ms 3.4M 4204      loses a
66//	GetTree/dir+last        fixture  warm  5.3ms 1.8M 1454      190µs 166.1K 142     win
67//	GetTree/dir+last        fixture  cold  5.4ms 1.8M 1455      316µs 247.6K 323     win
68//	GetTree/dir+last        lazygit  warm  195.2ms 20.5M 17116  7.9ms 1.5M 855       win
69//	GetTree/dir+last        lazygit  cold  195.9ms 20.5M 17107  14.8ms 5.1M 6989     win
70//	OpenBlob/small          fixture  warm  46µs 6.1K 25         17µs 5.8K 14         win
71//	OpenBlob/small          fixture  cold  47µs 6.1K 25         87µs 27.7K 147       loses tba
72//	OpenBlob/small          lazygit  warm  51µs 5.4K 25         29µs 7.0K 42         loses ba
73//	OpenBlob/small          lazygit  cold  50µs 5.4K 25         131µs 25.1K 184      loses tba
74//	OpenBlob/largest        fixture  warm  21.4ms 69.7K 64      52.5ms 9.0K 13       loses t
75//	OpenBlob/largest        fixture  cold  21.6ms 70.0K 64      51.4ms 26.2K 143     loses ta
76//	OpenBlob/largest        lazygit  warm  3.3ms 69.9K 64       5.7ms 16.3K 123      loses ta
77//	OpenBlob/largest        lazygit  cold  3.3ms 69.9K 64       5.8ms 31.6K 283      loses ta
78//	ListCommits/page1       fixture  warm  1.0ms 122.5K 404     61µs 19.1K 108       win
79//	ListCommits/page1       fixture  cold  1.0ms 122.5K 404     134µs 36.9K 244      win
80//	ListCommits/page1       lazygit  warm  1.3ms 157.2K 415     361µs 120.1K 224     win
81//	ListCommits/page1       lazygit  cold  1.3ms 157.2K 415     503µs 136.2K 377     win
82//	ListCommits/deep        fixture  warm  1.0ms 122.1K 404     71µs 19.3K 108       win
83//	ListCommits/deep        fixture  cold  1.0ms 122.1K 404     136µs 36.1K 238      win
84//	ListCommits/deep        lazygit  warm  2.0ms 123.2K 404     424µs 23.9K 112      win
85//	ListCommits/deep        lazygit  cold  2.0ms 123.2K 404     544µs 36.3K 248      win
86//	ListCommits/path        fixture  warm  1.6ms 108.8K 138     443µs 25.4K 42       win
87//	ListCommits/path        fixture  cold  1.6ms 108.9K 138     594µs 93.6K 360      loses a
88//	ListCommits/path        lazygit  warm  12.9ms 108.7K 118    6.0ms 29.2K 58       win
89//	ListCommits/path        lazygit  cold  12.8ms 107.7K 118    9.5ms 2.4M 6498      loses ba
90//	ListCommits/dirpath     fixture  warm  1.3ms 123.0K 403     199µs 33.8K 113      win
91//	ListCommits/dirpath     fixture  cold  1.3ms 123.0K 403     277µs 55.4K 268      win
92//	ListCommits/dirpath     lazygit  warm  6.7ms 127.8K 403     2.0ms 50.2K 181      win
93//	ListCommits/dirpath     lazygit  cold  6.7ms 127.8K 403     3.3ms 887.1K 2019    loses ba
94//
95// What decides the routes, with ermite-git 5228465 (zlib reader with a reused
96// adler32, header-size cache, Refresh and LookupRefID without allocations):
97//
98//   - The warm runs all win but GetTree of a large directory on lazygit (time
99//     is won since the zlib change, bytes are not) and OpenBlob, whose
100//     allocations come from the inflate of a small blob and whose time is
101//     lost for a 10 MiB blob (inflate speed: 52 ms against 21 ms).
102//   - The cold runs lose in allocations for every method that does little
103//     work after the open (ListRefs, GetTree, ResolveRefPath: 150 to 200
104//     against 60 to 140), and in time too for the ones that cost a few
105//     microseconds warm (ResolveRevision: 65 µs against 9 to 63 µs).
106//   - Only the history of a revision (ListCommits page 1 and deep) wins every
107//     line, so it is the only method routed. GetTree dir+last also wins every
108//     line, but GetTreeLastCommits covers GetTree root+last too, which loses
109//     cold allocations on lazygit (4204 against 3073): it is the nearest
110//     miss, and the first to flip once opening a repository allocates less.
111//   - OpenBlob by size: below 1 MiB the small blob loses cold and, on lazygit,
112//     warm bytes and allocations; above, it loses time. No size makes it win,
113//     so there is no size-based route.
114//
115// Once opening a repository allocates less, re-run the benchmark and flip the
116// constants it wins: ListRefs, ResolveRefPath and ResolveRevision win warm by 4
117// to 60 times in time.
118func DefaultRoutes() Routes {
119	return Routes{
120		ListRefs:              CLI,
121		ResolveRevision:       CLI,
122		ResolveRevisionAbbrev: CLI,
123		ResolveRefPath:        CLI,
124		GetTree:               CLI,
125		GetTreeLastCommits:    CLI,
126		OpenBlob:              CLI,
127		ListCommits:           ErmiteGit,
128		ListCommitsPath:       CLI,
129	}
130}

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