pub struct CommitLog { /* private fields */ }
Implementations§
Source§impl CommitLog
impl CommitLog
Sourcepub fn iter(&self) -> impl Iterator<Item = &Commit>
pub fn iter(&self) -> impl Iterator<Item = &Commit>
Get an iterator over all commits
Examples found in repository?
examples/merge_operations.rs (line 146)
96fn demonstrate_no_fast_forward_merge(repo: &Repository, temp_dir: &std::path::Path) -> Result<()> {
97 println!("\n--- Demonstrating No-Fast-Forward Merge ---\n");
98
99 // Add a commit to master to prevent fast-forward
100 println!("1. Adding commit to master...");
101 let readme_path = temp_dir.join("README.md");
102 fs::write(
103 &readme_path,
104 "# Project\n\nInitial content\n\n## Updates\nAdded documentation",
105 )?;
106 repo.add(&["README.md"])?;
107 let master_commit = repo.commit("Update documentation")?;
108 println!(" Master commit: {}", master_commit);
109
110 // Create another feature branch
111 println!("\n2. Creating another feature branch...");
112 repo.checkout_new("feature/no-ff", None)?;
113
114 let config_path = temp_dir.join("config.yaml");
115 fs::write(&config_path, "app:\n name: example\n version: 1.0")?;
116 repo.add(&["config.yaml"])?;
117 let config_commit = repo.commit("Add configuration file")?;
118 println!(" Config commit: {}", config_commit);
119
120 // Switch back to master
121 println!("\n3. Switching back to master...");
122 let branches = repo.branches()?;
123 let master_branch = branches.find("master").unwrap();
124 repo.checkout(master_branch)?;
125
126 // Perform no-fast-forward merge
127 println!("\n4. Performing no-fast-forward merge...");
128 let options = MergeOptions::new()
129 .with_fast_forward(FastForwardMode::Never)
130 .with_message("Merge feature/no-ff into master".to_string());
131
132 let merge_status = repo.merge_with_options("feature/no-ff", options)?;
133
134 match merge_status {
135 MergeStatus::Success(hash) => {
136 println!(" ✓ Merge commit created!");
137 println!(" Merge commit: {}", hash);
138 println!(" Created explicit merge commit preserving branch history");
139 }
140 _ => println!(" Unexpected merge result: {:?}", merge_status),
141 }
142
143 // Show the commit history
144 println!("\n5. Recent commit history:");
145 let commits = repo.recent_commits(3)?;
146 for (i, commit) in commits.iter().enumerate() {
147 println!(
148 " {}: {} - {}",
149 i + 1,
150 commit.hash.short(),
151 commit.message.subject
152 );
153 }
154
155 Ok(())
156}
157
158fn demonstrate_merge_conflicts(repo: &Repository, temp_dir: &std::path::Path) -> Result<()> {
159 println!("\n--- Demonstrating Merge Conflicts ---\n");
160
161 // Create conflicting branch
162 println!("1. Creating branch with conflicting changes...");
163 repo.checkout_new("feature/conflict", None)?;
164
165 // Modify the same file differently
166 let readme_path = temp_dir.join("README.md");
167 fs::write(
168 &readme_path,
169 "# Project\n\nFeature branch changes\n\n## Updates\nAdded documentation",
170 )?;
171 repo.add(&["README.md"])?;
172 let feature_commit = repo.commit("Update README from feature branch")?;
173 println!(" Feature commit: {}", feature_commit);
174
175 // Switch back to master and make conflicting change
176 println!("\n2. Making conflicting change on master...");
177 let branches = repo.branches()?;
178 let master_branch = branches.find("master").unwrap();
179 repo.checkout(master_branch)?;
180
181 fs::write(
182 &readme_path,
183 "# Project\n\nMaster branch changes\n\n## Updates\nAdded documentation",
184 )?;
185 repo.add(&["README.md"])?;
186 let master_conflict_commit = repo.commit("Update README from master")?;
187 println!(" Master commit: {}", master_conflict_commit);
188
189 // Attempt merge (will have conflicts)
190 println!("\n3. Attempting merge (will have conflicts)...");
191 let merge_status = repo.merge("feature/conflict")?;
192
193 match merge_status {
194 MergeStatus::Conflicts(files) => {
195 println!(" ⚠️ Merge conflicts detected!");
196 println!(" Conflicted files:");
197 for file in &files {
198 println!(" - {}", file.display());
199 }
200
201 // Check merge in progress
202 if repo.merge_in_progress()? {
203 println!(" ✓ Merge in progress status detected");
204 }
205
206 // Show conflict markers in file
207 println!("\n4. Conflict markers in README.md:");
208 let content = fs::read_to_string(&readme_path)?;
209 for (i, line) in content.lines().enumerate() {
210 if line.starts_with("<<<<<<< ")
211 || line.starts_with("======= ")
212 || line.starts_with(">>>>>>> ")
213 {
214 println!(" {}: {} <-- conflict marker", i + 1, line);
215 } else {
216 println!(" {}: {}", i + 1, line);
217 }
218 }
219
220 // Abort the merge
221 println!("\n5. Aborting merge...");
222 repo.abort_merge()?;
223 println!(" ✓ Merge aborted successfully");
224
225 // Verify merge is no longer in progress
226 if !repo.merge_in_progress()? {
227 println!(" ✓ Repository is back to clean state");
228 }
229 }
230 _ => println!(" Unexpected merge result: {:?}", merge_status),
231 }
232
233 Ok(())
234}
235
236fn demonstrate_merge_status_and_abort(repo: &Repository, temp_dir: &std::path::Path) -> Result<()> {
237 println!("\n--- Demonstrating Merge Status and Options ---\n");
238
239 // Create a simple feature branch
240 println!("1. Creating simple feature branch...");
241 repo.checkout_new("feature/simple", None)?;
242
243 let simple_path = temp_dir.join("simple.txt");
244 fs::write(&simple_path, "Simple feature content")?;
245 repo.add(&["simple.txt"])?;
246 repo.commit("Add simple feature")?;
247
248 // Switch back to master
249 let branches = repo.branches()?;
250 let master_branch = branches.find("master").unwrap();
251 repo.checkout(master_branch)?;
252
253 // Test merge with different options
254 println!("\n2. Testing merge with custom options...");
255 let options = MergeOptions::new()
256 .with_fast_forward(FastForwardMode::Auto)
257 .with_message("Integrate simple feature".to_string());
258
259 let merge_status = repo.merge_with_options("feature/simple", options)?;
260
261 match merge_status {
262 MergeStatus::FastForward(hash) => {
263 println!(" ✓ Fast-forward merge completed: {}", hash);
264 }
265 MergeStatus::Success(hash) => {
266 println!(" ✓ Merge commit created: {}", hash);
267 }
268 MergeStatus::UpToDate => {
269 println!(" ✓ Already up to date");
270 }
271 MergeStatus::Conflicts(_) => {
272 println!(" ⚠️ Unexpected conflicts");
273 }
274 }
275
276 // Show final repository state
277 println!("\n3. Final repository state:");
278 let status = repo.status()?;
279 println!(
280 " Working directory clean: {}",
281 status.staged_files().count() == 0 && status.unstaged_files().count() == 0
282 );
283
284 let commits = repo.recent_commits(5)?;
285 println!(" Recent commits:");
286 for (i, commit) in commits.iter().enumerate() {
287 println!(
288 " {}: {} - {}",
289 i + 1,
290 commit.hash.short(),
291 commit.message.subject
292 );
293 }
294
295 Ok(())
296}
More examples
examples/commit_history.rs (line 86)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Get commits by a specific author
Sourcepub fn since(&self, date: DateTime<Utc>) -> impl Iterator<Item = &Commit>
pub fn since(&self, date: DateTime<Utc>) -> impl Iterator<Item = &Commit>
Get commits since a specific date
Examples found in repository?
examples/commit_history.rs (line 113)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn until(&self, date: DateTime<Utc>) -> impl Iterator<Item = &Commit>
pub fn until(&self, date: DateTime<Utc>) -> impl Iterator<Item = &Commit>
Get commits until a specific date
Sourcepub fn with_message_containing(
&self,
text: &str,
) -> impl Iterator<Item = &Commit>
pub fn with_message_containing( &self, text: &str, ) -> impl Iterator<Item = &Commit>
Get commits with message containing text
Examples found in repository?
examples/commit_history.rs (line 105)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn merges_only(&self) -> impl Iterator<Item = &Commit>
pub fn merges_only(&self) -> impl Iterator<Item = &Commit>
Get only merge commits
Examples found in repository?
examples/commit_history.rs (line 166)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn no_merges(&self) -> impl Iterator<Item = &Commit>
pub fn no_merges(&self) -> impl Iterator<Item = &Commit>
Get commits excluding merges
Examples found in repository?
examples/commit_history.rs (line 167)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn find_by_hash(&self, hash: &Hash) -> Option<&Commit>
pub fn find_by_hash(&self, hash: &Hash) -> Option<&Commit>
Find commit by full hash
Examples found in repository?
examples/commit_history.rs (line 194)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn find_by_short_hash(&self, short: &str) -> Option<&Commit>
pub fn find_by_short_hash(&self, short: &str) -> Option<&Commit>
Find commit by short hash
Examples found in repository?
examples/commit_history.rs (line 199)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Get the count of commits
Examples found in repository?
examples/commit_history.rs (line 83)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn first(&self) -> Option<&Commit>
pub fn first(&self) -> Option<&Commit>
Get the first (most recent) commit
Examples found in repository?
examples/commit_history.rs (line 174)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Sourcepub fn last(&self) -> Option<&Commit>
pub fn last(&self) -> Option<&Commit>
Get the last (oldest) commit
Examples found in repository?
examples/commit_history.rs (line 182)
5fn main() -> Result<()> {
6 let test_path = env::temp_dir().join("rustic_git_commit_history_example");
7
8 // Clean up if exists
9 if test_path.exists() {
10 fs::remove_dir_all(&test_path).unwrap();
11 }
12
13 // Create a test repository
14 let repo = Repository::init(&test_path, false)?;
15 println!("Created repository at: {}", test_path.display());
16
17 // Create several commits to build history
18 println!("\n=== Building Commit History ===");
19
20 // First commit
21 fs::write(
22 test_path.join("README.md"),
23 "# Commit History Demo\n\nA demonstration of rustic-git log functionality.",
24 )
25 .unwrap();
26 repo.add(&["README.md"])?;
27 let commit1 = repo.commit("Initial commit - add README")?;
28 println!("Created commit 1: {} - Initial commit", commit1.short());
29
30 // Second commit
31 fs::create_dir_all(test_path.join("src")).unwrap();
32 fs::write(
33 test_path.join("src/main.rs"),
34 "fn main() {\n println!(\"Hello, world!\");\n}",
35 )
36 .unwrap();
37 repo.add(&["src/main.rs"])?;
38 let commit2 = repo.commit("Add main.rs with Hello World")?;
39 println!("Created commit 2: {} - Add main.rs", commit2.short());
40
41 // Third commit
42 fs::write(
43 test_path.join("src/lib.rs"),
44 "pub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}",
45 )
46 .unwrap();
47 repo.add(&["src/lib.rs"])?;
48 let commit3 = repo.commit("Add library module with greet function")?;
49 println!("Created commit 3: {} - Add lib.rs", commit3.short());
50
51 // Fourth commit
52 fs::write(
53 test_path.join("Cargo.toml"),
54 "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
55 )
56 .unwrap();
57 repo.add(&["Cargo.toml"])?;
58 let commit4 = repo.commit("Add Cargo.toml configuration")?;
59 println!("Created commit 4: {} - Add Cargo.toml", commit4.short());
60
61 // Fifth commit - bug fix
62 fs::write(
63 test_path.join("src/main.rs"),
64 "fn main() {\n println!(\"Hello, rustic-git!\");\n}",
65 )
66 .unwrap();
67 repo.add(&["src/main.rs"])?;
68 let commit5 = repo.commit("Fix greeting message in main")?;
69 println!("Created commit 5: {} - Fix greeting", commit5.short());
70
71 // Sixth commit - documentation
72 fs::write(test_path.join("README.md"), "# Commit History Demo\n\nA demonstration of rustic-git log functionality.\n\n## Features\n\n- Greeting functionality\n- Command line interface\n").unwrap();
73 repo.add(&["README.md"])?;
74 let commit6 = repo.commit("Update README with features section")?;
75 println!("Created commit 6: {} - Update README", commit6.short());
76
77 println!("Built commit history with 6 commits");
78
79 // Basic log operations
80 println!("\n=== Basic Log Operations ===");
81
82 let all_commits = repo.log()?;
83 println!("Total commits in repository: {}", all_commits.len());
84
85 println!("\nAll commits (most recent first):");
86 for (i, commit) in all_commits.iter().enumerate() {
87 println!(" {}. {}", i + 1, commit);
88 }
89
90 // Recent commits
91 println!("\n=== Recent Commits ===");
92 let recent = repo.recent_commits(3)?;
93 println!("Last 3 commits:");
94 for commit in recent.iter() {
95 println!(" {} - {}", commit.hash.short(), commit.message.subject);
96 if let Some(body) = &commit.message.body {
97 println!(" Body: {}", body);
98 }
99 }
100
101 // Advanced filtering with LogOptions
102 println!("\n=== Advanced Filtering ===");
103
104 // Filter by message content
105 let fix_commits = all_commits.with_message_containing("fix");
106 println!("Commits with 'fix' in message:");
107 for commit in fix_commits {
108 println!(" {} - {}", commit.hash.short(), commit.message.subject);
109 }
110
111 // Filter by date (recent commits)
112 let now = Utc::now();
113 let recent_commits = all_commits.since(now - Duration::minutes(5));
114 println!("\nCommits from last 5 minutes: {}", recent_commits.count());
115
116 // Using LogOptions for advanced queries
117 println!("\n=== LogOptions Advanced Queries ===");
118
119 // Get commits with grep
120 let opts = LogOptions::new().max_count(10).grep("README".to_string());
121 let readme_commits = repo.log_with_options(&opts)?;
122 println!("Commits mentioning 'README': {}", readme_commits.len());
123 for commit in readme_commits.iter() {
124 println!(" {} - {}", commit.hash.short(), commit.message.subject);
125 }
126
127 // Get commits affecting specific paths
128 println!("\n=== Path-Specific History ===");
129 let src_commits = repo.log_for_paths(&["src/"])?;
130 println!("Commits affecting src/ directory: {}", src_commits.len());
131 for commit in src_commits.iter() {
132 println!(" {} - {}", commit.hash.short(), commit.message.subject);
133 }
134
135 // Show detailed commit information
136 println!("\n=== Detailed Commit Information ===");
137
138 let commit_details = repo.show_commit(&commit3)?;
139 println!("Detailed info for commit {}:", commit3.short());
140 println!(" Author: {}", commit_details.commit.author);
141 println!(" Committer: {}", commit_details.commit.committer);
142 println!(
143 " Timestamp: {}",
144 commit_details
145 .commit
146 .timestamp
147 .format("%Y-%m-%d %H:%M:%S UTC")
148 );
149 println!(" Message: {}", commit_details.commit.message.subject);
150 println!(" Parents: {}", commit_details.commit.parents.len());
151 for parent in commit_details.commit.parents.iter() {
152 println!(" - {}", parent.short());
153 }
154 println!(" Files changed: {}", commit_details.files_changed.len());
155 for file in &commit_details.files_changed {
156 println!(" - {}", file.display());
157 }
158 println!(
159 " Changes: +{} -{}",
160 commit_details.insertions, commit_details.deletions
161 );
162
163 // Commit analysis
164 println!("\n=== Commit Analysis ===");
165
166 let merge_commits: Vec<_> = all_commits.merges_only().collect();
167 let regular_commits: Vec<_> = all_commits.no_merges().collect();
168
169 println!("Repository statistics:");
170 println!(" Total commits: {}", all_commits.len());
171 println!(" Merge commits: {}", merge_commits.len());
172 println!(" Regular commits: {}", regular_commits.len());
173
174 if let Some(first_commit) = all_commits.first() {
175 println!(
176 " Most recent: {} ({})",
177 first_commit.hash.short(),
178 first_commit.message.subject
179 );
180 }
181
182 if let Some(last_commit) = all_commits.last() {
183 println!(
184 " Oldest: {} ({})",
185 last_commit.hash.short(),
186 last_commit.message.subject
187 );
188 }
189
190 // Search operations
191 println!("\n=== Search Operations ===");
192
193 // Find by hash
194 if let Some(found) = all_commits.find_by_hash(&commit2) {
195 println!("Found commit by full hash: {}", found.message.subject);
196 }
197
198 // Find by short hash
199 if let Some(found) = all_commits.find_by_short_hash(commit4.short()) {
200 println!("Found commit by short hash: {}", found.message.subject);
201 }
202
203 // Commit range operations
204 println!("\n=== Commit Range Operations ===");
205
206 let range_commits = repo.log_range(&commit2, &commit5)?;
207 println!(
208 "Commits in range {}..{}: {}",
209 commit2.short(),
210 commit5.short(),
211 range_commits.len()
212 );
213 for commit in range_commits.iter() {
214 println!(" {} - {}", commit.hash.short(), commit.message.subject);
215 }
216
217 // Advanced LogOptions demonstration
218 println!("\n=== Advanced LogOptions Usage ===");
219
220 let advanced_opts = LogOptions::new()
221 .max_count(5)
222 .no_merges(true)
223 .paths(vec!["src/main.rs".into()]);
224
225 let filtered_commits = repo.log_with_options(&advanced_opts)?;
226 println!(
227 "Non-merge commits affecting src/main.rs (max 5): {}",
228 filtered_commits.len()
229 );
230 for commit in filtered_commits.iter() {
231 println!(" {} - {}", commit.hash.short(), commit.message.subject);
232 }
233
234 // Commit message analysis
235 println!("\n=== Commit Message Analysis ===");
236
237 let total_commits = all_commits.len();
238 let commits_with_body: Vec<_> = all_commits
239 .iter()
240 .filter(|c| c.message.body.is_some())
241 .collect();
242
243 println!("Message statistics:");
244 println!(" Total commits: {}", total_commits);
245 println!(" Commits with body text: {}", commits_with_body.len());
246 println!(
247 " Commits with subject only: {}",
248 total_commits - commits_with_body.len()
249 );
250
251 // Display commit types by analyzing subjects
252 let fix_count = all_commits
253 .iter()
254 .filter(|c| c.message.subject.to_lowercase().contains("fix"))
255 .count();
256 let add_count = all_commits
257 .iter()
258 .filter(|c| c.message.subject.to_lowercase().contains("add"))
259 .count();
260 let update_count = all_commits
261 .iter()
262 .filter(|c| c.message.subject.to_lowercase().contains("update"))
263 .count();
264
265 println!(" Commit types:");
266 println!(" - Fix commits: {}", fix_count);
267 println!(" - Add commits: {}", add_count);
268 println!(" - Update commits: {}", update_count);
269 println!(
270 " - Other commits: {}",
271 total_commits - fix_count - add_count - update_count
272 );
273
274 // Timeline view
275 println!("\n=== Timeline View ===");
276
277 println!("Commit timeline (oldest to newest):");
278 let commits: Vec<_> = all_commits.iter().collect();
279 for commit in commits.iter().rev() {
280 let commit_type = if commit.is_merge() { "MERGE" } else { "COMMIT" };
281 println!(
282 " {} {} {} - {}",
283 commit.timestamp.format("%H:%M:%S"),
284 commit_type,
285 commit.hash.short(),
286 commit.message.subject
287 );
288 }
289
290 // Summary
291 println!("\n=== Summary ===");
292
293 println!("Commit history demonstration completed!");
294 println!(" Repository: {}", test_path.display());
295 println!(" Total commits analyzed: {}", all_commits.len());
296 println!(" Hash examples:");
297 for commit in all_commits.iter().take(3) {
298 println!(" - Full: {}", commit.hash.as_str());
299 println!(" Short: {}", commit.hash.short());
300 }
301
302 // Clean up
303 fs::remove_dir_all(&test_path).unwrap();
304 println!("\nCleaned up test repository");
305
306 Ok(())
307}
Trait Implementations§
impl StructuralPartialEq for CommitLog
Auto Trait Implementations§
impl Freeze for CommitLog
impl RefUnwindSafe for CommitLog
impl Send for CommitLog
impl Sync for CommitLog
impl Unpin for CommitLog
impl UnwindSafe for CommitLog
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