@@ -9,12 +9,15 @@ Rustic Git provides a simple, ergonomic interface for common Git operations. It
99## Features
1010
1111- ✅ Repository initialization and opening
12- - ✅ File status checking with detailed parsing
13- - ✅ File staging (add files, add all, add updates)
12+ - ✅ ** Enhanced file status checking** with separate staged/unstaged tracking
13+ - ✅ ** Precise Git state representation** using IndexStatus and WorktreeStatus enums
14+ - ✅ File staging (add files, add all, add updates)
1415- ✅ Commit creation with hash return
15- - ✅ Type-safe error handling
16+ - ✅ Type-safe error handling with custom GitError enum
1617- ✅ Universal ` Hash ` type for Git objects
17- - ✅ Comprehensive test coverage
18+ - ✅ ** Immutable collections** (Box<[ FileEntry] >) for memory efficiency
19+ - ✅ ** Const enum conversions** with zero runtime cost
20+ - ✅ Comprehensive test coverage (80+ tests)
1821
1922## Installation
2023
@@ -28,7 +31,7 @@ rustic-git = "0.1.0"
2831## Quick Start
2932
3033``` rust
31- use rustic_git :: {Repository , Result };
34+ use rustic_git :: {Repository , Result , IndexStatus , WorktreeStatus };
3235
3336fn main () -> Result <()> {
3437 // Initialize a new repository
@@ -37,11 +40,24 @@ fn main() -> Result<()> {
3740 // Or open an existing repository
3841 let repo = Repository :: open (" /path/to/existing/repo" )? ;
3942
40- // Check repository status
43+ // Check repository status with enhanced API
4144 let status = repo . status ()? ;
4245 if ! status . is_clean () {
43- println! (" Modified files: {:?}" , status . modified_files ());
44- println! (" Untracked files: {:?}" , status . untracked_files ());
46+ // Get files by staging state
47+ let staged_count = status . staged_files (). count ();
48+ let unstaged_count = status . unstaged_files (). count ();
49+ let untracked_count = status . untracked_entries (). count ();
50+
51+ println! (" Repository status:" );
52+ println! (" Staged: {} files" , staged_count );
53+ println! (" Unstaged: {} files" , unstaged_count );
54+ println! (" Untracked: {} files" , untracked_count );
55+
56+ // Filter by specific status types
57+ let modified_files : Vec <_ > = status
58+ . files_with_worktree_status (WorktreeStatus :: Modified )
59+ . collect ();
60+ println! (" Modified files: {:?}" , modified_files );
4561 }
4662
4763 // Stage files
@@ -85,7 +101,7 @@ let repo = Repository::open("/path/to/existing/repo")?;
85101
86102#### ` Repository::status() -> Result<GitStatus> `
87103
88- Get the current repository status.
104+ Get the current repository status with enhanced staged/unstaged file tracking .
89105
90106``` rust
91107let status = repo . status ()? ;
@@ -97,36 +113,81 @@ if status.is_clean() {
97113 println! (" Repository has changes" );
98114}
99115
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 );
116+ // Get files by staging state
117+ let staged_files : Vec <_ > = status . staged_files (). collect ();
118+ let unstaged_files : Vec <_ > = status . unstaged_files (). collect ();
119+ let untracked_files : Vec <_ > = status . untracked_entries (). collect ();
120+
121+ // Filter by specific status types
122+ let modified_in_index : Vec <_ > = status
123+ . files_with_index_status (IndexStatus :: Modified )
124+ . collect ();
125+ let modified_in_worktree : Vec <_ > = status
126+ . files_with_worktree_status (WorktreeStatus :: Modified )
127+ . collect ();
128+
129+ // Work with all file entries directly
130+ for entry in status . entries () {
131+ println! (" [{}][{}] {}" ,
132+ entry . index_status. to_char (),
133+ entry . worktree_status. to_char (),
134+ entry . path. display ()
135+ );
107136}
108137```
109138
110139The ` GitStatus ` struct contains:
111- - ` files : Box<[(FileStatus, String) ]>` - All files with their status
140+ - ` entries : Box<[FileEntry ]>` - Immutable collection of file entries
112141- ` is_clean() ` - Returns true if no changes
113142- ` 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
143+ - ` staged_files() ` - Iterator over files with index changes (staged)
144+ - ` unstaged_files() ` - Iterator over files with worktree changes (unstaged)
145+ - ` untracked_entries() ` - Iterator over untracked files
146+ - ` ignored_files() ` - Iterator over ignored files
147+ - ` files_with_index_status(status) ` - Filter by specific index status
148+ - ` files_with_worktree_status(status) ` - Filter by specific worktree status
117149
118150#### File Status Types
119151
152+ The enhanced status API uses separate enums for index (staged) and worktree (unstaged) states:
153+
120154``` 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
155+ // Index (staging area) status
156+ pub enum IndexStatus {
157+ Clean , // No changes in index
158+ Modified , // File modified in index
159+ Added , // File added to index
160+ Deleted , // File deleted in index
161+ Renamed , // File renamed in index
162+ Copied , // File copied in index
163+ }
164+
165+ // Worktree (working directory) status
166+ pub enum WorktreeStatus {
167+ Clean , // No changes in worktree
168+ Modified , // File modified in worktree
169+ Deleted , // File deleted in worktree
170+ Untracked , // File not tracked by git
171+ Ignored , // File ignored by git
129172}
173+
174+ // File entry combining both states
175+ pub struct FileEntry {
176+ pub path : PathBuf ,
177+ pub index_status : IndexStatus ,
178+ pub worktree_status : WorktreeStatus ,
179+ }
180+ ```
181+
182+ Both enums support const character conversion:
183+ ``` rust
184+ // Convert to/from git porcelain characters
185+ let status = IndexStatus :: from_char ('M' ); // IndexStatus::Modified
186+ let char = status . to_char (); // 'M'
187+
188+ // Display formatting
189+ println! (" {}" , IndexStatus :: Modified ); // Prints: M
190+ println! (" {}" , WorktreeStatus :: Untracked ); // Prints: ?
130191```
131192
132193### Staging Operations
@@ -220,7 +281,7 @@ match repo.commit("message") {
220281## Complete Workflow Example
221282
222283``` rust
223- use rustic_git :: {Repository , FileStatus };
284+ use rustic_git :: {Repository , IndexStatus , WorktreeStatus };
224285use std :: fs;
225286
226287fn main () -> rustic_git :: Result <()> {
@@ -229,23 +290,36 @@ fn main() -> rustic_git::Result<()> {
229290
230291 // Create some files
231292 fs :: write (" ./my-project/README.md" , " # My Project" )? ;
232- fs :: write (" ./my-project/src/main.rs" , " fn main() { println!(\ " Hello!\ " ); }" )? ;
233293 fs :: create_dir_all (" ./my-project/src" )? ;
294+ fs :: write (" ./my-project/src/main.rs" , " fn main() { println!(\ " Hello!\ " ); }" )? ;
234295
235- // Check status
296+ // Check status with enhanced API
236297 let status = repo . status ()? ;
237- println! (" Found {} untracked files" , status . untracked_files (). len ());
298+ let untracked_count = status . untracked_entries (). count ();
299+ println! (" Found {} untracked files" , untracked_count );
300+
301+ // Display detailed status
302+ for entry in status . entries () {
303+ println! (" [{}][{}] {}" ,
304+ entry . index_status. to_char (),
305+ entry . worktree_status. to_char (),
306+ entry . path. display ()
307+ );
308+ }
238309
239310 // Stage all files
240311 repo . add_all ()? ;
241312
242- // Verify staging
313+ // Verify staging with enhanced API
243314 let status = repo . status ()? ;
244- let added_files : Vec <_ > = status . files. iter ()
245- . filter (| (s , _ )| matches! (s , FileStatus :: Added ))
246- . map (| (_ , f )| f )
315+ let staged_files : Vec <_ > = status . staged_files (). collect ();
316+ println! (" Staged {} files" , staged_files . len ());
317+
318+ // Show specifically added files
319+ let added_files : Vec <_ > = status
320+ . files_with_index_status (IndexStatus :: Added )
247321 . collect ();
248- println! (" Staged files: {:?}" , added_files );
322+ println! (" Added files: {:?}" , added_files );
249323
250324 // Create initial commit
251325 let hash = repo . commit (" Initial commit with project structure" )? ;
@@ -273,7 +347,7 @@ cargo run --example basic_usage
273347# Repository lifecycle operations
274348cargo run --example repository_operations
275349
276- # Status checking and file state filtering
350+ # Enhanced status API with staged/unstaged tracking
277351cargo run --example status_checking
278352
279353# Staging operations (add, add_all, add_update)
0 commit comments