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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
# cgit — Overview
## What Is cgit?
cgit is a fast, lightweight web frontend for Git repositories, implemented as a
CGI application written in C. It links directly against libgit (the C library
that forms the core of the `git` command-line tool), giving it native access to
repository objects without spawning external processes for every request. This
design makes cgit one of the fastest Git web interfaces available.
The Project Tick fork carries version `0.0.5-1-Project-Tick` (defined in the
top-level `Makefile` as `CGIT_VERSION`). It builds against Git 2.46.0 and
extends the upstream cgit with features such as subtree display, SPDX license
detection, badge support, Code of Conduct / CLA pages, root links, and an
enhanced summary page with repository metadata.
## Key Design Goals
| Goal | How cgit achieves it |
|------|---------------------|
| **Speed** | Direct libgit linkage; file-based response cache; `sendfile()` on Linux |
| **Security** | `GIT_CONFIG_NOSYSTEM=1` set at load time; HTML entity escaping in every output function; directory-traversal guards; auth-filter framework |
| **Simplicity** | Single CGI binary; flat config file (`cgitrc`); no database requirement |
| **Extensibility** | Pluggable filter system (exec / Lua) for about, commit, source, email, owner, and auth content |
## Source File Map
The entire cgit source tree lives in `cgit/`. Every `.c` file has a matching
`.h` (with a few exceptions such as `shared.c` and `parsing.c` which declare
their interfaces in `cgit.h`).
### Core files
| File | Purpose |
|------|---------|
| `cgit.h` | Master header — includes libgit headers; defines all major types (`cgit_repo`, `cgit_config`, `cgit_query`, `cgit_context`, etc.) and function prototypes |
| `cgit.c` | Entry point — `prepare_context()`, `config_cb()`, `querystring_cb()`, `process_request()`, `main()` |
| `shared.c` | Global variables (`cgit_repolist`, `ctx`); repo management (`cgit_add_repo`, `cgit_get_repoinfo`); diff helpers; parsing helpers |
| `parsing.c` | Commit/tag parsing (`cgit_parse_commit`, `cgit_parse_tag`, `cgit_parse_url`) |
| `cmd.c` | Command dispatch table — maps URL page names to handler functions |
| `cmd.h` | `struct cgit_cmd` definition; `cgit_get_cmd()` prototype |
| `configfile.c` | Generic `name=value` config parser (`parse_configfile`) |
| `configfile.h` | `configfile_value_fn` typedef; `parse_configfile` prototype |
### Infrastructure files
| File | Purpose |
|------|---------|
| `cache.c` / `cache.h` | File-based response cache — FNV-1 hashing, slot open/lock/fill/unlock cycle |
| `filter.c` | Filter framework — exec filters (fork/exec), Lua filters (`luaL_newstate`) |
| `html.c` / `html.h` | HTML output primitives — entity escaping, URL encoding, form helpers |
| `scan-tree.c` / `scan-tree.h` | Filesystem repository scanning — `scan_tree()`, `scan_projects()` |
### UI modules (`ui-*.c` / `ui-*.h`)
| Module | Page | Handler function |
|--------|------|-----------------|
| `ui-repolist` | `repolist` | `cgit_print_repolist()` |
| `ui-summary` | `summary` | `cgit_print_summary()` |
| `ui-log` | `log` | `cgit_print_log()` |
| `ui-commit` | `commit` | `cgit_print_commit()` |
| `ui-diff` | `diff` | `cgit_print_diff()` |
| `ui-tree` | `tree` | `cgit_print_tree()` |
| `ui-blob` | `blob` | `cgit_print_blob()` |
| `ui-refs` | `refs` | `cgit_print_refs()` |
| `ui-tag` | `tag` | `cgit_print_tag()` |
| `ui-snapshot` | `snapshot` | `cgit_print_snapshot()` |
| `ui-plain` | `plain` | `cgit_print_plain()` |
| `ui-blame` | `blame` | `cgit_print_blame()` |
| `ui-patch` | `patch` | `cgit_print_patch()` |
| `ui-atom` | `atom` | `cgit_print_atom()` |
| `ui-clone` | `HEAD` / `info` / `objects` | `cgit_clone_head()`, `cgit_clone_info()`, `cgit_clone_objects()` |
| `ui-stats` | `stats` | `cgit_show_stats()` |
| `ui-ssdiff` | (helper) | Side-by-side diff rendering via LCS algorithm |
| `ui-shared` | (helper) | HTTP headers, HTML page skeleton, link generation |
### Static assets
| File | Description |
|------|-------------|
| `cgit.css` | Default stylesheet |
| `cgit.js` | Client-side JavaScript (e.g. tree filtering) |
| `cgit.png` | Default logo |
| `favicon.ico` | Default favicon |
| `robots.txt` | Default robots file |
## Core Data Structures
All major types are defined in `cgit.h`. The single global
`struct cgit_context ctx` (declared in `shared.c`) holds the entire request
state:
```c
struct cgit_context {
struct cgit_environment env; /* CGI environment variables */
struct cgit_query qry; /* Parsed query/URL parameters */
struct cgit_config cfg; /* Global configuration */
struct cgit_repo *repo; /* Currently selected repository (or NULL) */
struct cgit_page page; /* HTTP response metadata */
};
```
### `struct cgit_repo`
Represents a single Git repository. Key fields:
```c
struct cgit_repo {
char *url; /* URL-visible name (e.g. "myproject") */
char *name; /* Display name */
char *basename; /* Last path component */
char *path; /* Filesystem path to .git directory */
char *desc; /* Description string */
char *owner; /* Repository owner */
char *defbranch; /* Default branch (NULL → guess from HEAD) */
char *section; /* Section for grouped display */
char *clone_url; /* Clone URL override */
char *homepage; /* Project homepage URL */
struct string_list readme; /* README file references */
struct string_list badges; /* Badge image URLs */
int snapshots; /* Bitmask of enabled snapshot formats */
int enable_blame; /* Whether blame view is enabled */
int enable_commit_graph;/* Whether commit graph is shown in log */
int enable_subtree; /* Whether subtree detection is enabled */
int max_stats; /* Stats period index (0=disabled) */
int hide; /* 1 = hidden from listing */
int ignore; /* 1 = completely ignored */
struct cgit_filter *about_filter; /* Per-repo about filter */
struct cgit_filter *source_filter; /* Per-repo source highlighting */
struct cgit_filter *email_filter; /* Per-repo email filter */
struct cgit_filter *commit_filter; /* Per-repo commit message filter */
struct cgit_filter *owner_filter; /* Per-repo owner filter */
/* ... */
};
```
### `struct cgit_query`
Holds all parsed URL/query-string parameters:
```c
struct cgit_query {
int has_symref, has_oid, has_difftype;
char *raw; /* Raw query string */
char *repo; /* Repository URL */
char *page; /* Page name (log, commit, diff, ...) */
char *search; /* Search query (q=) */
char *grep; /* Search type (qt=) */
char *head; /* Branch/ref (h=) */
char *oid, *oid2; /* Object IDs (id=, id2=) */
char *path; /* Path within repository */
char *name; /* Snapshot filename */
int ofs; /* Pagination offset */
int showmsg; /* Show full commit messages in log */
diff_type difftype; /* DIFF_UNIFIED / DIFF_SSDIFF / DIFF_STATONLY */
int context; /* Diff context lines */
int ignorews; /* Ignore whitespace in diffs */
int follow; /* Follow renames in log */
char *vpath; /* Virtual path (set by cmd dispatch) */
/* ... */
};
```
## Request Lifecycle
1. **Environment setup** — The `constructor_environment()` function runs before
`main()` (via `__attribute__((constructor))`). It sets
`GIT_CONFIG_NOSYSTEM=1` and `GIT_ATTR_NOSYSTEM=1`, then unsets `HOME` and
`XDG_CONFIG_HOME` to prevent Git from reading user/system configurations.
2. **Context initialization** — `prepare_context()` zeroes out `ctx` and sets
all configuration defaults (cache sizes, TTLs, feature flags, etc.). CGI
environment variables are read from `getenv()`.
3. **Configuration parsing** — `parse_configfile()` reads the cgitrc file
(default `/etc/cgitrc`, overridable via `$CGIT_CONFIG`) and calls
`config_cb()` for each `name=value` pair. Repository definitions begin with
`repo.url=` and subsequent `repo.*` directives configure that repository.
4. **Query parsing** — If running in CGI mode (no `$NO_HTTP`),
`http_parse_querystring()` breaks the query string into name/value pairs and
passes them to `querystring_cb()`. The `url=` parameter is further parsed by
`cgit_parse_url()` which splits it into repo, page, and path components.
5. **Authentication** — `authenticate_cookie()` checks whether an `auth-filter`
is configured. If so, it invokes the filter with function
`"authenticate-cookie"` and sets `ctx.env.authenticated` from the filter's
exit code. POST requests to `/?p=login` route through
`authenticate_post()` instead.
6. **Cache lookup** — If caching is enabled (`cache-size > 0`), a cache key is
constructed from the URL and passed to `cache_process()`. On a cache hit the
stored response is sent directly via `sendfile()`. On a miss, stdout is
redirected to a lock file and the request proceeds through normal processing.
7. **Command dispatch** — `cgit_get_cmd()` looks up `ctx.qry.page` in the
static `cmds[]` table (defined in `cmd.c`). If the command requires a
repository (`want_repo == 1`), the repository is initialized via
`prepare_repo_env()` and `prepare_repo_cmd()`.
8. **Page rendering** — The matched command's handler function is called. Each
handler uses `cgit_print_http_headers()`, `cgit_print_docstart()`,
`cgit_print_pageheader()`, and `cgit_print_docend()` (from `ui-shared.c`)
to frame their output inside a proper HTML document.
9. **Cleanup** — `cgit_cleanup_filters()` reaps all filter resources (closing
Lua states, freeing argv arrays).
## Version String
The version is compiled into the binary via:
```makefile
CGIT_VERSION = 0.0.5-1-Project-Tick
```
and exposed as the global:
```c
const char *cgit_version = CGIT_VERSION;
```
This string appears in the HTML footer (rendered by `ui-shared.c`) and in patch
output trailers.
## Relationship to Git
cgit is built *inside* the Git source tree. The `Makefile` downloads
Git 2.46.0, extracts it as a `git/` subdirectory, then calls `make -C git -f
../cgit.mk` which includes Git's own `Makefile` to inherit all build variables,
object files, and linker flags. The resulting `cgit` binary is a statically
linked combination of cgit's own object files and libgit.
## Time Constants
`cgit.h` defines convenience macros used for relative date display:
```c
#define TM_MIN 60
#define TM_HOUR (TM_MIN * 60)
#define TM_DAY (TM_HOUR * 24)
#define TM_WEEK (TM_DAY * 7)
#define TM_YEAR (TM_DAY * 365)
#define TM_MONTH (TM_YEAR / 12.0)
```
These are used by `cgit_print_age()` in `ui-shared.c` to render "2 hours ago"
style timestamps.
## Default Encoding
```c
#define PAGE_ENCODING "UTF-8"
```
All commit messages are re-encoded to UTF-8 before display (see
`cgit_parse_commit()` in `parsing.c`).
## License
cgit is licensed under the GNU General Public License v2. The `COPYING` file
in the cgit directory contains the full text.
|