1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# Furgit
[](https://builds.sr.ht/~runxiyu/furgit)
[](https://pkg.go.dev/codeberg.org/lindenii/furgit)
Furgit is a low-level Git library in Go.
## Status
* Several years away from stable
* Do not use in production
* Mature alternative: [go-git](https://github.com/go-git/go-git)
* Will use [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) starting at 1.0.0
## Goals
* General-purpose Git plumbing library for UNIX-like systems
* Aim for extremely clear and modular architecture
* Then aim for high performance
* Expect familiarity with Git internals
## Finding your way around
If you are working with an on-disk repository, start with
`repository.Open(...)`. It opens the repository and wires together the refs storage, object
storage, and resolver.
That gives you a repository handle with a few different entry points, but they
serve different purposes:
* `repo.Refs()` is for branch names, tags, `HEAD`, and ref updates.
* Use it when you are starting from names rather than object IDs.
* A common pattern is to resolve a ref first, then pass the resulting object
ID to the resolver.
* `repo.Resolver()` is the main object-facing API for most callers.
* Use it when you want commits, trees, blobs, or tags as typed values.
* It also handles peeling through annotated tags, resolving objects to the
type you actually want, and walking paths inside trees.
* It even allows you to access a tree as an `io/fs.FS`.
* If your goal is "show me this commit", "read this tree", "follow this tag",
or "get me the file at this path", this is usually the right layer.
* `repo.Objects()` is the storage layer underneath resolution.
* Use it when you need to read object headers, read raw object contents,
stream object data, or otherwise look up objects directly by ID.
* Most callers who want to work with Git objects as commits, trees, blobs, or
tags should prefer the resolver instead.
* However, checking an object ID's size and type are somewhat common
operations that should be done here.
Some object concepts are kept separate:
* `object` contains parsed Git object values such as blobs, trees, commits, and
tags. These are the decoded contents of Git objects and do not tell you
anything about the object's identity.
* `object/stored` wraps a parsed object together with the object ID it was
loaded from. This is used when you need both the parsed value and the
identity it was loaded under.
As a rule of thumb:
* If you have a ref name, start with `repo.Refs()`.
* If you want typed objects or path-based access, use `repo.Resolver()`.
* If you need raw object lookup by ID, object headers, or object streams, use
`repo.Objects()`.
Some useful operations are built separately and are meant to be constructed
over the stores that `Repository` already exposes:
* To check whether one revision is an ancestor of another, or to compute merge
bases, construct a `commitquery.Query` over `repo.Objects()`.
* This is the tool to reach for when you already have object IDs and want to
ask commit-history questions.
* If you already have a commit-graph reader, pass it in as well for
performance.
* To walk commits or all reachable objects from a set of starting points,
construct a `reachability.Reachability` over `repo.Objects()`.
* Use commit traversal when you only care about history, and full object
traversal when you care about the complete reachable object set.
* This is useful for tasks such as connectivity checks and computing the
object set that a fetch or push needs to account for.
* To accept pushes on the server side, construct `receivepack` or
`receivepack/service` with the repository's ref store, object store, and
object ID algorithm.
* Push handling also needs the repository's object storage root so incoming
objects can be quarantined and later promoted.
* `Repository` does not currently expose that root directly (we'll consider
possible solutions sometime later), so a push server usually keeps the
repository path or object root handle alongside the `Repository` value.
* Hook-based checks are just Go functions; then, a fast-forward check can use
`commitquery` over the existing and quarantined object stores. Some hooks
are provided.
## Community
* [#lindenii](https://webirc.runxiyu.org/kiwiirc/#lindenii)
on [irc.runxiyu.org](https://irc.runxiyu.org)
* [#lindenii](https://web.libera.chat/#lindenii)
on [Libera.Chat](https://libera.chat)
See the CONTRIBUTING document for bug reports and patch submissions.
## Acknowledgements
Partly inspired by [upstream Git](https://git-scm.com),
OpenBSD's [Game of Trees](https://gameoftrees.org), and
[9front Git](https://git.9front.org/plan9front/9front/HEAD/sys/src/cmd/git/f.html).
## License
This project is licensed under the GNU Affero General Public License,
Version 3.0 only.
Pursuant to Section 14 of the GNU Affero General Public License, Version 3.0,
[Runxi Yu](https://runxiyu.org) is hereby designated as the proxy who is
authorized to issue a public statement accepting any future version of the
GNU Affero General Public License for use with this Program.
Therefore, notwithstanding the specification that this Program is licensed
under the GNU Affero General Public License, Version 3.0 only, a public
acceptance by the Designated Proxy of any subsequent version of the GNU Affero
General Public License shall permanently authorize the use of that accepted
version for this Program.
|