rustic-git 0.1.0

A Rustic Git - clean type-safe API over git cli
Documentation
# Rustic Git

A Rust library for Git repository operations with a clean, type-safe API.

## Overview

Rustic Git provides a simple, ergonomic interface for common Git operations. It follows a repository-centric design where you create a `Repository` instance and call methods on it to perform Git operations.

## Features

- ✅ Repository initialization and opening
- ✅ File status checking with detailed parsing  
- ✅ File staging (add files, add all, add updates)
- ✅ Commit creation with hash return
- ✅ Type-safe error handling
- ✅ Universal `Hash` type for Git objects
- ✅ Comprehensive test coverage

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
rustic-git = "0.1.0"
```

## Quick Start

```rust
use rustic_git::{Repository, Result};

fn main() -> Result<()> {
    // Initialize a new repository
    let repo = Repository::init("/path/to/repo", false)?;
    
    // Or open an existing repository
    let repo = Repository::open("/path/to/existing/repo")?;
    
    // Check repository status
    let status = repo.status()?;
    if !status.is_clean() {
        println!("Modified files: {:?}", status.modified_files());
        println!("Untracked files: {:?}", status.untracked_files());
    }
    
    // Stage files
    repo.add(&["file1.txt", "file2.txt"])?;
    // Or stage all changes
    repo.add_all()?;
    
    // Create a commit
    let hash = repo.commit("Add new features")?;
    println!("Created commit: {}", hash.short());
    
    Ok(())
}
```

## API Documentation

### Repository Lifecycle

#### `Repository::init(path, bare) -> Result<Repository>`

Initialize a new Git repository.

```rust
// Initialize a regular repository
let repo = Repository::init("/path/to/repo", false)?;

// Initialize a bare repository  
let bare_repo = Repository::init("/path/to/bare-repo", true)?;
```

#### `Repository::open(path) -> Result<Repository>`

Open an existing Git repository.

```rust
let repo = Repository::open("/path/to/existing/repo")?;
```

### Status Operations

#### `Repository::status() -> Result<GitStatus>`

Get the current repository status.

```rust
let status = repo.status()?;

// Check if repository is clean
if status.is_clean() {
    println!("No changes");
} else {
    println!("Repository has changes");
}

// Get files by status
let modified = status.modified_files();
let untracked = status.untracked_files();

// Or work with all files directly
for (file_status, filename) in &status.files {
    println!("{:?}: {}", file_status, filename);
}
```

The `GitStatus` struct contains:
- `files: Box<[(FileStatus, String)]>` - All files with their status
- `is_clean()` - Returns true if no changes
- `has_changes()` - Returns true if any changes exist
- `modified_files()` - Get all modified files
- `untracked_files()` - Get all untracked files
- `files_with_status(status)` - Get files with specific status

#### File Status Types

```rust
pub enum FileStatus {
    Modified,   // File has been modified
    Added,      // File has been added to index
    Deleted,    // File has been deleted
    Renamed,    // File has been renamed
    Copied,     // File has been copied
    Untracked,  // File is not tracked by git
    Ignored,    // File is ignored by git
}
```

### Staging Operations

#### `Repository::add(paths) -> Result<()>`

Add specific files to the staging area.

```rust
// Add single file
repo.add(&["file.txt"])?;

// Add multiple files
repo.add(&["file1.txt", "file2.txt", "dir/file3.txt"])?;

// Add with Path objects
use std::path::Path;
repo.add(&[Path::new("file.txt")])?;
```

#### `Repository::add_all() -> Result<()>`

Add all changes to the staging area (equivalent to `git add .`).

```rust
repo.add_all()?;
```

#### `Repository::add_update() -> Result<()>`

Add all tracked files that have been modified (equivalent to `git add -u`).

```rust
repo.add_update()?;
```

### Commit Operations

#### `Repository::commit(message) -> Result<Hash>`

Create a commit with the given message.

```rust
let hash = repo.commit("Fix critical bug")?;
println!("Commit created: {}", hash);
println!("Short hash: {}", hash.short());
```

#### `Repository::commit_with_author(message, author) -> Result<Hash>`

Create a commit with a custom author.

```rust
let hash = repo.commit_with_author(
    "Add new feature", 
    "Jane Developer <jane@example.com>"
)?;
```

### Hash Type

The `Hash` type represents Git object hashes (commits, trees, blobs, etc.).

```rust
let hash = repo.commit("message")?;

// Get full hash as string
let full_hash: &str = hash.as_str();

// Get short hash (first 7 characters)
let short_hash: &str = hash.short();

// Display formatting
println!("Commit: {}", hash);  // Displays full hash
```

## Error Handling

All operations return `Result<T, GitError>` for proper error handling.

```rust
use rustic_git::{Repository, GitError};

match repo.commit("message") {
    Ok(hash) => println!("Success: {}", hash),
    Err(GitError::CommandFailed(msg)) => eprintln!("Git command failed: {}", msg),
    Err(GitError::IoError(msg)) => eprintln!("IO error: {}", msg),
}
```

## Complete Workflow Example

```rust
use rustic_git::{Repository, FileStatus};
use std::fs;

fn main() -> rustic_git::Result<()> {
    // Create a new repository
    let repo = Repository::init("./my-project", false)?;
    
    // Create some files
    fs::write("./my-project/README.md", "# My Project")?;
    fs::write("./my-project/src/main.rs", "fn main() { println!(\"Hello!\"); }")?;
    fs::create_dir_all("./my-project/src")?;
    
    // Check status
    let status = repo.status()?;
    println!("Found {} untracked files", status.untracked_files().len());
    
    // Stage all files
    repo.add_all()?;
    
    // Verify staging
    let status = repo.status()?;
    let added_files: Vec<_> = status.files.iter()
        .filter(|(s, _)| matches!(s, FileStatus::Added))
        .map(|(_, f)| f)
        .collect();
    println!("Staged files: {:?}", added_files);
    
    // Create initial commit
    let hash = repo.commit("Initial commit with project structure")?;
    println!("Created commit: {}", hash.short());
    
    // Verify clean state
    let status = repo.status()?;
    assert!(status.is_clean());
    println!("Repository is now clean!");
    
    Ok(())
}
```

## Testing

Run the test suite:

```bash
cargo test
```

All tests create temporary repositories in `/tmp/` and clean up after themselves.

## Contributing

This library follows these design principles:

- **Repository-centric API**: Static lifecycle methods (`init`, `open`) return `Repository` instances
- **Type safety**: Strong typing with custom error types and structured return values  
- **Ergonomic design**: Clean, intuitive API that follows Rust conventions
- **Comprehensive testing**: All functionality thoroughly tested
- **Modular organization**: Commands organized in separate modules

## License

MIT License - see LICENSE file for details.

## Roadmap

Future planned features:
- [ ] Commit history and log operations
- [ ] Diff operations  
- [ ] Branch operations
- [ ] Remote operations (clone, push, pull)
- [ ] Merge and rebase operations
- [ ] Tag operations
- [ ] Stash operations

## Version

Current version: 0.1.0 - Basic git workflow (init, status, add, commit)