detached 83c704c

build(mmap): map packs on openbsd, netbsd and dragonfly; document limits (GO-007, GO-008)

syscall.Mmap exists on these systems. README gains a Limits section: the
SIGBUS on in-place truncation and the in-memory fallback elsewhere are
deferred, and the Resolve order is documented.
commit
83c704caf029705bccef04865ea6a557a583505b
author
brice · · 2026-10-10 22:15 UTC
parent
3c103d3
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
4 files · +9 -3
M README.md +6 -0
@@ -41,6 +41,12 @@ A `Repo` is safe for concurrent use. Call `Refresh` after the repository changed
4141
4242 Repositories the package does not read are rejected by `Open` with `ErrUnsupported`: SHA-256, reftable, other `extensions.*`, shallow, grafts, replace refs, alternates, partial clones, incremental or stale multi-pack-index.
4343
44+## Limits
45+
46+- **A pack truncated in place can crash the process.** Packs and indexes are memory-mapped; if another process shrinks one of them while it is mapped, a read of the missing part ends with SIGBUS, which Go cannot recover from. Git always replaces a pack by renaming a new file over it (repack, gc, fetch), and a mapping keeps the old file alive, so this takes an external actor that edits packs in place, or a failing disk. Not handled.
47+- **Without mmap, packs are read into memory.** Linux, macOS, FreeBSD, OpenBSD, NetBSD and DragonFly map packs. On Windows and other systems the whole `.pack` and `.idx` are read into memory when a pack is opened, so memory grows with the size of the repository. Not handled.
48+- **Revision names.** `Resolve` follows `git rev-parse` for plain names: a tag wins over a branch of the same name, and a full 40 digit id is never read as a ref. Use `ResolveRef` for a full ref name and `ResolveCommitPrefix` for an abbreviation that must designate a commit.
49+
4450 ## Test
4551
4652 ```sh
@@ -41,6 +41,12 @@ A `Repo` is safe for concurrent use. Call `Refresh` after the repository changed
41 41
42 Repositories the package does not read are rejected by `Open` with `ErrUnsupported`: SHA-256, reftable, other `extensions.*`, shallow, grafts, replace refs, alternates, partial clones, incremental or stale multi-pack-index.42 Repositories the package does not read are rejected by `Open` with `ErrUnsupported`: SHA-256, reftable, other `extensions.*`, shallow, grafts, replace refs, alternates, partial clones, incremental or stale multi-pack-index.
43 43
44+## Limits
45+
46+- **A pack truncated in place can crash the process.** Packs and indexes are memory-mapped; if another process shrinks one of them while it is mapped, a read of the missing part ends with SIGBUS, which Go cannot recover from. Git always replaces a pack by renaming a new file over it (repack, gc, fetch), and a mapping keeps the old file alive, so this takes an external actor that edits packs in place, or a failing disk. Not handled.
47+- **Without mmap, packs are read into memory.** Linux, macOS, FreeBSD, OpenBSD, NetBSD and DragonFly map packs. On Windows and other systems the whole `.pack` and `.idx` are read into memory when a pack is opened, so memory grows with the size of the repository. Not handled.
48+- **Revision names.** `Resolve` follows `git rev-parse` for plain names: a tag wins over a branch of the same name, and a full 40 digit id is never read as a ref. Use `ResolveRef` for a full ref name and `ResolveCommitPrefix` for an abbreviation that must designate a commit.
49+
44 ## Test50 ## Test
45 51
46 ```sh52 ```sh
M mmap_notlinux.go +1 -1
@@ -1,6 +1,6 @@
11 // SPDX-License-Identifier: MIT
22
3-//go:build darwin || freebsd
3+//go:build darwin || freebsd || openbsd || netbsd || dragonfly
44
55 package git
66
@@ -1,6 +1,6 @@
1 // SPDX-License-Identifier: MIT1 // SPDX-License-Identifier: MIT
2 2
3-//go:build darwin || freebsd3+//go:build darwin || freebsd || openbsd || netbsd || dragonfly
4 4
5 package git5 package git
6 6
M mmap_other.go +1 -1
@@ -1,6 +1,6 @@
11 // SPDX-License-Identifier: MIT
22
3-//go:build !(linux || darwin || freebsd)
3+//go:build !(linux || darwin || freebsd || openbsd || netbsd || dragonfly)
44
55 package git
66
@@ -1,6 +1,6 @@
1 // SPDX-License-Identifier: MIT1 // SPDX-License-Identifier: MIT
2 2
3-//go:build !(linux || darwin || freebsd)3+//go:build !(linux || darwin || freebsd || openbsd || netbsd || dragonfly)
4 4
5 package git5 package git
6 6
M mmap_unix.go +1 -1
@@ -1,6 +1,6 @@
11 // SPDX-License-Identifier: MIT
22
3-//go:build linux || darwin || freebsd
3+//go:build linux || darwin || freebsd || openbsd || netbsd || dragonfly
44
55 package git
66
@@ -1,6 +1,6 @@
1 // SPDX-License-Identifier: MIT1 // SPDX-License-Identifier: MIT
2 2
3-//go:build linux || darwin || freebsd3+//go:build linux || darwin || freebsd || openbsd || netbsd || dragonfly
4 4
5 package git5 package git
6 6

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 1

Tags 2

↑↓ moveenter openesc close