Skip to content

Minimal, read-only git library for status detection in cupidfm.

License

Notifications You must be signed in to change notification settings

cupidthecat/cupidgit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

cupidgit

Minimal, read-only git library for status detection in cupidfm.

Overview

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.

Features

  • Repository detection - Walk up directory tree to find .git
  • Git index parsing - Parse binary .git/index format (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

Architecture

Components

  • git_repo.c/h - Repository detection and initialization
  • git_index.c/h - Binary index file parsing
  • git_status.c/h - Status calculation (compare working tree vs index)
  • git_hash.c/h - Git object hash computation
  • sha1.c/h - Custom SHA-1 implementation (cupidsha)

Status Detection Algorithm

  1. Check if file is in git index
    • Not in index → GIT_STATUS_UNTRACKED (🟢)
  2. Compare file mtime with index entry mtime
    • Matches → GIT_STATUS_UNMODIFIED (⚪) [fast path]
  3. If mtime differs, compute SHA-1 hash
    • Hash matches index → GIT_STATUS_UNMODIFIED (⚪)
    • Hash differs → GIT_STATUS_MODIFIED (🔴)

API

// 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);

Usage Example

#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);

Building

make

Produces libcupidgit.a static library.

Dependencies

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.

Performance

  • 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

Implementation Details

Git Index Format

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

SHA-1 Implementation

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)

Symlink Support

Symlinks are hashed using their target path:

sha1("blob " + target_length + "\0" + target_path)

Limitations

  • 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

Testing

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.txt shows 🔴 (modified)
  • untracked.txt shows 🟢 (untracked)
  • Any other committed files show ⚪ (unmodified)

Integration with cupidfm

cupidgit is designed to integrate seamlessly with cupidfm:

  1. Initialization: Call git_init() on startup
  2. Directory changes: Call git_update_directory(path) when navigating
  3. File queries: Call git_query_file_status(path) for each file
  4. Cleanup: Call git_cleanup() on shutdown

The library maintains a single global repository context and automatically detects when entering/exiting git repositories.

References

License

Part of cupidfm - GNU General Public License v3.0

About

Minimal, read-only git library for status detection in cupidfm.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published