Skip to content

Commit 67e2380

Browse files
committed
feat: implement commit functionality and refactor to Hash type
Add Repository::commit() and commit_with_author() methods that create commits and return Hash objects. Refactor CommitHash to shorter Hash type in dedicated types module for broader reusability. Include comprehensive README with full API documentation and usage examples. - Add commit.rs with commit creation and validation - Create types.rs module with universal Hash type - Add comprehensive test coverage for commit operations - Create complete README.md with API docs and examples - Update CLAUDE.md with latest implementation status
1 parent 57570ee commit 67e2380

File tree

6 files changed

+579
-3
lines changed

6 files changed

+579
-3
lines changed

CLAUDE.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
- **Command execution**: Use std::process::Command with proper error handling and stderr capture
1313

1414
## Implementation
15-
- Available methods: Repository::init(path, bare), Repository::open(path), Repository::status(), Repository::add(paths), Repository::add_all(), Repository::add_update()
15+
- Available methods: Repository::init(path, bare), Repository::open(path), Repository::status(), Repository::add(paths), Repository::add_all(), Repository::add_update(), Repository::commit(message), Repository::commit_with_author(message, author)
1616
- Status functionality: GitStatus with FileStatus enum, files as Box<[(FileStatus, String)]>
1717
- Add functionality: Stage specific files, all changes, or tracked file updates
18+
- Commit functionality: Create commits and return Hash of created commit
19+
- Hash type: Universal git object hash representation with short() and Display methods
1820
- Utility functions: git(args, working_dir) -> Result<String>, git_raw(args, working_dir) -> Result<Output>
19-
- Command modules: status.rs, add.rs (in src/commands/)
21+
- Command modules: status.rs, add.rs, commit.rs (in src/commands/)
22+
- Core types: Hash (in src/types.rs)
2023
- Run `cargo build && cargo test` after code changes

README.md

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
# Rustic Git
2+
3+
A Rust library for Git repository operations with a clean, type-safe API.
4+
5+
## Overview
6+
7+
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.
8+
9+
## Features
10+
11+
- ✅ Repository initialization and opening
12+
- ✅ File status checking with detailed parsing
13+
- ✅ File staging (add files, add all, add updates)
14+
- ✅ Commit creation with hash return
15+
- ✅ Type-safe error handling
16+
- ✅ Universal `Hash` type for Git objects
17+
- ✅ Comprehensive test coverage
18+
19+
## Installation
20+
21+
Add this to your `Cargo.toml`:
22+
23+
```toml
24+
[dependencies]
25+
rustic-git = "0.1.0"
26+
```
27+
28+
## Quick Start
29+
30+
```rust
31+
use rustic_git::{Repository, Result};
32+
33+
fn main() -> Result<()> {
34+
// Initialize a new repository
35+
let repo = Repository::init("/path/to/repo", false)?;
36+
37+
// Or open an existing repository
38+
let repo = Repository::open("/path/to/existing/repo")?;
39+
40+
// Check repository status
41+
let status = repo.status()?;
42+
if !status.is_clean() {
43+
println!("Modified files: {:?}", status.modified_files());
44+
println!("Untracked files: {:?}", status.untracked_files());
45+
}
46+
47+
// Stage files
48+
repo.add(&["file1.txt", "file2.txt"])?;
49+
// Or stage all changes
50+
repo.add_all()?;
51+
52+
// Create a commit
53+
let hash = repo.commit("Add new features")?;
54+
println!("Created commit: {}", hash.short());
55+
56+
Ok(())
57+
}
58+
```
59+
60+
## API Documentation
61+
62+
### Repository Lifecycle
63+
64+
#### `Repository::init(path, bare) -> Result<Repository>`
65+
66+
Initialize a new Git repository.
67+
68+
```rust
69+
// Initialize a regular repository
70+
let repo = Repository::init("/path/to/repo", false)?;
71+
72+
// Initialize a bare repository
73+
let bare_repo = Repository::init("/path/to/bare-repo", true)?;
74+
```
75+
76+
#### `Repository::open(path) -> Result<Repository>`
77+
78+
Open an existing Git repository.
79+
80+
```rust
81+
let repo = Repository::open("/path/to/existing/repo")?;
82+
```
83+
84+
### Status Operations
85+
86+
#### `Repository::status() -> Result<GitStatus>`
87+
88+
Get the current repository status.
89+
90+
```rust
91+
let status = repo.status()?;
92+
93+
// Check if repository is clean
94+
if status.is_clean() {
95+
println!("No changes");
96+
} else {
97+
println!("Repository has changes");
98+
}
99+
100+
// Get files by status
101+
let modified = status.modified_files();
102+
let untracked = status.untracked_files();
103+
104+
// Or work with all files directly
105+
for (file_status, filename) in &status.files {
106+
println!("{:?}: {}", file_status, filename);
107+
}
108+
```
109+
110+
The `GitStatus` struct contains:
111+
- `files: Box<[(FileStatus, String)]>` - All files with their status
112+
- `is_clean()` - Returns true if no changes
113+
- `has_changes()` - Returns true if any changes exist
114+
- `modified_files()` - Get all modified files
115+
- `untracked_files()` - Get all untracked files
116+
- `files_with_status(status)` - Get files with specific status
117+
118+
#### File Status Types
119+
120+
```rust
121+
pub enum FileStatus {
122+
Modified, // File has been modified
123+
Added, // File has been added to index
124+
Deleted, // File has been deleted
125+
Renamed, // File has been renamed
126+
Copied, // File has been copied
127+
Untracked, // File is not tracked by git
128+
Ignored, // File is ignored by git
129+
}
130+
```
131+
132+
### Staging Operations
133+
134+
#### `Repository::add(paths) -> Result<()>`
135+
136+
Add specific files to the staging area.
137+
138+
```rust
139+
// Add single file
140+
repo.add(&["file.txt"])?;
141+
142+
// Add multiple files
143+
repo.add(&["file1.txt", "file2.txt", "dir/file3.txt"])?;
144+
145+
// Add with Path objects
146+
use std::path::Path;
147+
repo.add(&[Path::new("file.txt")])?;
148+
```
149+
150+
#### `Repository::add_all() -> Result<()>`
151+
152+
Add all changes to the staging area (equivalent to `git add .`).
153+
154+
```rust
155+
repo.add_all()?;
156+
```
157+
158+
#### `Repository::add_update() -> Result<()>`
159+
160+
Add all tracked files that have been modified (equivalent to `git add -u`).
161+
162+
```rust
163+
repo.add_update()?;
164+
```
165+
166+
### Commit Operations
167+
168+
#### `Repository::commit(message) -> Result<Hash>`
169+
170+
Create a commit with the given message.
171+
172+
```rust
173+
let hash = repo.commit("Fix critical bug")?;
174+
println!("Commit created: {}", hash);
175+
println!("Short hash: {}", hash.short());
176+
```
177+
178+
#### `Repository::commit_with_author(message, author) -> Result<Hash>`
179+
180+
Create a commit with a custom author.
181+
182+
```rust
183+
let hash = repo.commit_with_author(
184+
"Add new feature",
185+
"Jane Developer <[email protected]>"
186+
)?;
187+
```
188+
189+
### Hash Type
190+
191+
The `Hash` type represents Git object hashes (commits, trees, blobs, etc.).
192+
193+
```rust
194+
let hash = repo.commit("message")?;
195+
196+
// Get full hash as string
197+
let full_hash: &str = hash.as_str();
198+
199+
// Get short hash (first 7 characters)
200+
let short_hash: &str = hash.short();
201+
202+
// Display formatting
203+
println!("Commit: {}", hash); // Displays full hash
204+
```
205+
206+
## Error Handling
207+
208+
All operations return `Result<T, GitError>` for proper error handling.
209+
210+
```rust
211+
use rustic_git::{Repository, GitError};
212+
213+
match repo.commit("message") {
214+
Ok(hash) => println!("Success: {}", hash),
215+
Err(GitError::CommandFailed(msg)) => eprintln!("Git command failed: {}", msg),
216+
Err(GitError::IoError(msg)) => eprintln!("IO error: {}", msg),
217+
}
218+
```
219+
220+
## Complete Workflow Example
221+
222+
```rust
223+
use rustic_git::{Repository, FileStatus};
224+
use std::fs;
225+
226+
fn main() -> rustic_git::Result<()> {
227+
// Create a new repository
228+
let repo = Repository::init("./my-project", false)?;
229+
230+
// Create some files
231+
fs::write("./my-project/README.md", "# My Project")?;
232+
fs::write("./my-project/src/main.rs", "fn main() { println!(\"Hello!\"); }")?;
233+
fs::create_dir_all("./my-project/src")?;
234+
235+
// Check status
236+
let status = repo.status()?;
237+
println!("Found {} untracked files", status.untracked_files().len());
238+
239+
// Stage all files
240+
repo.add_all()?;
241+
242+
// Verify staging
243+
let status = repo.status()?;
244+
let added_files: Vec<_> = status.files.iter()
245+
.filter(|(s, _)| matches!(s, FileStatus::Added))
246+
.map(|(_, f)| f)
247+
.collect();
248+
println!("Staged files: {:?}", added_files);
249+
250+
// Create initial commit
251+
let hash = repo.commit("Initial commit with project structure")?;
252+
println!("Created commit: {}", hash.short());
253+
254+
// Verify clean state
255+
let status = repo.status()?;
256+
assert!(status.is_clean());
257+
println!("Repository is now clean!");
258+
259+
Ok(())
260+
}
261+
```
262+
263+
## Testing
264+
265+
Run the test suite:
266+
267+
```bash
268+
cargo test
269+
```
270+
271+
All tests create temporary repositories in `/tmp/` and clean up after themselves.
272+
273+
## Contributing
274+
275+
This library follows these design principles:
276+
277+
- **Repository-centric API**: Static lifecycle methods (`init`, `open`) return `Repository` instances
278+
- **Type safety**: Strong typing with custom error types and structured return values
279+
- **Ergonomic design**: Clean, intuitive API that follows Rust conventions
280+
- **Comprehensive testing**: All functionality thoroughly tested
281+
- **Modular organization**: Commands organized in separate modules
282+
283+
## License
284+
285+
MIT License - see LICENSE file for details.
286+
287+
## Roadmap
288+
289+
Future planned features:
290+
- [ ] Commit history and log operations
291+
- [ ] Diff operations
292+
- [ ] Branch operations
293+
- [ ] Remote operations (clone, push, pull)
294+
- [ ] Merge and rebase operations
295+
- [ ] Tag operations
296+
- [ ] Stash operations
297+
298+
## Version
299+
300+
Current version: 0.1.0 - Basic git workflow (init, status, add, commit)

0 commit comments

Comments
 (0)