pub struct GitStatus {
pub entries: Box<[FileEntry]>,
}
Fields§
§entries: Box<[FileEntry]>
Implementations§
Source§impl GitStatus
impl GitStatus
Sourcepub fn is_clean(&self) -> bool
pub fn is_clean(&self) -> bool
Examples found in repository?
examples/staging_operations.rs (line 251)
250fn display_status_breakdown(status: &rustic_git::GitStatus) {
251 if status.is_clean() {
252 println!(" Repository is clean");
253 return;
254 }
255
256 let mut index_counts = std::collections::HashMap::new();
257 let mut worktree_counts = std::collections::HashMap::new();
258
259 for entry in &status.entries {
260 if !matches!(entry.index_status, IndexStatus::Clean) {
261 *index_counts.entry(&entry.index_status).or_insert(0) += 1;
262 }
263 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
264 *worktree_counts.entry(&entry.worktree_status).or_insert(0) += 1;
265 }
266 }
267
268 println!(" Index status:");
269 for (index_status, count) in &index_counts {
270 let marker = match index_status {
271 IndexStatus::Modified => "[M]",
272 IndexStatus::Added => "[A]",
273 IndexStatus::Deleted => "[D]",
274 IndexStatus::Renamed => "[R]",
275 IndexStatus::Copied => "[C]",
276 IndexStatus::Clean => "[ ]",
277 };
278 println!(" {} {:?}: {} files", marker, index_status, count);
279 }
280
281 println!(" Worktree status:");
282 for (worktree_status, count) in &worktree_counts {
283 let marker = match worktree_status {
284 WorktreeStatus::Modified => "[M]",
285 WorktreeStatus::Deleted => "[D]",
286 WorktreeStatus::Untracked => "[?]",
287 WorktreeStatus::Ignored => "[I]",
288 WorktreeStatus::Clean => "[ ]",
289 };
290 println!(" {} {:?}: {} files", marker, worktree_status, count);
291 }
292}
More examples
examples/basic_usage.rs (line 61)
16fn main() -> Result<()> {
17 println!("Rustic Git - Basic Usage Example\n");
18
19 // Use a temporary directory for this example
20 let repo_path = env::temp_dir().join("rustic_git_basic_example");
21
22 // Clean up any previous run
23 if repo_path.exists() {
24 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
25 }
26
27 println!("Initializing new repository at: {}", repo_path.display());
28
29 // Initialize a new repository
30 let repo = Repository::init(&repo_path, false)?;
31 println!("Repository initialized successfully\n");
32
33 // Create some example files
34 println!("Creating example files...");
35 fs::create_dir_all(repo_path.join("src"))?;
36
37 fs::write(
38 repo_path.join("README.md"),
39 "# My Awesome Project\n\nThis is a demo project for rustic-git!\n",
40 )?;
41
42 fs::write(
43 repo_path.join("src/main.rs"),
44 r#"fn main() {
45 println!("Hello from rustic-git example!");
46}
47"#,
48 )?;
49
50 fs::write(
51 repo_path.join("src/lib.rs"),
52 "// Library code goes here\npub fn hello() -> &'static str {\n \"Hello, World!\"\n}\n",
53 )?;
54
55 println!("Created 3 files: README.md, src/main.rs, src/lib.rs\n");
56
57 // Check repository status
58 println!("Checking repository status...");
59 let status = repo.status()?;
60
61 if status.is_clean() {
62 println!(" Repository is clean (no changes)");
63 } else {
64 println!(" Repository has changes:");
65 println!(" Unstaged files: {}", status.unstaged_files().count());
66 println!(" Untracked files: {}", status.untracked_entries().count());
67
68 // Show untracked files
69 for entry in status.untracked_entries() {
70 println!(" - {}", entry.path.display());
71 }
72 }
73 println!();
74
75 // Stage specific files first
76 println!("Staging files...");
77
78 // Stage README.md first
79 repo.add(&["README.md"])?;
80 println!("Staged README.md");
81
82 // Stage all remaining files
83 repo.add_all()?;
84 println!("Staged all remaining files");
85
86 // Check status after staging
87 let status_after_staging = repo.status()?;
88 println!("\nStatus after staging:");
89 if status_after_staging.is_clean() {
90 println!(" Repository is clean (all changes staged)");
91 } else {
92 println!(
93 " Files staged for commit: {}",
94 status_after_staging.entries.len()
95 );
96 for entry in &status_after_staging.entries {
97 println!(
98 " Index {:?}, Worktree {:?}: {}",
99 entry.index_status,
100 entry.worktree_status,
101 entry.path.display()
102 );
103 }
104 }
105 println!();
106
107 // Create a commit
108 println!("Creating commit...");
109 let hash = repo.commit("Initial commit: Add project structure and basic files")?;
110
111 println!("Commit created successfully!");
112 println!(" Full hash: {}", hash);
113 println!(" Short hash: {}", hash.short());
114 println!();
115
116 // Verify final status
117 println!("Final repository status:");
118 let final_status = repo.status()?;
119 if final_status.is_clean() {
120 println!(" Repository is clean - all changes committed!");
121 } else {
122 println!(" Repository still has uncommitted changes");
123 }
124 println!();
125
126 // Clean up
127 println!("Cleaning up example repository...");
128 fs::remove_dir_all(&repo_path)?;
129 println!("Example completed successfully!");
130
131 Ok(())
132}
examples/error_handling.rs (line 289)
207fn demonstrate_error_recovery_patterns(repo_path: &std::path::Path) -> Result<()> {
208 println!("Error Recovery Patterns:\n");
209
210 let repo = Repository::open(repo_path)?;
211
212 // Pattern 1: Retry with different approach
213 println!("1. Retry Pattern - Graceful degradation:");
214
215 // Try to add specific files, fall back to add_all on failure
216 let files_to_add = ["missing1.txt", "missing2.txt", "missing3.txt"];
217
218 println!(" Attempting to add specific files...");
219 match repo.add(&files_to_add) {
220 Ok(_) => println!(" Specific files added successfully"),
221 Err(e) => {
222 println!(" Specific files failed: {:?}", e);
223 println!(" Falling back to add_all()...");
224
225 match repo.add_all() {
226 Ok(_) => {
227 let status = repo.status()?;
228 println!(
229 " add_all() succeeded, {} files staged",
230 status.entries.len()
231 );
232 }
233 Err(fallback_error) => {
234 println!(" Fallback also failed: {:?}", fallback_error);
235 }
236 }
237 }
238 }
239
240 // Pattern 2: Partial success handling
241 println!("\n2. Partial Success Pattern:");
242
243 // Create some files with known issues
244 fs::write(repo_path.join("good1.txt"), "Good file 1")?;
245 fs::write(repo_path.join("good2.txt"), "Good file 2")?;
246 // Don't create bad1.txt - it will be missing
247
248 let mixed_files = ["good1.txt", "bad1.txt", "good2.txt"];
249
250 println!(" Attempting to add mixed valid/invalid files...");
251 match repo.add(&mixed_files) {
252 Ok(_) => println!(" All files added (unexpected success)"),
253 Err(GitError::CommandFailed(msg)) => {
254 println!(" Batch add failed: {}", msg);
255 println!(" Recovery: Adding files individually...");
256
257 let mut successful_adds = 0;
258 let mut failed_adds = 0;
259
260 for file in &mixed_files {
261 match repo.add(&[file]) {
262 Ok(_) => {
263 successful_adds += 1;
264 println!(" Added: {}", file);
265 }
266 Err(_) => {
267 failed_adds += 1;
268 println!(" Failed: {}", file);
269 }
270 }
271 }
272
273 println!(
274 " Results: {} succeeded, {} failed",
275 successful_adds, failed_adds
276 );
277 }
278 Err(GitError::IoError(msg)) => {
279 println!(" IoError during batch add: {}", msg);
280 }
281 }
282
283 // Pattern 3: Status checking before operations
284 println!("\n3. Preventive Pattern - Check before operation:");
285
286 println!(" Checking repository status before commit...");
287 let status = repo.status()?;
288
289 if status.is_clean() {
290 println!(" Repository is clean - no commit needed");
291 } else {
292 println!(" Repository has {} changes", status.entries.len());
293
294 // Show what would be committed
295 for entry in &status.entries {
296 println!(
297 " Index {:?}, Worktree {:?}: {}",
298 entry.index_status,
299 entry.worktree_status,
300 entry.path.display()
301 );
302 }
303
304 // Safe commit since we know there are changes
305 match repo.commit("Commit after status check") {
306 Ok(hash) => println!(" Safe commit succeeded: {}", hash.short()),
307 Err(e) => println!(" Even safe commit failed: {:?}", e),
308 }
309 }
310
311 println!();
312 Ok(())
313}
examples/status_checking.rs (line 85)
15fn main() -> Result<()> {
16 println!("Rustic Git - Status Checking Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_status_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 // Initialize repository
26 println!("Setting up repository for status demonstration...");
27 let repo = Repository::init(&repo_path, false)?;
28
29 println!("=== Clean Repository Status ===\n");
30
31 // Check initial status (should be clean)
32 let status = repo.status()?;
33 println!("Initial repository status:");
34 display_status_summary(&status);
35 println!();
36
37 println!("=== Creating Files with Different States ===\n");
38
39 // Create various types of files to demonstrate different statuses
40 println!("Creating test files...");
41
42 // Create some files that will be untracked
43 fs::write(repo_path.join("untracked1.txt"), "This file is untracked")?;
44 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
45
46 // Create a .gitignore to demonstrate ignored files
47 fs::write(repo_path.join(".gitignore"), "*.log\n*.tmp\n/temp/\n")?;
48
49 // Create files that will be ignored
50 fs::write(repo_path.join("debug.log"), "Log file content")?;
51 fs::write(repo_path.join("cache.tmp"), "Temporary file")?;
52 fs::create_dir_all(repo_path.join("temp"))?;
53 fs::write(repo_path.join("temp/data.txt"), "Temp data")?;
54
55 println!("Created test files");
56
57 // Check status after creating untracked files
58 println!("\nStatus after creating untracked files:");
59 let status_untracked = repo.status()?;
60 display_status_summary(&status_untracked);
61 display_detailed_status(&status_untracked);
62 println!();
63
64 println!("=== Staging Files to Show 'Added' Status ===\n");
65
66 // Stage some files to show "Added" status
67 repo.add(&["untracked1.txt", ".gitignore"])?;
68 println!("Staged untracked1.txt and .gitignore");
69
70 let status_added = repo.status()?;
71 println!("\nStatus after staging files:");
72 display_status_summary(&status_added);
73 display_detailed_status(&status_added);
74 println!();
75
76 println!("=== Creating Initial Commit ===\n");
77
78 // Commit the staged files so we can demonstrate modified/deleted states
79 let _hash = repo.commit("Initial commit with basic files")?;
80 println!("Created initial commit");
81
82 let status_after_commit = repo.status()?;
83 println!("\nStatus after commit:");
84 display_status_summary(&status_after_commit);
85 if !status_after_commit.is_clean() {
86 display_detailed_status(&status_after_commit);
87 }
88 println!();
89
90 println!("=== Modifying Files to Show 'Modified' Status ===\n");
91
92 // Modify existing tracked files
93 fs::write(
94 repo_path.join("untracked1.txt"),
95 "This file has been MODIFIED!",
96 )?;
97 fs::write(
98 repo_path.join(".gitignore"),
99 "*.log\n*.tmp\n/temp/\n# Added comment\n",
100 )?;
101 println!("Modified untracked1.txt and .gitignore");
102
103 let status_modified = repo.status()?;
104 println!("\nStatus after modifying files:");
105 display_status_summary(&status_modified);
106 display_detailed_status(&status_modified);
107 println!();
108
109 println!("=== Demonstrating All Status Query Methods ===\n");
110
111 // Stage one of the modified files to show mixed states
112 repo.add(&["untracked1.txt"])?;
113 println!("Staged untracked1.txt (now shows as Added)");
114
115 let status_mixed = repo.status()?;
116 println!("\nMixed status demonstration:");
117 display_status_summary(&status_mixed);
118
119 // Demonstrate different query methods
120 println!("\nUsing different status query methods:");
121
122 println!(" All files ({} total):", status_mixed.entries.len());
123 for entry in &status_mixed.entries {
124 println!(
125 " Index {:?}, Worktree {:?}: {}",
126 entry.index_status,
127 entry.worktree_status,
128 entry.path.display()
129 );
130 }
131
132 // Query by specific status
133 let unstaged_files: Vec<_> = status_mixed.unstaged_files().collect();
134 if !unstaged_files.is_empty() {
135 println!("\n Unstaged files ({}):", unstaged_files.len());
136 for entry in &unstaged_files {
137 println!(" - {}", entry.path.display());
138 }
139 }
140
141 let untracked_files: Vec<_> = status_mixed.untracked_entries().collect();
142 if !untracked_files.is_empty() {
143 println!("\n Untracked files ({}):", untracked_files.len());
144 for entry in &untracked_files {
145 println!(" - {}", entry.path.display());
146 }
147 }
148
149 // Query by IndexStatus enum
150 let added_files: Vec<_> = status_mixed
151 .files_with_index_status(IndexStatus::Added)
152 .collect();
153 if !added_files.is_empty() {
154 println!("\n Added files ({}):", added_files.len());
155 for entry in &added_files {
156 println!(" - {}", entry.path.display());
157 }
158 }
159
160 println!();
161
162 println!("=== File Status Filtering Examples ===\n");
163
164 // Demonstrate filtering capabilities
165 println!("Filtering examples:");
166
167 // Count files by status
168 let mut index_status_counts = std::collections::HashMap::new();
169 let mut worktree_status_counts = std::collections::HashMap::new();
170
171 for entry in &status_mixed.entries {
172 if !matches!(entry.index_status, IndexStatus::Clean) {
173 *index_status_counts
174 .entry(format!("{:?}", entry.index_status))
175 .or_insert(0) += 1;
176 }
177 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
178 *worktree_status_counts
179 .entry(format!("{:?}", entry.worktree_status))
180 .or_insert(0) += 1;
181 }
182 }
183
184 println!(" Index status counts:");
185 for (status, count) in &index_status_counts {
186 println!(" {}: {} files", status, count);
187 }
188
189 println!(" Worktree status counts:");
190 for (status, count) in &worktree_status_counts {
191 println!(" {}: {} files", status, count);
192 }
193
194 // Filter for specific patterns
195 let txt_files: Vec<_> = status_mixed
196 .entries
197 .iter()
198 .filter(|entry| entry.path.to_string_lossy().ends_with(".txt"))
199 .collect();
200
201 if !txt_files.is_empty() {
202 println!("\n .txt files:");
203 for entry in txt_files {
204 println!(
205 " Index {:?}, Worktree {:?}: {}",
206 entry.index_status,
207 entry.worktree_status,
208 entry.path.display()
209 );
210 }
211 }
212
213 println!();
214
215 println!("=== Repository State Checking ===\n");
216
217 println!("Repository state summary:");
218 println!(" Total files tracked: {}", status_mixed.entries.len());
219 println!(" Is clean: {}", status_mixed.is_clean());
220 println!(" Has changes: {}", status_mixed.has_changes());
221
222 if status_mixed.has_changes() {
223 println!(" Repository needs attention!");
224
225 let unstaged_count = status_mixed.unstaged_files().count();
226 if unstaged_count > 0 {
227 println!(" - {} files need to be staged", unstaged_count);
228 }
229
230 let untracked_count = status_mixed.untracked_entries().count();
231 if untracked_count > 0 {
232 println!(" - {} untracked files to consider", untracked_count);
233 }
234
235 let staged_count = status_mixed.staged_files().count();
236 if staged_count > 0 {
237 println!(" - {} files ready to commit", staged_count);
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Status checking example completed!");
245
246 Ok(())
247}
248
249/// Display a summary of the repository status
250fn display_status_summary(status: &rustic_git::GitStatus) {
251 if status.is_clean() {
252 println!(" Repository is clean (no changes)");
253 } else {
254 println!(" Repository has {} changes", status.entries.len());
255 println!(" Unstaged: {}", status.unstaged_files().count());
256 println!(" Untracked: {}", status.untracked_entries().count());
257 }
258}
examples/commit_workflows.rs (line 318)
15fn main() -> Result<()> {
16 println!("Rustic Git - Commit Workflows Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_commit_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 // Initialize repository
26 println!("Setting up repository for commit demonstrations...");
27 let repo = Repository::init(&repo_path, false)?;
28 println!("Repository initialized\n");
29
30 println!("=== Basic Commit Operations ===\n");
31
32 // Create initial files
33 println!("Creating initial project files...");
34 fs::create_dir_all(repo_path.join("src"))?;
35
36 fs::write(
37 repo_path.join("README.md"),
38 "# Commit Demo Project\n\nThis project demonstrates commit workflows with rustic-git.\n",
39 )?;
40
41 fs::write(
42 repo_path.join("src/main.rs"),
43 r#"fn main() {
44 println!("Hello, Commit Demo!");
45}
46"#,
47 )?;
48
49 fs::write(
50 repo_path.join("Cargo.toml"),
51 r#"[package]
52name = "commit-demo"
53version = "0.1.0"
54edition = "2021"
55"#,
56 )?;
57
58 println!("Created README.md, src/main.rs, and Cargo.toml");
59
60 // Stage and commit with basic commit()
61 println!("\nStaging files for first commit...");
62 repo.add_all()?;
63
64 println!("Creating first commit with basic commit() method:");
65 let first_hash = repo.commit("Initial commit: Add project structure")?;
66
67 println!("First commit created!");
68 display_hash_info(&first_hash, "First commit");
69 println!();
70
71 println!("=== Hash Type Demonstrations ===\n");
72
73 println!("Hash type methods and usage:");
74
75 // Demonstrate different ways to work with Hash
76 let hash_as_string: String = first_hash.to_string();
77 let hash_as_str: &str = first_hash.as_str();
78 let short_hash: &str = first_hash.short();
79
80 println!(" Hash conversions:");
81 println!(" as_str(): '{}'", hash_as_str);
82 println!(" short(): '{}'", short_hash);
83 println!(" to_string(): '{}'", hash_as_string);
84 println!(" Display: '{}'", first_hash);
85
86 // Demonstrate Hash equality and cloning
87 let cloned_hash = first_hash.clone();
88 println!("\n Hash operations:");
89 println!(" Original == Clone: {}", first_hash == cloned_hash);
90 println!(
91 " Hash length: {} characters",
92 first_hash.as_str().len()
93 );
94 println!(
95 " Short hash length: {} characters",
96 first_hash.short().len()
97 );
98
99 // Create Hash from different sources for demonstration
100 let hash_from_string: Hash = "1234567890abcdef".to_string().into();
101 let hash_from_str: Hash = "fedcba0987654321".into();
102
103 println!(" Hash from String: {}", hash_from_string.short());
104 println!(" Hash from &str: {}", hash_from_str.short());
105 println!();
106
107 println!("=== Commits with Custom Authors ===\n");
108
109 // Create more files to commit with custom author
110 println!("Adding features for custom author commit...");
111 fs::create_dir_all(repo_path.join("tests"))?;
112
113 fs::write(
114 repo_path.join("src/lib.rs"),
115 r#"//! Commit demo library
116
117pub fn greet(name: &str) -> String {
118 format!("Hello, {}! This is a commit demo.", name)
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_greet() {
127 assert_eq!(greet("Alice"), "Hello, Alice! This is a commit demo.");
128 }
129}
130"#,
131 )?;
132
133 fs::write(
134 repo_path.join("tests/integration_test.rs"),
135 r#"use commit_demo::greet;
136
137#[test]
138fn test_integration() {
139 let result = greet("Integration");
140 assert!(result.contains("Integration"));
141 assert!(result.contains("commit demo"));
142}
143"#,
144 )?;
145
146 println!("Created src/lib.rs and tests/integration_test.rs");
147
148 // Stage and commit with custom author
149 repo.add_all()?;
150 println!("\nCreating commit with custom author:");
151 let second_hash = repo.commit_with_author(
152 "Add library code and tests\n\n- Implement greet function with proper documentation\n- Add unit tests and integration tests\n- Prepare for version 0.2.0 release",
153 "Jane Developer <jane.dev@example.com>"
154 )?;
155
156 println!("Commit with custom author created!");
157 display_hash_info(&second_hash, "Second commit (custom author)");
158 println!();
159
160 println!("=== Multiple Commit Workflow ===\n");
161
162 // Demonstrate a series of commits
163 let mut commit_hashes = vec![first_hash, second_hash];
164
165 // Commit 3: Update version
166 println!("Step 1: Update version information...");
167 fs::write(
168 repo_path.join("Cargo.toml"),
169 r#"[package]
170name = "commit-demo"
171version = "0.2.0"
172edition = "2021"
173description = "A demo project for commit workflows"
174"#,
175 )?;
176
177 repo.add(&["Cargo.toml"])?;
178 let third_hash = repo.commit("Bump version to 0.2.0 and add description")?;
179 commit_hashes.push(third_hash);
180
181 // Commit 4: Add documentation
182 println!("Step 2: Add documentation...");
183 fs::write(
184 repo_path.join("CHANGELOG.md"),
185 r#"# Changelog
186
187## [0.2.0] - 2024-01-01
188
189### Added
190- Library functionality with greet function
191- Comprehensive test suite
192- Project documentation
193
194## [0.1.0] - 2024-01-01
195
196### Added
197- Initial project structure
198- Basic Cargo configuration
199"#,
200 )?;
201
202 repo.add(&["CHANGELOG.md"])?;
203 let fourth_hash = repo.commit_with_author(
204 "docs: Add CHANGELOG with version history",
205 "Doc Writer <docs@example.com>",
206 )?;
207 commit_hashes.push(fourth_hash);
208
209 // Commit 5: Final polish
210 println!("Step 3: Final polish...");
211 fs::write(
212 repo_path.join("README.md"),
213 r#"# Commit Demo Project
214
215This project demonstrates commit workflows with rustic-git.
216
217## Features
218
219- Clean, type-safe Git operations
220- Comprehensive commit history
221- Multiple author support
222- Hash management utilities
223
224## Usage
225
226```rust
227use commit_demo::greet;
228
229fn main() {
230 println!("{}", greet("World"));
231}
232```
233
234## Version
235
236Current version: 0.2.0
237
238See CHANGELOG.md for version history.
239"#,
240 )?;
241
242 repo.add(&["README.md"])?;
243 let fifth_hash = repo.commit("docs: Enhance README with usage examples and features")?;
244 commit_hashes.push(fifth_hash);
245
246 println!("\nComplete commit history created!");
247
248 // Display all commits
249 println!("\n=== Commit History Summary ===\n");
250
251 for (i, hash) in commit_hashes.iter().enumerate() {
252 println!("{}. Commit {}", i + 1, i + 1);
253 display_hash_info(hash, &format!("Commit {}", i + 1));
254 println!();
255 }
256
257 // Compare hashes
258 println!("Hash comparisons:");
259 println!(
260 " First commit == Last commit: {}",
261 commit_hashes[0] == commit_hashes[4]
262 );
263 println!(" All hashes unique: {}", all_unique(&commit_hashes));
264
265 // Show short hashes for all commits
266 println!("\nAll commit short hashes:");
267 for (i, hash) in commit_hashes.iter().enumerate() {
268 println!(" {}: {}", i + 1, hash.short());
269 }
270 println!();
271
272 println!("=== Error Handling for Commits ===\n");
273
274 // Try to commit with nothing staged (should fail)
275 println!("Testing commit with no staged changes:");
276 match repo.commit("This should fail - no changes") {
277 Ok(_hash) => println!(" Unexpectedly succeeded with empty commit"),
278 Err(e) => {
279 println!(" Expected error for empty commit: {:?}", e);
280 println!(" This is normal behavior - Git requires changes to commit");
281 }
282 }
283
284 // Try commit with custom author but no changes (should also fail)
285 println!("\nTesting custom author commit with no changes:");
286 match repo.commit_with_author("This should also fail", "Test Author <test@example.com>") {
287 Ok(_hash) => println!(" Unexpectedly succeeded with empty custom author commit"),
288 Err(e) => {
289 println!(
290 " Expected error for empty commit with custom author: {:?}",
291 e
292 );
293 }
294 }
295
296 // Test commit with empty message (Git might handle this differently)
297 println!("\nTesting commit with empty message:");
298
299 // Create a change to commit
300 fs::write(repo_path.join("temp_for_empty_message.txt"), "temp content")?;
301 repo.add(&["temp_for_empty_message.txt"])?;
302
303 match repo.commit("") {
304 Ok(hash) => {
305 println!(" Commit with empty message succeeded: {}", hash.short());
306 println!(" Some Git configurations allow empty commit messages");
307 }
308 Err(e) => {
309 println!(" Empty commit message rejected: {:?}", e);
310 }
311 }
312
313 println!();
314
315 println!("=== Final Repository State ===\n");
316
317 let final_status = repo.status()?;
318 if final_status.is_clean() {
319 println!("Repository is clean - all changes committed!");
320 } else {
321 println!(
322 "Repository has {} uncommitted changes",
323 final_status.entries.len()
324 );
325 }
326
327 println!("\nWorkflow summary:");
328 println!(" Total commits created: {}", commit_hashes.len());
329 println!(" Hash examples demonstrated: [OK]");
330 println!(" Custom author commits: [OK]");
331 println!(" Error handling tested: [OK]");
332
333 // Clean up
334 println!("\nCleaning up example repository...");
335 fs::remove_dir_all(&repo_path)?;
336 println!("Commit workflows example completed!");
337
338 Ok(())
339}
Sourcepub fn has_changes(&self) -> bool
pub fn has_changes(&self) -> bool
Examples found in repository?
examples/status_checking.rs (line 220)
15fn main() -> Result<()> {
16 println!("Rustic Git - Status Checking Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_status_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 // Initialize repository
26 println!("Setting up repository for status demonstration...");
27 let repo = Repository::init(&repo_path, false)?;
28
29 println!("=== Clean Repository Status ===\n");
30
31 // Check initial status (should be clean)
32 let status = repo.status()?;
33 println!("Initial repository status:");
34 display_status_summary(&status);
35 println!();
36
37 println!("=== Creating Files with Different States ===\n");
38
39 // Create various types of files to demonstrate different statuses
40 println!("Creating test files...");
41
42 // Create some files that will be untracked
43 fs::write(repo_path.join("untracked1.txt"), "This file is untracked")?;
44 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
45
46 // Create a .gitignore to demonstrate ignored files
47 fs::write(repo_path.join(".gitignore"), "*.log\n*.tmp\n/temp/\n")?;
48
49 // Create files that will be ignored
50 fs::write(repo_path.join("debug.log"), "Log file content")?;
51 fs::write(repo_path.join("cache.tmp"), "Temporary file")?;
52 fs::create_dir_all(repo_path.join("temp"))?;
53 fs::write(repo_path.join("temp/data.txt"), "Temp data")?;
54
55 println!("Created test files");
56
57 // Check status after creating untracked files
58 println!("\nStatus after creating untracked files:");
59 let status_untracked = repo.status()?;
60 display_status_summary(&status_untracked);
61 display_detailed_status(&status_untracked);
62 println!();
63
64 println!("=== Staging Files to Show 'Added' Status ===\n");
65
66 // Stage some files to show "Added" status
67 repo.add(&["untracked1.txt", ".gitignore"])?;
68 println!("Staged untracked1.txt and .gitignore");
69
70 let status_added = repo.status()?;
71 println!("\nStatus after staging files:");
72 display_status_summary(&status_added);
73 display_detailed_status(&status_added);
74 println!();
75
76 println!("=== Creating Initial Commit ===\n");
77
78 // Commit the staged files so we can demonstrate modified/deleted states
79 let _hash = repo.commit("Initial commit with basic files")?;
80 println!("Created initial commit");
81
82 let status_after_commit = repo.status()?;
83 println!("\nStatus after commit:");
84 display_status_summary(&status_after_commit);
85 if !status_after_commit.is_clean() {
86 display_detailed_status(&status_after_commit);
87 }
88 println!();
89
90 println!("=== Modifying Files to Show 'Modified' Status ===\n");
91
92 // Modify existing tracked files
93 fs::write(
94 repo_path.join("untracked1.txt"),
95 "This file has been MODIFIED!",
96 )?;
97 fs::write(
98 repo_path.join(".gitignore"),
99 "*.log\n*.tmp\n/temp/\n# Added comment\n",
100 )?;
101 println!("Modified untracked1.txt and .gitignore");
102
103 let status_modified = repo.status()?;
104 println!("\nStatus after modifying files:");
105 display_status_summary(&status_modified);
106 display_detailed_status(&status_modified);
107 println!();
108
109 println!("=== Demonstrating All Status Query Methods ===\n");
110
111 // Stage one of the modified files to show mixed states
112 repo.add(&["untracked1.txt"])?;
113 println!("Staged untracked1.txt (now shows as Added)");
114
115 let status_mixed = repo.status()?;
116 println!("\nMixed status demonstration:");
117 display_status_summary(&status_mixed);
118
119 // Demonstrate different query methods
120 println!("\nUsing different status query methods:");
121
122 println!(" All files ({} total):", status_mixed.entries.len());
123 for entry in &status_mixed.entries {
124 println!(
125 " Index {:?}, Worktree {:?}: {}",
126 entry.index_status,
127 entry.worktree_status,
128 entry.path.display()
129 );
130 }
131
132 // Query by specific status
133 let unstaged_files: Vec<_> = status_mixed.unstaged_files().collect();
134 if !unstaged_files.is_empty() {
135 println!("\n Unstaged files ({}):", unstaged_files.len());
136 for entry in &unstaged_files {
137 println!(" - {}", entry.path.display());
138 }
139 }
140
141 let untracked_files: Vec<_> = status_mixed.untracked_entries().collect();
142 if !untracked_files.is_empty() {
143 println!("\n Untracked files ({}):", untracked_files.len());
144 for entry in &untracked_files {
145 println!(" - {}", entry.path.display());
146 }
147 }
148
149 // Query by IndexStatus enum
150 let added_files: Vec<_> = status_mixed
151 .files_with_index_status(IndexStatus::Added)
152 .collect();
153 if !added_files.is_empty() {
154 println!("\n Added files ({}):", added_files.len());
155 for entry in &added_files {
156 println!(" - {}", entry.path.display());
157 }
158 }
159
160 println!();
161
162 println!("=== File Status Filtering Examples ===\n");
163
164 // Demonstrate filtering capabilities
165 println!("Filtering examples:");
166
167 // Count files by status
168 let mut index_status_counts = std::collections::HashMap::new();
169 let mut worktree_status_counts = std::collections::HashMap::new();
170
171 for entry in &status_mixed.entries {
172 if !matches!(entry.index_status, IndexStatus::Clean) {
173 *index_status_counts
174 .entry(format!("{:?}", entry.index_status))
175 .or_insert(0) += 1;
176 }
177 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
178 *worktree_status_counts
179 .entry(format!("{:?}", entry.worktree_status))
180 .or_insert(0) += 1;
181 }
182 }
183
184 println!(" Index status counts:");
185 for (status, count) in &index_status_counts {
186 println!(" {}: {} files", status, count);
187 }
188
189 println!(" Worktree status counts:");
190 for (status, count) in &worktree_status_counts {
191 println!(" {}: {} files", status, count);
192 }
193
194 // Filter for specific patterns
195 let txt_files: Vec<_> = status_mixed
196 .entries
197 .iter()
198 .filter(|entry| entry.path.to_string_lossy().ends_with(".txt"))
199 .collect();
200
201 if !txt_files.is_empty() {
202 println!("\n .txt files:");
203 for entry in txt_files {
204 println!(
205 " Index {:?}, Worktree {:?}: {}",
206 entry.index_status,
207 entry.worktree_status,
208 entry.path.display()
209 );
210 }
211 }
212
213 println!();
214
215 println!("=== Repository State Checking ===\n");
216
217 println!("Repository state summary:");
218 println!(" Total files tracked: {}", status_mixed.entries.len());
219 println!(" Is clean: {}", status_mixed.is_clean());
220 println!(" Has changes: {}", status_mixed.has_changes());
221
222 if status_mixed.has_changes() {
223 println!(" Repository needs attention!");
224
225 let unstaged_count = status_mixed.unstaged_files().count();
226 if unstaged_count > 0 {
227 println!(" - {} files need to be staged", unstaged_count);
228 }
229
230 let untracked_count = status_mixed.untracked_entries().count();
231 if untracked_count > 0 {
232 println!(" - {} untracked files to consider", untracked_count);
233 }
234
235 let staged_count = status_mixed.staged_files().count();
236 if staged_count > 0 {
237 println!(" - {} files ready to commit", staged_count);
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Status checking example completed!");
245
246 Ok(())
247}
More examples
examples/staging_operations.rs (line 228)
14fn main() -> Result<()> {
15 println!("Rustic Git - Staging Operations Example\n");
16
17 let repo_path = env::temp_dir().join("rustic_git_staging_example");
18
19 // Clean up any previous run
20 if repo_path.exists() {
21 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
22 }
23
24 // Initialize repository and create initial commit
25 println!("Setting up repository with initial files...");
26 let repo = Repository::init(&repo_path, false)?;
27
28 // Create initial files
29 fs::create_dir_all(repo_path.join("src"))?;
30 fs::create_dir_all(repo_path.join("docs"))?;
31
32 fs::write(
33 repo_path.join("README.md"),
34 "# Staging Demo\nOriginal content",
35 )?;
36 fs::write(
37 repo_path.join("src/main.rs"),
38 "fn main() { println!(\"v1\"); }",
39 )?;
40 fs::write(
41 repo_path.join("src/lib.rs"),
42 "pub fn version() -> &'static str { \"1.0\" }",
43 )?;
44
45 // Create initial commit so we can demonstrate staging tracked file changes
46 repo.add_all()?;
47 let _initial_hash = repo.commit("Initial commit with basic files")?;
48 println!("Created initial repository with 3 files\n");
49
50 println!("=== Staging Specific Files with add() ===\n");
51
52 // Create some new files and modify existing ones
53 println!("Creating new files and modifying existing ones...");
54 fs::write(repo_path.join("new_file1.txt"), "New file 1 content")?;
55 fs::write(repo_path.join("new_file2.txt"), "New file 2 content")?;
56 fs::write(repo_path.join("docs/guide.md"), "# User Guide")?;
57
58 // Modify existing files
59 fs::write(
60 repo_path.join("README.md"),
61 "# Staging Demo\nUpdated content!",
62 )?;
63 fs::write(
64 repo_path.join("src/main.rs"),
65 "fn main() { println!(\"v2 - updated!\"); }",
66 )?;
67
68 println!("Created 3 new files and modified 2 existing files");
69
70 // Show status before staging
71 println!("\nStatus before staging:");
72 let status_before = repo.status()?;
73 display_status_breakdown(&status_before);
74
75 // Stage specific files using add()
76 println!("\nUsing add() to stage specific files:");
77
78 // Stage just the README.md
79 repo.add(&["README.md"])?;
80 println!(" Staged README.md");
81
82 let status_after_readme = repo.status()?;
83 display_status_changes(
84 &status_before,
85 &status_after_readme,
86 "after staging README.md",
87 );
88
89 // Stage multiple specific files
90 repo.add(&["new_file1.txt", "src/main.rs"])?;
91 println!(" Staged new_file1.txt and src/main.rs");
92
93 let status_after_multiple = repo.status()?;
94 display_status_changes(
95 &status_after_readme,
96 &status_after_multiple,
97 "after staging multiple files",
98 );
99
100 // Stage using Path objects (alternative syntax)
101 use std::path::Path as StdPath;
102 repo.add(&[StdPath::new("docs/guide.md")])?;
103 println!(" Staged docs/guide.md using Path object");
104
105 let status_after_path = repo.status()?;
106 display_status_changes(
107 &status_after_multiple,
108 &status_after_path,
109 "after staging with Path object",
110 );
111
112 println!();
113
114 println!("=== Staging All Changes with add_all() ===\n");
115
116 // Create more files to demonstrate add_all()
117 println!("Creating additional files for add_all() demo...");
118 fs::write(
119 repo_path.join("config.toml"),
120 "[package]\nname = \"example\"",
121 )?;
122 fs::write(repo_path.join("src/utils.rs"), "pub fn helper() {}")?;
123 fs::create_dir_all(repo_path.join("tests"))?;
124 fs::write(
125 repo_path.join("tests/integration.rs"),
126 "#[test]\nfn test_basic() {}",
127 )?;
128
129 println!("Created 3 more files");
130
131 let status_before_add_all = repo.status()?;
132 println!("\nStatus before add_all():");
133 display_status_breakdown(&status_before_add_all);
134
135 // Use add_all() to stage everything remaining
136 println!("\nUsing add_all() to stage all remaining changes:");
137 repo.add_all()?;
138 println!(" Staged all changes with add_all()");
139
140 let status_after_add_all = repo.status()?;
141 display_status_changes(
142 &status_before_add_all,
143 &status_after_add_all,
144 "after add_all()",
145 );
146
147 // Create a commit to set up for add_update() demo
148 let _commit_hash = repo.commit("Add all new files and modifications")?;
149 println!(" Committed all staged changes\n");
150
151 println!("=== Staging Tracked Changes with add_update() ===\n");
152
153 // Create new untracked files and modify existing tracked files
154 println!("Setting up files for add_update() demonstration...");
155
156 // Create new untracked files (these should NOT be staged by add_update)
157 fs::write(repo_path.join("untracked1.txt"), "This is untracked")?;
158 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
159
160 // Modify existing tracked files (these SHOULD be staged by add_update)
161 fs::write(
162 repo_path.join("README.md"),
163 "# Staging Demo\nContent updated again for add_update demo!",
164 )?;
165 fs::write(
166 repo_path.join("src/lib.rs"),
167 "pub fn version() -> &'static str { \"2.0\" }",
168 )?;
169 fs::write(
170 repo_path.join("config.toml"),
171 "[package]\nname = \"example\"\nversion = \"0.2.0\"",
172 )?;
173
174 println!("Created 2 untracked files and modified 3 tracked files");
175
176 let status_before_add_update = repo.status()?;
177 println!("\nStatus before add_update():");
178 display_status_breakdown(&status_before_add_update);
179
180 // Use add_update() to stage only tracked file changes
181 println!("\nUsing add_update() to stage only tracked file modifications:");
182 repo.add_update()?;
183 println!(" Used add_update() - should stage modified tracked files only");
184
185 let status_after_add_update = repo.status()?;
186 display_status_changes(
187 &status_before_add_update,
188 &status_after_add_update,
189 "after add_update()",
190 );
191
192 // Verify that untracked files are still untracked
193 let remaining_untracked: Vec<_> = status_after_add_update.untracked_entries().collect();
194 if !remaining_untracked.is_empty() {
195 println!(" Untracked files remain untracked (as expected):");
196 for entry in remaining_untracked {
197 println!(" - {}", entry.path.display());
198 }
199 }
200
201 println!();
202
203 println!("=== Error Handling in Staging Operations ===\n");
204
205 // Demonstrate error handling
206 println!("Testing error conditions:");
207
208 // Try to add non-existent files
209 match repo.add(&["nonexistent_file.txt"]) {
210 Ok(_) => println!(" Unexpectedly succeeded adding non-existent file"),
211 Err(e) => println!(" Expected error for non-existent file: {:?}", e),
212 }
213
214 // Try to add empty array (should succeed but do nothing)
215 match repo.add(&[] as &[&str]) {
216 Ok(_) => println!(" Empty add() succeeded (no-op)"),
217 Err(e) => println!(" Empty add() failed: {:?}", e),
218 }
219
220 println!();
221
222 println!("=== Final Repository State ===\n");
223
224 let final_status = repo.status()?;
225 println!("Final repository summary:");
226 display_status_breakdown(&final_status);
227
228 if final_status.has_changes() {
229 let staged_count = final_status.staged_files().count();
230 let untracked_count = final_status.untracked_entries().count();
231
232 println!("\nRepository state:");
233 println!(" {} files staged and ready to commit", staged_count);
234 println!(" {} untracked files not yet added", untracked_count);
235
236 if staged_count > 0 {
237 println!("\n You could now commit with: repo.commit(\"Your message\")?");
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Staging operations example completed!");
245
246 Ok(())
247}
Sourcepub fn staged_files(&self) -> impl Iterator<Item = &FileEntry> + '_
pub fn staged_files(&self) -> impl Iterator<Item = &FileEntry> + '_
Get all files that have changes in the index (staged)
Examples found in repository?
examples/status_checking.rs (line 235)
15fn main() -> Result<()> {
16 println!("Rustic Git - Status Checking Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_status_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 // Initialize repository
26 println!("Setting up repository for status demonstration...");
27 let repo = Repository::init(&repo_path, false)?;
28
29 println!("=== Clean Repository Status ===\n");
30
31 // Check initial status (should be clean)
32 let status = repo.status()?;
33 println!("Initial repository status:");
34 display_status_summary(&status);
35 println!();
36
37 println!("=== Creating Files with Different States ===\n");
38
39 // Create various types of files to demonstrate different statuses
40 println!("Creating test files...");
41
42 // Create some files that will be untracked
43 fs::write(repo_path.join("untracked1.txt"), "This file is untracked")?;
44 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
45
46 // Create a .gitignore to demonstrate ignored files
47 fs::write(repo_path.join(".gitignore"), "*.log\n*.tmp\n/temp/\n")?;
48
49 // Create files that will be ignored
50 fs::write(repo_path.join("debug.log"), "Log file content")?;
51 fs::write(repo_path.join("cache.tmp"), "Temporary file")?;
52 fs::create_dir_all(repo_path.join("temp"))?;
53 fs::write(repo_path.join("temp/data.txt"), "Temp data")?;
54
55 println!("Created test files");
56
57 // Check status after creating untracked files
58 println!("\nStatus after creating untracked files:");
59 let status_untracked = repo.status()?;
60 display_status_summary(&status_untracked);
61 display_detailed_status(&status_untracked);
62 println!();
63
64 println!("=== Staging Files to Show 'Added' Status ===\n");
65
66 // Stage some files to show "Added" status
67 repo.add(&["untracked1.txt", ".gitignore"])?;
68 println!("Staged untracked1.txt and .gitignore");
69
70 let status_added = repo.status()?;
71 println!("\nStatus after staging files:");
72 display_status_summary(&status_added);
73 display_detailed_status(&status_added);
74 println!();
75
76 println!("=== Creating Initial Commit ===\n");
77
78 // Commit the staged files so we can demonstrate modified/deleted states
79 let _hash = repo.commit("Initial commit with basic files")?;
80 println!("Created initial commit");
81
82 let status_after_commit = repo.status()?;
83 println!("\nStatus after commit:");
84 display_status_summary(&status_after_commit);
85 if !status_after_commit.is_clean() {
86 display_detailed_status(&status_after_commit);
87 }
88 println!();
89
90 println!("=== Modifying Files to Show 'Modified' Status ===\n");
91
92 // Modify existing tracked files
93 fs::write(
94 repo_path.join("untracked1.txt"),
95 "This file has been MODIFIED!",
96 )?;
97 fs::write(
98 repo_path.join(".gitignore"),
99 "*.log\n*.tmp\n/temp/\n# Added comment\n",
100 )?;
101 println!("Modified untracked1.txt and .gitignore");
102
103 let status_modified = repo.status()?;
104 println!("\nStatus after modifying files:");
105 display_status_summary(&status_modified);
106 display_detailed_status(&status_modified);
107 println!();
108
109 println!("=== Demonstrating All Status Query Methods ===\n");
110
111 // Stage one of the modified files to show mixed states
112 repo.add(&["untracked1.txt"])?;
113 println!("Staged untracked1.txt (now shows as Added)");
114
115 let status_mixed = repo.status()?;
116 println!("\nMixed status demonstration:");
117 display_status_summary(&status_mixed);
118
119 // Demonstrate different query methods
120 println!("\nUsing different status query methods:");
121
122 println!(" All files ({} total):", status_mixed.entries.len());
123 for entry in &status_mixed.entries {
124 println!(
125 " Index {:?}, Worktree {:?}: {}",
126 entry.index_status,
127 entry.worktree_status,
128 entry.path.display()
129 );
130 }
131
132 // Query by specific status
133 let unstaged_files: Vec<_> = status_mixed.unstaged_files().collect();
134 if !unstaged_files.is_empty() {
135 println!("\n Unstaged files ({}):", unstaged_files.len());
136 for entry in &unstaged_files {
137 println!(" - {}", entry.path.display());
138 }
139 }
140
141 let untracked_files: Vec<_> = status_mixed.untracked_entries().collect();
142 if !untracked_files.is_empty() {
143 println!("\n Untracked files ({}):", untracked_files.len());
144 for entry in &untracked_files {
145 println!(" - {}", entry.path.display());
146 }
147 }
148
149 // Query by IndexStatus enum
150 let added_files: Vec<_> = status_mixed
151 .files_with_index_status(IndexStatus::Added)
152 .collect();
153 if !added_files.is_empty() {
154 println!("\n Added files ({}):", added_files.len());
155 for entry in &added_files {
156 println!(" - {}", entry.path.display());
157 }
158 }
159
160 println!();
161
162 println!("=== File Status Filtering Examples ===\n");
163
164 // Demonstrate filtering capabilities
165 println!("Filtering examples:");
166
167 // Count files by status
168 let mut index_status_counts = std::collections::HashMap::new();
169 let mut worktree_status_counts = std::collections::HashMap::new();
170
171 for entry in &status_mixed.entries {
172 if !matches!(entry.index_status, IndexStatus::Clean) {
173 *index_status_counts
174 .entry(format!("{:?}", entry.index_status))
175 .or_insert(0) += 1;
176 }
177 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
178 *worktree_status_counts
179 .entry(format!("{:?}", entry.worktree_status))
180 .or_insert(0) += 1;
181 }
182 }
183
184 println!(" Index status counts:");
185 for (status, count) in &index_status_counts {
186 println!(" {}: {} files", status, count);
187 }
188
189 println!(" Worktree status counts:");
190 for (status, count) in &worktree_status_counts {
191 println!(" {}: {} files", status, count);
192 }
193
194 // Filter for specific patterns
195 let txt_files: Vec<_> = status_mixed
196 .entries
197 .iter()
198 .filter(|entry| entry.path.to_string_lossy().ends_with(".txt"))
199 .collect();
200
201 if !txt_files.is_empty() {
202 println!("\n .txt files:");
203 for entry in txt_files {
204 println!(
205 " Index {:?}, Worktree {:?}: {}",
206 entry.index_status,
207 entry.worktree_status,
208 entry.path.display()
209 );
210 }
211 }
212
213 println!();
214
215 println!("=== Repository State Checking ===\n");
216
217 println!("Repository state summary:");
218 println!(" Total files tracked: {}", status_mixed.entries.len());
219 println!(" Is clean: {}", status_mixed.is_clean());
220 println!(" Has changes: {}", status_mixed.has_changes());
221
222 if status_mixed.has_changes() {
223 println!(" Repository needs attention!");
224
225 let unstaged_count = status_mixed.unstaged_files().count();
226 if unstaged_count > 0 {
227 println!(" - {} files need to be staged", unstaged_count);
228 }
229
230 let untracked_count = status_mixed.untracked_entries().count();
231 if untracked_count > 0 {
232 println!(" - {} untracked files to consider", untracked_count);
233 }
234
235 let staged_count = status_mixed.staged_files().count();
236 if staged_count > 0 {
237 println!(" - {} files ready to commit", staged_count);
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Status checking example completed!");
245
246 Ok(())
247}
More examples
examples/staging_operations.rs (line 229)
14fn main() -> Result<()> {
15 println!("Rustic Git - Staging Operations Example\n");
16
17 let repo_path = env::temp_dir().join("rustic_git_staging_example");
18
19 // Clean up any previous run
20 if repo_path.exists() {
21 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
22 }
23
24 // Initialize repository and create initial commit
25 println!("Setting up repository with initial files...");
26 let repo = Repository::init(&repo_path, false)?;
27
28 // Create initial files
29 fs::create_dir_all(repo_path.join("src"))?;
30 fs::create_dir_all(repo_path.join("docs"))?;
31
32 fs::write(
33 repo_path.join("README.md"),
34 "# Staging Demo\nOriginal content",
35 )?;
36 fs::write(
37 repo_path.join("src/main.rs"),
38 "fn main() { println!(\"v1\"); }",
39 )?;
40 fs::write(
41 repo_path.join("src/lib.rs"),
42 "pub fn version() -> &'static str { \"1.0\" }",
43 )?;
44
45 // Create initial commit so we can demonstrate staging tracked file changes
46 repo.add_all()?;
47 let _initial_hash = repo.commit("Initial commit with basic files")?;
48 println!("Created initial repository with 3 files\n");
49
50 println!("=== Staging Specific Files with add() ===\n");
51
52 // Create some new files and modify existing ones
53 println!("Creating new files and modifying existing ones...");
54 fs::write(repo_path.join("new_file1.txt"), "New file 1 content")?;
55 fs::write(repo_path.join("new_file2.txt"), "New file 2 content")?;
56 fs::write(repo_path.join("docs/guide.md"), "# User Guide")?;
57
58 // Modify existing files
59 fs::write(
60 repo_path.join("README.md"),
61 "# Staging Demo\nUpdated content!",
62 )?;
63 fs::write(
64 repo_path.join("src/main.rs"),
65 "fn main() { println!(\"v2 - updated!\"); }",
66 )?;
67
68 println!("Created 3 new files and modified 2 existing files");
69
70 // Show status before staging
71 println!("\nStatus before staging:");
72 let status_before = repo.status()?;
73 display_status_breakdown(&status_before);
74
75 // Stage specific files using add()
76 println!("\nUsing add() to stage specific files:");
77
78 // Stage just the README.md
79 repo.add(&["README.md"])?;
80 println!(" Staged README.md");
81
82 let status_after_readme = repo.status()?;
83 display_status_changes(
84 &status_before,
85 &status_after_readme,
86 "after staging README.md",
87 );
88
89 // Stage multiple specific files
90 repo.add(&["new_file1.txt", "src/main.rs"])?;
91 println!(" Staged new_file1.txt and src/main.rs");
92
93 let status_after_multiple = repo.status()?;
94 display_status_changes(
95 &status_after_readme,
96 &status_after_multiple,
97 "after staging multiple files",
98 );
99
100 // Stage using Path objects (alternative syntax)
101 use std::path::Path as StdPath;
102 repo.add(&[StdPath::new("docs/guide.md")])?;
103 println!(" Staged docs/guide.md using Path object");
104
105 let status_after_path = repo.status()?;
106 display_status_changes(
107 &status_after_multiple,
108 &status_after_path,
109 "after staging with Path object",
110 );
111
112 println!();
113
114 println!("=== Staging All Changes with add_all() ===\n");
115
116 // Create more files to demonstrate add_all()
117 println!("Creating additional files for add_all() demo...");
118 fs::write(
119 repo_path.join("config.toml"),
120 "[package]\nname = \"example\"",
121 )?;
122 fs::write(repo_path.join("src/utils.rs"), "pub fn helper() {}")?;
123 fs::create_dir_all(repo_path.join("tests"))?;
124 fs::write(
125 repo_path.join("tests/integration.rs"),
126 "#[test]\nfn test_basic() {}",
127 )?;
128
129 println!("Created 3 more files");
130
131 let status_before_add_all = repo.status()?;
132 println!("\nStatus before add_all():");
133 display_status_breakdown(&status_before_add_all);
134
135 // Use add_all() to stage everything remaining
136 println!("\nUsing add_all() to stage all remaining changes:");
137 repo.add_all()?;
138 println!(" Staged all changes with add_all()");
139
140 let status_after_add_all = repo.status()?;
141 display_status_changes(
142 &status_before_add_all,
143 &status_after_add_all,
144 "after add_all()",
145 );
146
147 // Create a commit to set up for add_update() demo
148 let _commit_hash = repo.commit("Add all new files and modifications")?;
149 println!(" Committed all staged changes\n");
150
151 println!("=== Staging Tracked Changes with add_update() ===\n");
152
153 // Create new untracked files and modify existing tracked files
154 println!("Setting up files for add_update() demonstration...");
155
156 // Create new untracked files (these should NOT be staged by add_update)
157 fs::write(repo_path.join("untracked1.txt"), "This is untracked")?;
158 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
159
160 // Modify existing tracked files (these SHOULD be staged by add_update)
161 fs::write(
162 repo_path.join("README.md"),
163 "# Staging Demo\nContent updated again for add_update demo!",
164 )?;
165 fs::write(
166 repo_path.join("src/lib.rs"),
167 "pub fn version() -> &'static str { \"2.0\" }",
168 )?;
169 fs::write(
170 repo_path.join("config.toml"),
171 "[package]\nname = \"example\"\nversion = \"0.2.0\"",
172 )?;
173
174 println!("Created 2 untracked files and modified 3 tracked files");
175
176 let status_before_add_update = repo.status()?;
177 println!("\nStatus before add_update():");
178 display_status_breakdown(&status_before_add_update);
179
180 // Use add_update() to stage only tracked file changes
181 println!("\nUsing add_update() to stage only tracked file modifications:");
182 repo.add_update()?;
183 println!(" Used add_update() - should stage modified tracked files only");
184
185 let status_after_add_update = repo.status()?;
186 display_status_changes(
187 &status_before_add_update,
188 &status_after_add_update,
189 "after add_update()",
190 );
191
192 // Verify that untracked files are still untracked
193 let remaining_untracked: Vec<_> = status_after_add_update.untracked_entries().collect();
194 if !remaining_untracked.is_empty() {
195 println!(" Untracked files remain untracked (as expected):");
196 for entry in remaining_untracked {
197 println!(" - {}", entry.path.display());
198 }
199 }
200
201 println!();
202
203 println!("=== Error Handling in Staging Operations ===\n");
204
205 // Demonstrate error handling
206 println!("Testing error conditions:");
207
208 // Try to add non-existent files
209 match repo.add(&["nonexistent_file.txt"]) {
210 Ok(_) => println!(" Unexpectedly succeeded adding non-existent file"),
211 Err(e) => println!(" Expected error for non-existent file: {:?}", e),
212 }
213
214 // Try to add empty array (should succeed but do nothing)
215 match repo.add(&[] as &[&str]) {
216 Ok(_) => println!(" Empty add() succeeded (no-op)"),
217 Err(e) => println!(" Empty add() failed: {:?}", e),
218 }
219
220 println!();
221
222 println!("=== Final Repository State ===\n");
223
224 let final_status = repo.status()?;
225 println!("Final repository summary:");
226 display_status_breakdown(&final_status);
227
228 if final_status.has_changes() {
229 let staged_count = final_status.staged_files().count();
230 let untracked_count = final_status.untracked_entries().count();
231
232 println!("\nRepository state:");
233 println!(" {} files staged and ready to commit", staged_count);
234 println!(" {} untracked files not yet added", untracked_count);
235
236 if staged_count > 0 {
237 println!("\n You could now commit with: repo.commit(\"Your message\")?");
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Staging operations example completed!");
245
246 Ok(())
247}
248
249/// Display a breakdown of repository status
250fn display_status_breakdown(status: &rustic_git::GitStatus) {
251 if status.is_clean() {
252 println!(" Repository is clean");
253 return;
254 }
255
256 let mut index_counts = std::collections::HashMap::new();
257 let mut worktree_counts = std::collections::HashMap::new();
258
259 for entry in &status.entries {
260 if !matches!(entry.index_status, IndexStatus::Clean) {
261 *index_counts.entry(&entry.index_status).or_insert(0) += 1;
262 }
263 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
264 *worktree_counts.entry(&entry.worktree_status).or_insert(0) += 1;
265 }
266 }
267
268 println!(" Index status:");
269 for (index_status, count) in &index_counts {
270 let marker = match index_status {
271 IndexStatus::Modified => "[M]",
272 IndexStatus::Added => "[A]",
273 IndexStatus::Deleted => "[D]",
274 IndexStatus::Renamed => "[R]",
275 IndexStatus::Copied => "[C]",
276 IndexStatus::Clean => "[ ]",
277 };
278 println!(" {} {:?}: {} files", marker, index_status, count);
279 }
280
281 println!(" Worktree status:");
282 for (worktree_status, count) in &worktree_counts {
283 let marker = match worktree_status {
284 WorktreeStatus::Modified => "[M]",
285 WorktreeStatus::Deleted => "[D]",
286 WorktreeStatus::Untracked => "[?]",
287 WorktreeStatus::Ignored => "[I]",
288 WorktreeStatus::Clean => "[ ]",
289 };
290 println!(" {} {:?}: {} files", marker, worktree_status, count);
291 }
292}
293
294/// Display changes between two status states
295fn display_status_changes(
296 before: &rustic_git::GitStatus,
297 after: &rustic_git::GitStatus,
298 description: &str,
299) {
300 println!("\n Status changes {}:", description);
301
302 let before_count = before.entries.len();
303 let after_count = after.entries.len();
304
305 if before_count == after_count {
306 println!(" Total files unchanged ({} files)", after_count);
307 } else {
308 println!(
309 " Total files: {} → {} ({:+})",
310 before_count,
311 after_count,
312 after_count as i32 - before_count as i32
313 );
314 }
315
316 // Show status summary
317 let before_staged = before.staged_files().count();
318 let after_staged = after.staged_files().count();
319 let before_untracked = before.untracked_entries().count();
320 let after_untracked = after.untracked_entries().count();
321
322 if before_staged != after_staged {
323 println!(
324 " Staged files: {} → {} ({:+})",
325 before_staged,
326 after_staged,
327 after_staged as i32 - before_staged as i32
328 );
329 }
330
331 if before_untracked != after_untracked {
332 println!(
333 " Untracked files: {} → {} ({:+})",
334 before_untracked,
335 after_untracked,
336 after_untracked as i32 - before_untracked as i32
337 );
338 }
339}
Sourcepub fn unstaged_files(&self) -> impl Iterator<Item = &FileEntry> + '_
pub fn unstaged_files(&self) -> impl Iterator<Item = &FileEntry> + '_
Get all files that have changes in the working tree (unstaged)
Examples found in repository?
examples/basic_usage.rs (line 65)
16fn main() -> Result<()> {
17 println!("Rustic Git - Basic Usage Example\n");
18
19 // Use a temporary directory for this example
20 let repo_path = env::temp_dir().join("rustic_git_basic_example");
21
22 // Clean up any previous run
23 if repo_path.exists() {
24 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
25 }
26
27 println!("Initializing new repository at: {}", repo_path.display());
28
29 // Initialize a new repository
30 let repo = Repository::init(&repo_path, false)?;
31 println!("Repository initialized successfully\n");
32
33 // Create some example files
34 println!("Creating example files...");
35 fs::create_dir_all(repo_path.join("src"))?;
36
37 fs::write(
38 repo_path.join("README.md"),
39 "# My Awesome Project\n\nThis is a demo project for rustic-git!\n",
40 )?;
41
42 fs::write(
43 repo_path.join("src/main.rs"),
44 r#"fn main() {
45 println!("Hello from rustic-git example!");
46}
47"#,
48 )?;
49
50 fs::write(
51 repo_path.join("src/lib.rs"),
52 "// Library code goes here\npub fn hello() -> &'static str {\n \"Hello, World!\"\n}\n",
53 )?;
54
55 println!("Created 3 files: README.md, src/main.rs, src/lib.rs\n");
56
57 // Check repository status
58 println!("Checking repository status...");
59 let status = repo.status()?;
60
61 if status.is_clean() {
62 println!(" Repository is clean (no changes)");
63 } else {
64 println!(" Repository has changes:");
65 println!(" Unstaged files: {}", status.unstaged_files().count());
66 println!(" Untracked files: {}", status.untracked_entries().count());
67
68 // Show untracked files
69 for entry in status.untracked_entries() {
70 println!(" - {}", entry.path.display());
71 }
72 }
73 println!();
74
75 // Stage specific files first
76 println!("Staging files...");
77
78 // Stage README.md first
79 repo.add(&["README.md"])?;
80 println!("Staged README.md");
81
82 // Stage all remaining files
83 repo.add_all()?;
84 println!("Staged all remaining files");
85
86 // Check status after staging
87 let status_after_staging = repo.status()?;
88 println!("\nStatus after staging:");
89 if status_after_staging.is_clean() {
90 println!(" Repository is clean (all changes staged)");
91 } else {
92 println!(
93 " Files staged for commit: {}",
94 status_after_staging.entries.len()
95 );
96 for entry in &status_after_staging.entries {
97 println!(
98 " Index {:?}, Worktree {:?}: {}",
99 entry.index_status,
100 entry.worktree_status,
101 entry.path.display()
102 );
103 }
104 }
105 println!();
106
107 // Create a commit
108 println!("Creating commit...");
109 let hash = repo.commit("Initial commit: Add project structure and basic files")?;
110
111 println!("Commit created successfully!");
112 println!(" Full hash: {}", hash);
113 println!(" Short hash: {}", hash.short());
114 println!();
115
116 // Verify final status
117 println!("Final repository status:");
118 let final_status = repo.status()?;
119 if final_status.is_clean() {
120 println!(" Repository is clean - all changes committed!");
121 } else {
122 println!(" Repository still has uncommitted changes");
123 }
124 println!();
125
126 // Clean up
127 println!("Cleaning up example repository...");
128 fs::remove_dir_all(&repo_path)?;
129 println!("Example completed successfully!");
130
131 Ok(())
132}
More examples
examples/status_checking.rs (line 133)
15fn main() -> Result<()> {
16 println!("Rustic Git - Status Checking Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_status_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 // Initialize repository
26 println!("Setting up repository for status demonstration...");
27 let repo = Repository::init(&repo_path, false)?;
28
29 println!("=== Clean Repository Status ===\n");
30
31 // Check initial status (should be clean)
32 let status = repo.status()?;
33 println!("Initial repository status:");
34 display_status_summary(&status);
35 println!();
36
37 println!("=== Creating Files with Different States ===\n");
38
39 // Create various types of files to demonstrate different statuses
40 println!("Creating test files...");
41
42 // Create some files that will be untracked
43 fs::write(repo_path.join("untracked1.txt"), "This file is untracked")?;
44 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
45
46 // Create a .gitignore to demonstrate ignored files
47 fs::write(repo_path.join(".gitignore"), "*.log\n*.tmp\n/temp/\n")?;
48
49 // Create files that will be ignored
50 fs::write(repo_path.join("debug.log"), "Log file content")?;
51 fs::write(repo_path.join("cache.tmp"), "Temporary file")?;
52 fs::create_dir_all(repo_path.join("temp"))?;
53 fs::write(repo_path.join("temp/data.txt"), "Temp data")?;
54
55 println!("Created test files");
56
57 // Check status after creating untracked files
58 println!("\nStatus after creating untracked files:");
59 let status_untracked = repo.status()?;
60 display_status_summary(&status_untracked);
61 display_detailed_status(&status_untracked);
62 println!();
63
64 println!("=== Staging Files to Show 'Added' Status ===\n");
65
66 // Stage some files to show "Added" status
67 repo.add(&["untracked1.txt", ".gitignore"])?;
68 println!("Staged untracked1.txt and .gitignore");
69
70 let status_added = repo.status()?;
71 println!("\nStatus after staging files:");
72 display_status_summary(&status_added);
73 display_detailed_status(&status_added);
74 println!();
75
76 println!("=== Creating Initial Commit ===\n");
77
78 // Commit the staged files so we can demonstrate modified/deleted states
79 let _hash = repo.commit("Initial commit with basic files")?;
80 println!("Created initial commit");
81
82 let status_after_commit = repo.status()?;
83 println!("\nStatus after commit:");
84 display_status_summary(&status_after_commit);
85 if !status_after_commit.is_clean() {
86 display_detailed_status(&status_after_commit);
87 }
88 println!();
89
90 println!("=== Modifying Files to Show 'Modified' Status ===\n");
91
92 // Modify existing tracked files
93 fs::write(
94 repo_path.join("untracked1.txt"),
95 "This file has been MODIFIED!",
96 )?;
97 fs::write(
98 repo_path.join(".gitignore"),
99 "*.log\n*.tmp\n/temp/\n# Added comment\n",
100 )?;
101 println!("Modified untracked1.txt and .gitignore");
102
103 let status_modified = repo.status()?;
104 println!("\nStatus after modifying files:");
105 display_status_summary(&status_modified);
106 display_detailed_status(&status_modified);
107 println!();
108
109 println!("=== Demonstrating All Status Query Methods ===\n");
110
111 // Stage one of the modified files to show mixed states
112 repo.add(&["untracked1.txt"])?;
113 println!("Staged untracked1.txt (now shows as Added)");
114
115 let status_mixed = repo.status()?;
116 println!("\nMixed status demonstration:");
117 display_status_summary(&status_mixed);
118
119 // Demonstrate different query methods
120 println!("\nUsing different status query methods:");
121
122 println!(" All files ({} total):", status_mixed.entries.len());
123 for entry in &status_mixed.entries {
124 println!(
125 " Index {:?}, Worktree {:?}: {}",
126 entry.index_status,
127 entry.worktree_status,
128 entry.path.display()
129 );
130 }
131
132 // Query by specific status
133 let unstaged_files: Vec<_> = status_mixed.unstaged_files().collect();
134 if !unstaged_files.is_empty() {
135 println!("\n Unstaged files ({}):", unstaged_files.len());
136 for entry in &unstaged_files {
137 println!(" - {}", entry.path.display());
138 }
139 }
140
141 let untracked_files: Vec<_> = status_mixed.untracked_entries().collect();
142 if !untracked_files.is_empty() {
143 println!("\n Untracked files ({}):", untracked_files.len());
144 for entry in &untracked_files {
145 println!(" - {}", entry.path.display());
146 }
147 }
148
149 // Query by IndexStatus enum
150 let added_files: Vec<_> = status_mixed
151 .files_with_index_status(IndexStatus::Added)
152 .collect();
153 if !added_files.is_empty() {
154 println!("\n Added files ({}):", added_files.len());
155 for entry in &added_files {
156 println!(" - {}", entry.path.display());
157 }
158 }
159
160 println!();
161
162 println!("=== File Status Filtering Examples ===\n");
163
164 // Demonstrate filtering capabilities
165 println!("Filtering examples:");
166
167 // Count files by status
168 let mut index_status_counts = std::collections::HashMap::new();
169 let mut worktree_status_counts = std::collections::HashMap::new();
170
171 for entry in &status_mixed.entries {
172 if !matches!(entry.index_status, IndexStatus::Clean) {
173 *index_status_counts
174 .entry(format!("{:?}", entry.index_status))
175 .or_insert(0) += 1;
176 }
177 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
178 *worktree_status_counts
179 .entry(format!("{:?}", entry.worktree_status))
180 .or_insert(0) += 1;
181 }
182 }
183
184 println!(" Index status counts:");
185 for (status, count) in &index_status_counts {
186 println!(" {}: {} files", status, count);
187 }
188
189 println!(" Worktree status counts:");
190 for (status, count) in &worktree_status_counts {
191 println!(" {}: {} files", status, count);
192 }
193
194 // Filter for specific patterns
195 let txt_files: Vec<_> = status_mixed
196 .entries
197 .iter()
198 .filter(|entry| entry.path.to_string_lossy().ends_with(".txt"))
199 .collect();
200
201 if !txt_files.is_empty() {
202 println!("\n .txt files:");
203 for entry in txt_files {
204 println!(
205 " Index {:?}, Worktree {:?}: {}",
206 entry.index_status,
207 entry.worktree_status,
208 entry.path.display()
209 );
210 }
211 }
212
213 println!();
214
215 println!("=== Repository State Checking ===\n");
216
217 println!("Repository state summary:");
218 println!(" Total files tracked: {}", status_mixed.entries.len());
219 println!(" Is clean: {}", status_mixed.is_clean());
220 println!(" Has changes: {}", status_mixed.has_changes());
221
222 if status_mixed.has_changes() {
223 println!(" Repository needs attention!");
224
225 let unstaged_count = status_mixed.unstaged_files().count();
226 if unstaged_count > 0 {
227 println!(" - {} files need to be staged", unstaged_count);
228 }
229
230 let untracked_count = status_mixed.untracked_entries().count();
231 if untracked_count > 0 {
232 println!(" - {} untracked files to consider", untracked_count);
233 }
234
235 let staged_count = status_mixed.staged_files().count();
236 if staged_count > 0 {
237 println!(" - {} files ready to commit", staged_count);
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Status checking example completed!");
245
246 Ok(())
247}
248
249/// Display a summary of the repository status
250fn display_status_summary(status: &rustic_git::GitStatus) {
251 if status.is_clean() {
252 println!(" Repository is clean (no changes)");
253 } else {
254 println!(" Repository has {} changes", status.entries.len());
255 println!(" Unstaged: {}", status.unstaged_files().count());
256 println!(" Untracked: {}", status.untracked_entries().count());
257 }
258}
Sourcepub fn untracked_entries(&self) -> impl Iterator<Item = &FileEntry> + '_
pub fn untracked_entries(&self) -> impl Iterator<Item = &FileEntry> + '_
Get all untracked files (new API)
Examples found in repository?
examples/basic_usage.rs (line 66)
16fn main() -> Result<()> {
17 println!("Rustic Git - Basic Usage Example\n");
18
19 // Use a temporary directory for this example
20 let repo_path = env::temp_dir().join("rustic_git_basic_example");
21
22 // Clean up any previous run
23 if repo_path.exists() {
24 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
25 }
26
27 println!("Initializing new repository at: {}", repo_path.display());
28
29 // Initialize a new repository
30 let repo = Repository::init(&repo_path, false)?;
31 println!("Repository initialized successfully\n");
32
33 // Create some example files
34 println!("Creating example files...");
35 fs::create_dir_all(repo_path.join("src"))?;
36
37 fs::write(
38 repo_path.join("README.md"),
39 "# My Awesome Project\n\nThis is a demo project for rustic-git!\n",
40 )?;
41
42 fs::write(
43 repo_path.join("src/main.rs"),
44 r#"fn main() {
45 println!("Hello from rustic-git example!");
46}
47"#,
48 )?;
49
50 fs::write(
51 repo_path.join("src/lib.rs"),
52 "// Library code goes here\npub fn hello() -> &'static str {\n \"Hello, World!\"\n}\n",
53 )?;
54
55 println!("Created 3 files: README.md, src/main.rs, src/lib.rs\n");
56
57 // Check repository status
58 println!("Checking repository status...");
59 let status = repo.status()?;
60
61 if status.is_clean() {
62 println!(" Repository is clean (no changes)");
63 } else {
64 println!(" Repository has changes:");
65 println!(" Unstaged files: {}", status.unstaged_files().count());
66 println!(" Untracked files: {}", status.untracked_entries().count());
67
68 // Show untracked files
69 for entry in status.untracked_entries() {
70 println!(" - {}", entry.path.display());
71 }
72 }
73 println!();
74
75 // Stage specific files first
76 println!("Staging files...");
77
78 // Stage README.md first
79 repo.add(&["README.md"])?;
80 println!("Staged README.md");
81
82 // Stage all remaining files
83 repo.add_all()?;
84 println!("Staged all remaining files");
85
86 // Check status after staging
87 let status_after_staging = repo.status()?;
88 println!("\nStatus after staging:");
89 if status_after_staging.is_clean() {
90 println!(" Repository is clean (all changes staged)");
91 } else {
92 println!(
93 " Files staged for commit: {}",
94 status_after_staging.entries.len()
95 );
96 for entry in &status_after_staging.entries {
97 println!(
98 " Index {:?}, Worktree {:?}: {}",
99 entry.index_status,
100 entry.worktree_status,
101 entry.path.display()
102 );
103 }
104 }
105 println!();
106
107 // Create a commit
108 println!("Creating commit...");
109 let hash = repo.commit("Initial commit: Add project structure and basic files")?;
110
111 println!("Commit created successfully!");
112 println!(" Full hash: {}", hash);
113 println!(" Short hash: {}", hash.short());
114 println!();
115
116 // Verify final status
117 println!("Final repository status:");
118 let final_status = repo.status()?;
119 if final_status.is_clean() {
120 println!(" Repository is clean - all changes committed!");
121 } else {
122 println!(" Repository still has uncommitted changes");
123 }
124 println!();
125
126 // Clean up
127 println!("Cleaning up example repository...");
128 fs::remove_dir_all(&repo_path)?;
129 println!("Example completed successfully!");
130
131 Ok(())
132}
More examples
examples/status_checking.rs (line 141)
15fn main() -> Result<()> {
16 println!("Rustic Git - Status Checking Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_status_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 // Initialize repository
26 println!("Setting up repository for status demonstration...");
27 let repo = Repository::init(&repo_path, false)?;
28
29 println!("=== Clean Repository Status ===\n");
30
31 // Check initial status (should be clean)
32 let status = repo.status()?;
33 println!("Initial repository status:");
34 display_status_summary(&status);
35 println!();
36
37 println!("=== Creating Files with Different States ===\n");
38
39 // Create various types of files to demonstrate different statuses
40 println!("Creating test files...");
41
42 // Create some files that will be untracked
43 fs::write(repo_path.join("untracked1.txt"), "This file is untracked")?;
44 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
45
46 // Create a .gitignore to demonstrate ignored files
47 fs::write(repo_path.join(".gitignore"), "*.log\n*.tmp\n/temp/\n")?;
48
49 // Create files that will be ignored
50 fs::write(repo_path.join("debug.log"), "Log file content")?;
51 fs::write(repo_path.join("cache.tmp"), "Temporary file")?;
52 fs::create_dir_all(repo_path.join("temp"))?;
53 fs::write(repo_path.join("temp/data.txt"), "Temp data")?;
54
55 println!("Created test files");
56
57 // Check status after creating untracked files
58 println!("\nStatus after creating untracked files:");
59 let status_untracked = repo.status()?;
60 display_status_summary(&status_untracked);
61 display_detailed_status(&status_untracked);
62 println!();
63
64 println!("=== Staging Files to Show 'Added' Status ===\n");
65
66 // Stage some files to show "Added" status
67 repo.add(&["untracked1.txt", ".gitignore"])?;
68 println!("Staged untracked1.txt and .gitignore");
69
70 let status_added = repo.status()?;
71 println!("\nStatus after staging files:");
72 display_status_summary(&status_added);
73 display_detailed_status(&status_added);
74 println!();
75
76 println!("=== Creating Initial Commit ===\n");
77
78 // Commit the staged files so we can demonstrate modified/deleted states
79 let _hash = repo.commit("Initial commit with basic files")?;
80 println!("Created initial commit");
81
82 let status_after_commit = repo.status()?;
83 println!("\nStatus after commit:");
84 display_status_summary(&status_after_commit);
85 if !status_after_commit.is_clean() {
86 display_detailed_status(&status_after_commit);
87 }
88 println!();
89
90 println!("=== Modifying Files to Show 'Modified' Status ===\n");
91
92 // Modify existing tracked files
93 fs::write(
94 repo_path.join("untracked1.txt"),
95 "This file has been MODIFIED!",
96 )?;
97 fs::write(
98 repo_path.join(".gitignore"),
99 "*.log\n*.tmp\n/temp/\n# Added comment\n",
100 )?;
101 println!("Modified untracked1.txt and .gitignore");
102
103 let status_modified = repo.status()?;
104 println!("\nStatus after modifying files:");
105 display_status_summary(&status_modified);
106 display_detailed_status(&status_modified);
107 println!();
108
109 println!("=== Demonstrating All Status Query Methods ===\n");
110
111 // Stage one of the modified files to show mixed states
112 repo.add(&["untracked1.txt"])?;
113 println!("Staged untracked1.txt (now shows as Added)");
114
115 let status_mixed = repo.status()?;
116 println!("\nMixed status demonstration:");
117 display_status_summary(&status_mixed);
118
119 // Demonstrate different query methods
120 println!("\nUsing different status query methods:");
121
122 println!(" All files ({} total):", status_mixed.entries.len());
123 for entry in &status_mixed.entries {
124 println!(
125 " Index {:?}, Worktree {:?}: {}",
126 entry.index_status,
127 entry.worktree_status,
128 entry.path.display()
129 );
130 }
131
132 // Query by specific status
133 let unstaged_files: Vec<_> = status_mixed.unstaged_files().collect();
134 if !unstaged_files.is_empty() {
135 println!("\n Unstaged files ({}):", unstaged_files.len());
136 for entry in &unstaged_files {
137 println!(" - {}", entry.path.display());
138 }
139 }
140
141 let untracked_files: Vec<_> = status_mixed.untracked_entries().collect();
142 if !untracked_files.is_empty() {
143 println!("\n Untracked files ({}):", untracked_files.len());
144 for entry in &untracked_files {
145 println!(" - {}", entry.path.display());
146 }
147 }
148
149 // Query by IndexStatus enum
150 let added_files: Vec<_> = status_mixed
151 .files_with_index_status(IndexStatus::Added)
152 .collect();
153 if !added_files.is_empty() {
154 println!("\n Added files ({}):", added_files.len());
155 for entry in &added_files {
156 println!(" - {}", entry.path.display());
157 }
158 }
159
160 println!();
161
162 println!("=== File Status Filtering Examples ===\n");
163
164 // Demonstrate filtering capabilities
165 println!("Filtering examples:");
166
167 // Count files by status
168 let mut index_status_counts = std::collections::HashMap::new();
169 let mut worktree_status_counts = std::collections::HashMap::new();
170
171 for entry in &status_mixed.entries {
172 if !matches!(entry.index_status, IndexStatus::Clean) {
173 *index_status_counts
174 .entry(format!("{:?}", entry.index_status))
175 .or_insert(0) += 1;
176 }
177 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
178 *worktree_status_counts
179 .entry(format!("{:?}", entry.worktree_status))
180 .or_insert(0) += 1;
181 }
182 }
183
184 println!(" Index status counts:");
185 for (status, count) in &index_status_counts {
186 println!(" {}: {} files", status, count);
187 }
188
189 println!(" Worktree status counts:");
190 for (status, count) in &worktree_status_counts {
191 println!(" {}: {} files", status, count);
192 }
193
194 // Filter for specific patterns
195 let txt_files: Vec<_> = status_mixed
196 .entries
197 .iter()
198 .filter(|entry| entry.path.to_string_lossy().ends_with(".txt"))
199 .collect();
200
201 if !txt_files.is_empty() {
202 println!("\n .txt files:");
203 for entry in txt_files {
204 println!(
205 " Index {:?}, Worktree {:?}: {}",
206 entry.index_status,
207 entry.worktree_status,
208 entry.path.display()
209 );
210 }
211 }
212
213 println!();
214
215 println!("=== Repository State Checking ===\n");
216
217 println!("Repository state summary:");
218 println!(" Total files tracked: {}", status_mixed.entries.len());
219 println!(" Is clean: {}", status_mixed.is_clean());
220 println!(" Has changes: {}", status_mixed.has_changes());
221
222 if status_mixed.has_changes() {
223 println!(" Repository needs attention!");
224
225 let unstaged_count = status_mixed.unstaged_files().count();
226 if unstaged_count > 0 {
227 println!(" - {} files need to be staged", unstaged_count);
228 }
229
230 let untracked_count = status_mixed.untracked_entries().count();
231 if untracked_count > 0 {
232 println!(" - {} untracked files to consider", untracked_count);
233 }
234
235 let staged_count = status_mixed.staged_files().count();
236 if staged_count > 0 {
237 println!(" - {} files ready to commit", staged_count);
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Status checking example completed!");
245
246 Ok(())
247}
248
249/// Display a summary of the repository status
250fn display_status_summary(status: &rustic_git::GitStatus) {
251 if status.is_clean() {
252 println!(" Repository is clean (no changes)");
253 } else {
254 println!(" Repository has {} changes", status.entries.len());
255 println!(" Unstaged: {}", status.unstaged_files().count());
256 println!(" Untracked: {}", status.untracked_entries().count());
257 }
258}
examples/staging_operations.rs (line 193)
14fn main() -> Result<()> {
15 println!("Rustic Git - Staging Operations Example\n");
16
17 let repo_path = env::temp_dir().join("rustic_git_staging_example");
18
19 // Clean up any previous run
20 if repo_path.exists() {
21 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
22 }
23
24 // Initialize repository and create initial commit
25 println!("Setting up repository with initial files...");
26 let repo = Repository::init(&repo_path, false)?;
27
28 // Create initial files
29 fs::create_dir_all(repo_path.join("src"))?;
30 fs::create_dir_all(repo_path.join("docs"))?;
31
32 fs::write(
33 repo_path.join("README.md"),
34 "# Staging Demo\nOriginal content",
35 )?;
36 fs::write(
37 repo_path.join("src/main.rs"),
38 "fn main() { println!(\"v1\"); }",
39 )?;
40 fs::write(
41 repo_path.join("src/lib.rs"),
42 "pub fn version() -> &'static str { \"1.0\" }",
43 )?;
44
45 // Create initial commit so we can demonstrate staging tracked file changes
46 repo.add_all()?;
47 let _initial_hash = repo.commit("Initial commit with basic files")?;
48 println!("Created initial repository with 3 files\n");
49
50 println!("=== Staging Specific Files with add() ===\n");
51
52 // Create some new files and modify existing ones
53 println!("Creating new files and modifying existing ones...");
54 fs::write(repo_path.join("new_file1.txt"), "New file 1 content")?;
55 fs::write(repo_path.join("new_file2.txt"), "New file 2 content")?;
56 fs::write(repo_path.join("docs/guide.md"), "# User Guide")?;
57
58 // Modify existing files
59 fs::write(
60 repo_path.join("README.md"),
61 "# Staging Demo\nUpdated content!",
62 )?;
63 fs::write(
64 repo_path.join("src/main.rs"),
65 "fn main() { println!(\"v2 - updated!\"); }",
66 )?;
67
68 println!("Created 3 new files and modified 2 existing files");
69
70 // Show status before staging
71 println!("\nStatus before staging:");
72 let status_before = repo.status()?;
73 display_status_breakdown(&status_before);
74
75 // Stage specific files using add()
76 println!("\nUsing add() to stage specific files:");
77
78 // Stage just the README.md
79 repo.add(&["README.md"])?;
80 println!(" Staged README.md");
81
82 let status_after_readme = repo.status()?;
83 display_status_changes(
84 &status_before,
85 &status_after_readme,
86 "after staging README.md",
87 );
88
89 // Stage multiple specific files
90 repo.add(&["new_file1.txt", "src/main.rs"])?;
91 println!(" Staged new_file1.txt and src/main.rs");
92
93 let status_after_multiple = repo.status()?;
94 display_status_changes(
95 &status_after_readme,
96 &status_after_multiple,
97 "after staging multiple files",
98 );
99
100 // Stage using Path objects (alternative syntax)
101 use std::path::Path as StdPath;
102 repo.add(&[StdPath::new("docs/guide.md")])?;
103 println!(" Staged docs/guide.md using Path object");
104
105 let status_after_path = repo.status()?;
106 display_status_changes(
107 &status_after_multiple,
108 &status_after_path,
109 "after staging with Path object",
110 );
111
112 println!();
113
114 println!("=== Staging All Changes with add_all() ===\n");
115
116 // Create more files to demonstrate add_all()
117 println!("Creating additional files for add_all() demo...");
118 fs::write(
119 repo_path.join("config.toml"),
120 "[package]\nname = \"example\"",
121 )?;
122 fs::write(repo_path.join("src/utils.rs"), "pub fn helper() {}")?;
123 fs::create_dir_all(repo_path.join("tests"))?;
124 fs::write(
125 repo_path.join("tests/integration.rs"),
126 "#[test]\nfn test_basic() {}",
127 )?;
128
129 println!("Created 3 more files");
130
131 let status_before_add_all = repo.status()?;
132 println!("\nStatus before add_all():");
133 display_status_breakdown(&status_before_add_all);
134
135 // Use add_all() to stage everything remaining
136 println!("\nUsing add_all() to stage all remaining changes:");
137 repo.add_all()?;
138 println!(" Staged all changes with add_all()");
139
140 let status_after_add_all = repo.status()?;
141 display_status_changes(
142 &status_before_add_all,
143 &status_after_add_all,
144 "after add_all()",
145 );
146
147 // Create a commit to set up for add_update() demo
148 let _commit_hash = repo.commit("Add all new files and modifications")?;
149 println!(" Committed all staged changes\n");
150
151 println!("=== Staging Tracked Changes with add_update() ===\n");
152
153 // Create new untracked files and modify existing tracked files
154 println!("Setting up files for add_update() demonstration...");
155
156 // Create new untracked files (these should NOT be staged by add_update)
157 fs::write(repo_path.join("untracked1.txt"), "This is untracked")?;
158 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
159
160 // Modify existing tracked files (these SHOULD be staged by add_update)
161 fs::write(
162 repo_path.join("README.md"),
163 "# Staging Demo\nContent updated again for add_update demo!",
164 )?;
165 fs::write(
166 repo_path.join("src/lib.rs"),
167 "pub fn version() -> &'static str { \"2.0\" }",
168 )?;
169 fs::write(
170 repo_path.join("config.toml"),
171 "[package]\nname = \"example\"\nversion = \"0.2.0\"",
172 )?;
173
174 println!("Created 2 untracked files and modified 3 tracked files");
175
176 let status_before_add_update = repo.status()?;
177 println!("\nStatus before add_update():");
178 display_status_breakdown(&status_before_add_update);
179
180 // Use add_update() to stage only tracked file changes
181 println!("\nUsing add_update() to stage only tracked file modifications:");
182 repo.add_update()?;
183 println!(" Used add_update() - should stage modified tracked files only");
184
185 let status_after_add_update = repo.status()?;
186 display_status_changes(
187 &status_before_add_update,
188 &status_after_add_update,
189 "after add_update()",
190 );
191
192 // Verify that untracked files are still untracked
193 let remaining_untracked: Vec<_> = status_after_add_update.untracked_entries().collect();
194 if !remaining_untracked.is_empty() {
195 println!(" Untracked files remain untracked (as expected):");
196 for entry in remaining_untracked {
197 println!(" - {}", entry.path.display());
198 }
199 }
200
201 println!();
202
203 println!("=== Error Handling in Staging Operations ===\n");
204
205 // Demonstrate error handling
206 println!("Testing error conditions:");
207
208 // Try to add non-existent files
209 match repo.add(&["nonexistent_file.txt"]) {
210 Ok(_) => println!(" Unexpectedly succeeded adding non-existent file"),
211 Err(e) => println!(" Expected error for non-existent file: {:?}", e),
212 }
213
214 // Try to add empty array (should succeed but do nothing)
215 match repo.add(&[] as &[&str]) {
216 Ok(_) => println!(" Empty add() succeeded (no-op)"),
217 Err(e) => println!(" Empty add() failed: {:?}", e),
218 }
219
220 println!();
221
222 println!("=== Final Repository State ===\n");
223
224 let final_status = repo.status()?;
225 println!("Final repository summary:");
226 display_status_breakdown(&final_status);
227
228 if final_status.has_changes() {
229 let staged_count = final_status.staged_files().count();
230 let untracked_count = final_status.untracked_entries().count();
231
232 println!("\nRepository state:");
233 println!(" {} files staged and ready to commit", staged_count);
234 println!(" {} untracked files not yet added", untracked_count);
235
236 if staged_count > 0 {
237 println!("\n You could now commit with: repo.commit(\"Your message\")?");
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Staging operations example completed!");
245
246 Ok(())
247}
248
249/// Display a breakdown of repository status
250fn display_status_breakdown(status: &rustic_git::GitStatus) {
251 if status.is_clean() {
252 println!(" Repository is clean");
253 return;
254 }
255
256 let mut index_counts = std::collections::HashMap::new();
257 let mut worktree_counts = std::collections::HashMap::new();
258
259 for entry in &status.entries {
260 if !matches!(entry.index_status, IndexStatus::Clean) {
261 *index_counts.entry(&entry.index_status).or_insert(0) += 1;
262 }
263 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
264 *worktree_counts.entry(&entry.worktree_status).or_insert(0) += 1;
265 }
266 }
267
268 println!(" Index status:");
269 for (index_status, count) in &index_counts {
270 let marker = match index_status {
271 IndexStatus::Modified => "[M]",
272 IndexStatus::Added => "[A]",
273 IndexStatus::Deleted => "[D]",
274 IndexStatus::Renamed => "[R]",
275 IndexStatus::Copied => "[C]",
276 IndexStatus::Clean => "[ ]",
277 };
278 println!(" {} {:?}: {} files", marker, index_status, count);
279 }
280
281 println!(" Worktree status:");
282 for (worktree_status, count) in &worktree_counts {
283 let marker = match worktree_status {
284 WorktreeStatus::Modified => "[M]",
285 WorktreeStatus::Deleted => "[D]",
286 WorktreeStatus::Untracked => "[?]",
287 WorktreeStatus::Ignored => "[I]",
288 WorktreeStatus::Clean => "[ ]",
289 };
290 println!(" {} {:?}: {} files", marker, worktree_status, count);
291 }
292}
293
294/// Display changes between two status states
295fn display_status_changes(
296 before: &rustic_git::GitStatus,
297 after: &rustic_git::GitStatus,
298 description: &str,
299) {
300 println!("\n Status changes {}:", description);
301
302 let before_count = before.entries.len();
303 let after_count = after.entries.len();
304
305 if before_count == after_count {
306 println!(" Total files unchanged ({} files)", after_count);
307 } else {
308 println!(
309 " Total files: {} → {} ({:+})",
310 before_count,
311 after_count,
312 after_count as i32 - before_count as i32
313 );
314 }
315
316 // Show status summary
317 let before_staged = before.staged_files().count();
318 let after_staged = after.staged_files().count();
319 let before_untracked = before.untracked_entries().count();
320 let after_untracked = after.untracked_entries().count();
321
322 if before_staged != after_staged {
323 println!(
324 " Staged files: {} → {} ({:+})",
325 before_staged,
326 after_staged,
327 after_staged as i32 - before_staged as i32
328 );
329 }
330
331 if before_untracked != after_untracked {
332 println!(
333 " Untracked files: {} → {} ({:+})",
334 before_untracked,
335 after_untracked,
336 after_untracked as i32 - before_untracked as i32
337 );
338 }
339}
Sourcepub fn ignored_files(&self) -> impl Iterator<Item = &FileEntry> + '_
pub fn ignored_files(&self) -> impl Iterator<Item = &FileEntry> + '_
Get all ignored files
Sourcepub fn files_with_index_status(
&self,
status: IndexStatus,
) -> impl Iterator<Item = &FileEntry> + '_
pub fn files_with_index_status( &self, status: IndexStatus, ) -> impl Iterator<Item = &FileEntry> + '_
Get files with specific index status
Examples found in repository?
examples/status_checking.rs (line 151)
15fn main() -> Result<()> {
16 println!("Rustic Git - Status Checking Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_status_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 // Initialize repository
26 println!("Setting up repository for status demonstration...");
27 let repo = Repository::init(&repo_path, false)?;
28
29 println!("=== Clean Repository Status ===\n");
30
31 // Check initial status (should be clean)
32 let status = repo.status()?;
33 println!("Initial repository status:");
34 display_status_summary(&status);
35 println!();
36
37 println!("=== Creating Files with Different States ===\n");
38
39 // Create various types of files to demonstrate different statuses
40 println!("Creating test files...");
41
42 // Create some files that will be untracked
43 fs::write(repo_path.join("untracked1.txt"), "This file is untracked")?;
44 fs::write(repo_path.join("untracked2.txt"), "Another untracked file")?;
45
46 // Create a .gitignore to demonstrate ignored files
47 fs::write(repo_path.join(".gitignore"), "*.log\n*.tmp\n/temp/\n")?;
48
49 // Create files that will be ignored
50 fs::write(repo_path.join("debug.log"), "Log file content")?;
51 fs::write(repo_path.join("cache.tmp"), "Temporary file")?;
52 fs::create_dir_all(repo_path.join("temp"))?;
53 fs::write(repo_path.join("temp/data.txt"), "Temp data")?;
54
55 println!("Created test files");
56
57 // Check status after creating untracked files
58 println!("\nStatus after creating untracked files:");
59 let status_untracked = repo.status()?;
60 display_status_summary(&status_untracked);
61 display_detailed_status(&status_untracked);
62 println!();
63
64 println!("=== Staging Files to Show 'Added' Status ===\n");
65
66 // Stage some files to show "Added" status
67 repo.add(&["untracked1.txt", ".gitignore"])?;
68 println!("Staged untracked1.txt and .gitignore");
69
70 let status_added = repo.status()?;
71 println!("\nStatus after staging files:");
72 display_status_summary(&status_added);
73 display_detailed_status(&status_added);
74 println!();
75
76 println!("=== Creating Initial Commit ===\n");
77
78 // Commit the staged files so we can demonstrate modified/deleted states
79 let _hash = repo.commit("Initial commit with basic files")?;
80 println!("Created initial commit");
81
82 let status_after_commit = repo.status()?;
83 println!("\nStatus after commit:");
84 display_status_summary(&status_after_commit);
85 if !status_after_commit.is_clean() {
86 display_detailed_status(&status_after_commit);
87 }
88 println!();
89
90 println!("=== Modifying Files to Show 'Modified' Status ===\n");
91
92 // Modify existing tracked files
93 fs::write(
94 repo_path.join("untracked1.txt"),
95 "This file has been MODIFIED!",
96 )?;
97 fs::write(
98 repo_path.join(".gitignore"),
99 "*.log\n*.tmp\n/temp/\n# Added comment\n",
100 )?;
101 println!("Modified untracked1.txt and .gitignore");
102
103 let status_modified = repo.status()?;
104 println!("\nStatus after modifying files:");
105 display_status_summary(&status_modified);
106 display_detailed_status(&status_modified);
107 println!();
108
109 println!("=== Demonstrating All Status Query Methods ===\n");
110
111 // Stage one of the modified files to show mixed states
112 repo.add(&["untracked1.txt"])?;
113 println!("Staged untracked1.txt (now shows as Added)");
114
115 let status_mixed = repo.status()?;
116 println!("\nMixed status demonstration:");
117 display_status_summary(&status_mixed);
118
119 // Demonstrate different query methods
120 println!("\nUsing different status query methods:");
121
122 println!(" All files ({} total):", status_mixed.entries.len());
123 for entry in &status_mixed.entries {
124 println!(
125 " Index {:?}, Worktree {:?}: {}",
126 entry.index_status,
127 entry.worktree_status,
128 entry.path.display()
129 );
130 }
131
132 // Query by specific status
133 let unstaged_files: Vec<_> = status_mixed.unstaged_files().collect();
134 if !unstaged_files.is_empty() {
135 println!("\n Unstaged files ({}):", unstaged_files.len());
136 for entry in &unstaged_files {
137 println!(" - {}", entry.path.display());
138 }
139 }
140
141 let untracked_files: Vec<_> = status_mixed.untracked_entries().collect();
142 if !untracked_files.is_empty() {
143 println!("\n Untracked files ({}):", untracked_files.len());
144 for entry in &untracked_files {
145 println!(" - {}", entry.path.display());
146 }
147 }
148
149 // Query by IndexStatus enum
150 let added_files: Vec<_> = status_mixed
151 .files_with_index_status(IndexStatus::Added)
152 .collect();
153 if !added_files.is_empty() {
154 println!("\n Added files ({}):", added_files.len());
155 for entry in &added_files {
156 println!(" - {}", entry.path.display());
157 }
158 }
159
160 println!();
161
162 println!("=== File Status Filtering Examples ===\n");
163
164 // Demonstrate filtering capabilities
165 println!("Filtering examples:");
166
167 // Count files by status
168 let mut index_status_counts = std::collections::HashMap::new();
169 let mut worktree_status_counts = std::collections::HashMap::new();
170
171 for entry in &status_mixed.entries {
172 if !matches!(entry.index_status, IndexStatus::Clean) {
173 *index_status_counts
174 .entry(format!("{:?}", entry.index_status))
175 .or_insert(0) += 1;
176 }
177 if !matches!(entry.worktree_status, WorktreeStatus::Clean) {
178 *worktree_status_counts
179 .entry(format!("{:?}", entry.worktree_status))
180 .or_insert(0) += 1;
181 }
182 }
183
184 println!(" Index status counts:");
185 for (status, count) in &index_status_counts {
186 println!(" {}: {} files", status, count);
187 }
188
189 println!(" Worktree status counts:");
190 for (status, count) in &worktree_status_counts {
191 println!(" {}: {} files", status, count);
192 }
193
194 // Filter for specific patterns
195 let txt_files: Vec<_> = status_mixed
196 .entries
197 .iter()
198 .filter(|entry| entry.path.to_string_lossy().ends_with(".txt"))
199 .collect();
200
201 if !txt_files.is_empty() {
202 println!("\n .txt files:");
203 for entry in txt_files {
204 println!(
205 " Index {:?}, Worktree {:?}: {}",
206 entry.index_status,
207 entry.worktree_status,
208 entry.path.display()
209 );
210 }
211 }
212
213 println!();
214
215 println!("=== Repository State Checking ===\n");
216
217 println!("Repository state summary:");
218 println!(" Total files tracked: {}", status_mixed.entries.len());
219 println!(" Is clean: {}", status_mixed.is_clean());
220 println!(" Has changes: {}", status_mixed.has_changes());
221
222 if status_mixed.has_changes() {
223 println!(" Repository needs attention!");
224
225 let unstaged_count = status_mixed.unstaged_files().count();
226 if unstaged_count > 0 {
227 println!(" - {} files need to be staged", unstaged_count);
228 }
229
230 let untracked_count = status_mixed.untracked_entries().count();
231 if untracked_count > 0 {
232 println!(" - {} untracked files to consider", untracked_count);
233 }
234
235 let staged_count = status_mixed.staged_files().count();
236 if staged_count > 0 {
237 println!(" - {} files ready to commit", staged_count);
238 }
239 }
240
241 // Clean up
242 println!("\nCleaning up example repository...");
243 fs::remove_dir_all(&repo_path)?;
244 println!("Status checking example completed!");
245
246 Ok(())
247}
Sourcepub fn files_with_worktree_status(
&self,
status: WorktreeStatus,
) -> impl Iterator<Item = &FileEntry> + '_
pub fn files_with_worktree_status( &self, status: WorktreeStatus, ) -> impl Iterator<Item = &FileEntry> + '_
Get files with specific worktree status
Trait Implementations§
impl StructuralPartialEq for GitStatus
Auto Trait Implementations§
impl Freeze for GitStatus
impl RefUnwindSafe for GitStatus
impl Send for GitStatus
impl Sync for GitStatus
impl Unpin for GitStatus
impl UnwindSafe for GitStatus
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more