Minimal, read-only git library for status detection in cupidfm.
cupidgit is a lightweight C library that provides git repository detection and file status calculation. It parses .git/index files directly and compares working tree files against the index to determine modification status.
No external dependencies - Uses a custom SHA-1 implementation (cupidsha) instead of OpenSSL.
- Repository detection - Walk up directory tree to find
.git - Git index parsing - Parse binary
.git/indexformat (versions 2, 3, 4) - File status calculation - Determine if files are modified, untracked, or unmodified
- SHA-1 hashing - Custom implementation for git object hash computation
- Performance optimized - mtime-based fast path, hash-based slow path
- Zero external dependencies - Self-contained with custom SHA-1
git_repo.c/h- Repository detection and initializationgit_index.c/h- Binary index file parsinggit_status.c/h- Status calculation (compare working tree vs index)git_hash.c/h- Git object hash computationsha1.c/h- Custom SHA-1 implementation (cupidsha)
- Check if file is in git index
- Not in index →
GIT_STATUS_UNTRACKED(🟢)
- Not in index →
- Compare file mtime with index entry mtime
- Matches →
GIT_STATUS_UNMODIFIED(⚪) [fast path]
- Matches →
- If mtime differs, compute SHA-1 hash
- Hash matches index →
GIT_STATUS_UNMODIFIED(⚪) - Hash differs →
GIT_STATUS_MODIFIED(🔴)
- Hash matches index →
// Repository management
GitRepository* git_repo_open(const char *path);
void git_repo_free(GitRepository *repo);
bool git_repo_is_valid(GitRepository *repo);
const char* git_repo_root(GitRepository *repo);
// Status queries
typedef enum {
GIT_STATUS_UNTRACKED = 0, // 🟢 Not in index
GIT_STATUS_UNMODIFIED, // ⚪ Tracked, no changes
GIT_STATUS_MODIFIED, // 🔴 Working tree differs from index
GIT_STATUS_ERROR // Error checking status
} GitStatus;
GitStatus git_file_status(GitRepository *repo, const char *path);
// Utility
const char* git_status_emoji(GitStatus status);#include "cupidgit.h"
// Open repository
GitRepository *repo = git_repo_open("/path/to/repo");
if (!repo) {
// Not a git repository
return;
}
// Check file status
GitStatus status = git_file_status(repo, "/path/to/repo/file.txt");
switch (status) {
case GIT_STATUS_MODIFIED:
printf("File is modified 🔴\n");
break;
case GIT_STATUS_UNTRACKED:
printf("File is untracked 🟢\n");
break;
case GIT_STATUS_UNMODIFIED:
printf("File is unmodified ⚪\n");
break;
case GIT_STATUS_ERROR:
printf("Error checking status\n");
break;
}
// Cleanup
git_repo_free(repo);makeProduces libcupidgit.a static library.
None! - Fully self-contained with custom SHA-1 implementation.
Previous versions used OpenSSL for SHA-1, but this has been replaced with a custom implementation (cupidsha) to eliminate external dependencies.
- mtime fast path - Avoids hashing 99% of files
- Index parsing - ~1ms for 1000 files
- Status calculation - <100μs per file (mtime match)
- SHA-1 hashing - <5ms for 1MB file
The library supports git index versions 2, 3, and 4. Each index entry contains:
Fixed fields (62 bytes):
- ctime: 8 bytes
- mtime: 8 bytes (seconds + nanoseconds)
- dev, ino, mode, uid, gid: 20 bytes
- file size: 4 bytes
- SHA-1 hash: 20 bytes
- flags: 2 bytes (includes path length)
Variable fields:
- Path: null-terminated, padded to 8-byte alignment
cupidsha provides a minimal, standards-compliant SHA-1 implementation:
- Processes data in 64-byte blocks
- Uses standard SHA-1 constants and operations
- Produces 20-byte (160-bit) digest
- Compatible with git's object hashing format
Git object hashing format:
sha1("blob " + filesize + "\0" + contents)
Symlinks are hashed using their target path:
sha1("blob " + target_length + "\0" + target_path)
- Read-only - No git operations (add, commit, etc.)
- No .gitignore - Shows all untracked files
- No staged status - Doesn't compare index vs HEAD
- File size limit - 100MB maximum for SHA-1 hashing
- Bare repositories - Not supported
Manual testing with git repositories:
# Create test repository
mkdir test_repo && cd test_repo
git init
echo "content" > file.txt
git add file.txt
git commit -m "Initial"
# Test modified file
echo "changed" > file.txt
# Test untracked file
echo "new" > untracked.txt
# Run cupidfm to see indicators
cupidfm .Expected results:
file.txtshows 🔴 (modified)untracked.txtshows 🟢 (untracked)- Any other committed files show ⚪ (unmodified)
cupidgit is designed to integrate seamlessly with cupidfm:
- Initialization: Call
git_init()on startup - Directory changes: Call
git_update_directory(path)when navigating - File queries: Call
git_query_file_status(path)for each file - Cleanup: Call
git_cleanup()on shutdown
The library maintains a single global repository context and automatically detects when entering/exiting git repositories.
Part of cupidfm - GNU General Public License v3.0