cgit reimplements git's core plumbing commands in C: init, hash-object, cat-file, ls-tree, write-tree, and commit-tree. It stores and retrieves objects in git's binary format, computes SHA-1 hashes with OpenSSL, and compresses objects with zlib. The objects cgit writes have the same content as git's for files, folders and commits, except for the cases listed under Known Limitations. Real git can read them, and cgit can read objects written by git.
cgit has three layers. main.c owns the dispatch table: it parses argv, matches the command name in a static array of structs, and calls the matching handler. The command layer (commands/) validates arguments, calls into core, and formats output. The core layer (core/) implements object I/O, hashing, compression, tree parsing, and path utilities. Dependencies point only downward; core has no knowledge of which commands exist or which flags they parse.
cmake -B build && cmake --build buildRequires CMake 4.2 or later, OpenSSL, and zlib. On macOS, OpenSSL is detected automatically via Homebrew.
cgit init
cgit hash-object -w <file>
cgit cat-file -p <hash>
cgit cat-file -t <hash>
cgit cat-file -s <hash>
cgit cat-file -e <hash>
cgit ls-tree [--name-only] <hash>
cgit write-tree
cgit commit-tree <tree-hash> [-p <parent-hash>] -m <message>All decision records live in docs/adr/. Each file documents the context, the options considered, and the consequences for the codebase.
init, hash-object, cat-file, ls-tree, write-tree, and commit-tree are implemented, and their output was checked against real git in the verification report. Author and committer identity in commit-tree are compile-time constants; there is no config file parsing. Objects are addressed by full 40-character SHA-1 hex; there is no ref resolution, no HEAD dereferencing, and no branch tracking. The staging area is not implemented: write-tree reads the working directory directly. Only loose objects are supported; pack files are not.
- A folder and a file whose names start the same way, such as
foo/andfoo.txt, are ordered differently from git. - Empty folders are included, while git ignores them.
- Symbolic links are saved as regular files.
- A commit message that already ends with a new line gets an extra one.
- The files on disk are compressed slightly differently from git's, even though their content is the same.