pub struct RepoConfig<'a> { /* private fields */ }
Expand description
Repository configuration manager
Provides methods for getting and setting git configuration values for a specific repository.
Implementations§
Source§impl<'a> RepoConfig<'a>
impl<'a> RepoConfig<'a>
pub const USER_NAME_KEY: &'static str = "user.name"
pub const USER_EMAIL_KEY: &'static str = "user.email"
Sourcepub fn set_user(&self, name: &str, email: &str) -> Result<()>
pub fn set_user(&self, name: &str, email: &str) -> Result<()>
Configure git user name and email for this repository
This is a convenience method that sets both user.name and user.email configuration values.
§Arguments
name
- The user’s full nameemail
- The user’s email address
§Example
use rustic_git::Repository;
use std::{env, fs};
let test_path = env::temp_dir().join("config_set_user_test");
if test_path.exists() {
fs::remove_dir_all(&test_path).unwrap();
}
let repo = Repository::init(&test_path, false)?;
repo.config().set_user("John Doe", "john@example.com")?;
// Clean up
fs::remove_dir_all(&test_path).unwrap();
Examples found in repository?
examples/config_operations.rs (line 36)
14fn main() -> Result<()> {
15 println!("Rustic Git - Repository Configuration Operations Example\n");
16
17 // Use a temporary directory for this example
18 let repo_path = env::temp_dir().join("rustic_git_config_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 println!("Initializing new repository at: {}", repo_path.display());
26
27 // Initialize a new repository
28 let repo = Repository::init(&repo_path, false)?;
29
30 // ==================== USER CONFIGURATION ====================
31
32 println!("\n[CONFIG] Configuring git user settings...");
33
34 // Set user configuration (convenience method)
35 repo.config()
36 .set_user("Alice Developer", "alice@example.com")?;
37 println!("Set user configuration");
38
39 // Verify user configuration
40 let (name, email) = repo.config().get_user()?;
41 println!("Current user: {} <{}>", name, email);
42
43 // ==================== GENERAL CONFIGURATION ====================
44
45 println!("\n[CONFIG] Setting repository configuration values...");
46
47 // Set various git configuration values
48 repo.config().set("core.autocrlf", "false")?;
49 repo.config().set("core.ignorecase", "true")?;
50 repo.config().set("pull.rebase", "true")?;
51 repo.config().set("push.default", "simple")?;
52 repo.config().set("branch.autosetupmerge", "always")?;
53
54 println!("Set core configuration values");
55
56 // Get and display configuration values
57 println!("\n[CONFIG] Current repository configuration:");
58
59 let configs = [
60 "core.autocrlf",
61 "core.ignorecase",
62 "pull.rebase",
63 "push.default",
64 "branch.autosetupmerge",
65 ];
66
67 for config_key in &configs {
68 match repo.config().get(config_key) {
69 Ok(value) => println!(" {} = {}", config_key, value),
70 Err(_) => println!(" {} = <not set>", config_key),
71 }
72 }
73
74 // ==================== CONFIGURATION WITH COMMITS ====================
75
76 println!("\n[COMMIT] Testing configuration with commit operations...");
77
78 // Create a test file
79 let test_file_path = repo_path.join("test.txt");
80 fs::write(
81 &test_file_path,
82 "Hello from rustic-git configuration example!",
83 )?;
84 println!("Created test file: test.txt");
85
86 // Stage the file
87 repo.add(&["test.txt"])?;
88 println!("Staged test.txt");
89
90 // Create a commit (this will use our configured user)
91 let commit_hash = repo.commit("Add test file with configuration example")?;
92 println!("Created commit: {}", commit_hash.short());
93
94 // ==================== CONFIGURATION MODIFICATION ====================
95
96 println!("\n[UPDATE] Modifying configuration values...");
97
98 // Change some configuration values
99 repo.config().set("core.autocrlf", "true")?;
100 repo.config()
101 .set("user.email", "alice.developer@newcompany.com")?;
102
103 println!("Updated configuration values");
104
105 // Display updated values
106 let autocrlf = repo.config().get("core.autocrlf")?;
107 let (updated_name, updated_email) = repo.config().get_user()?;
108
109 println!("Updated configuration:");
110 println!(" core.autocrlf = {}", autocrlf);
111 println!(" user: {} <{}>", updated_name, updated_email);
112
113 // ==================== CONFIGURATION REMOVAL ====================
114
115 println!("\n[REMOVE] Removing configuration values...");
116
117 // Remove a configuration value
118 repo.config().unset("branch.autosetupmerge")?;
119 println!("Removed branch.autosetupmerge");
120
121 // Try to get the removed value (should fail)
122 match repo.config().get("branch.autosetupmerge") {
123 Ok(value) => println!("Unexpected: branch.autosetupmerge = {}", value),
124 Err(_) => println!("Confirmed: branch.autosetupmerge is not set"),
125 }
126
127 // ==================== ADVANCED CONFIGURATION ====================
128
129 println!("\n[ADVANCED] Setting advanced configuration...");
130
131 // Set some advanced git configuration
132 repo.config().set("diff.tool", "vimdiff")?;
133 repo.config().set("merge.tool", "vimdiff")?;
134 repo.config().set("alias.st", "status")?;
135 repo.config().set("alias.co", "checkout")?;
136 repo.config().set("alias.br", "branch")?;
137 repo.config().set("alias.ci", "commit")?;
138
139 println!("Set advanced configuration (diff/merge tools and aliases)");
140
141 // Display all custom configuration
142 println!("\n[SUMMARY] Complete repository configuration summary:");
143
144 let all_configs = [
145 ("User", vec![("user.name", ""), ("user.email", "")]),
146 ("Core", vec![("core.autocrlf", ""), ("core.ignorecase", "")]),
147 ("Workflow", vec![("pull.rebase", ""), ("push.default", "")]),
148 ("Tools", vec![("diff.tool", ""), ("merge.tool", "")]),
149 (
150 "Aliases",
151 vec![
152 ("alias.st", ""),
153 ("alias.co", ""),
154 ("alias.br", ""),
155 ("alias.ci", ""),
156 ],
157 ),
158 ];
159
160 for (category, configs) in &all_configs {
161 println!("\n {}:", category);
162 for (key, _) in configs {
163 match repo.config().get(key) {
164 Ok(value) => println!(" {} = {}", key, value),
165 Err(_) => println!(" {} = <not set>", key),
166 }
167 }
168 }
169
170 // ==================== PRACTICAL EXAMPLE ====================
171
172 println!("\n[TEAM] Practical example: Setting up repository for a team...");
173
174 // Configure repository for team development
175 repo.config().set("user.name", "Team Member")?;
176 repo.config().set("user.email", "team@company.com")?;
177 repo.config().set("core.autocrlf", "input")?;
178 repo.config().set("core.safecrlf", "true")?;
179 repo.config().set("pull.rebase", "true")?;
180 repo.config().set("push.default", "current")?;
181 repo.config().set("init.defaultBranch", "main")?;
182
183 println!("Configured repository for team development");
184
185 // Create another commit with the team configuration
186 fs::write(
187 repo_path.join("team.md"),
188 "# Team Development\n\nThis repository is configured for team development.",
189 )?;
190 repo.add(&["team.md"])?;
191 let team_commit = repo.commit("Add team development documentation")?;
192
193 println!("Created team commit: {}", team_commit.short());
194
195 // Final verification
196 let (final_name, final_email) = repo.config().get_user()?;
197 println!("\n[FINAL] Final repository configuration:");
198 println!(" User: {} <{}>", final_name, final_email);
199 println!(" Repository configured for team development workflow");
200
201 // ==================== CLEANUP ====================
202
203 println!("\n[CLEANUP] Cleaning up...");
204 fs::remove_dir_all(&repo_path).expect("Failed to clean up example");
205 println!("Example completed successfully!");
206
207 Ok(())
208}
More examples
examples/diff_operations.rs (line 20)
4fn main() -> rustic_git::Result<()> {
5 println!("Rustic Git - Diff Operations Example\n");
6
7 let repo_path = env::temp_dir().join("rustic_git_diff_example");
8 // Clean up any previous run
9 if repo_path.exists() {
10 fs::remove_dir_all(&repo_path).ok();
11 }
12 println!("Working in temporary directory: {}", repo_path.display());
13
14 // Initialize repository
15 let repo = Repository::init(&repo_path, false)?;
16 println!("Repository initialized successfully\n");
17
18 // Configure git user for commits
19 let config = repo.config();
20 config.set_user("Test User", "test@example.com")?;
21
22 println!("=== Creating Initial Files ===");
23
24 // Create initial files
25 let readme_path = repo_path.join("README.md");
26 let src_dir = repo_path.join("src");
27 fs::create_dir_all(&src_dir).unwrap();
28 let main_path = src_dir.join("main.rs");
29 let lib_path = src_dir.join("lib.rs");
30
31 fs::write(
32 &readme_path,
33 "# Test Project\n\nA sample project for testing diff operations.\n",
34 )
35 .unwrap();
36 fs::write(
37 &main_path,
38 "fn main() {\n println!(\"Hello, world!\");\n}\n",
39 )
40 .unwrap();
41 fs::write(
42 &lib_path,
43 "pub fn add(a: i32, b: i32) -> i32 {\n a + b\n}\n",
44 )
45 .unwrap();
46
47 println!("Created initial files: README.md, src/main.rs, src/lib.rs");
48
49 // Stage and commit initial files
50 repo.add_all()?;
51 let initial_commit = repo.commit("feat: initial commit with basic files")?;
52 println!("Initial commit: {}\n", initial_commit.short());
53
54 println!("=== Testing Different Diff Operations ===");
55
56 // Test 1: Diff with no changes (should be empty)
57 println!("1. Diff with no changes:");
58 let diff = repo.diff()?;
59 if diff.is_empty() {
60 println!(" ✓ No changes detected (as expected)");
61 } else {
62 println!(" ✗ Unexpected changes found");
63 }
64 println!();
65
66 // Test 2: Modify files and show unstaged changes
67 println!("2. Creating unstaged changes:");
68 fs::write(&readme_path, "# Test Project\n\nA sample project for testing diff operations.\n\n## Features\n- Git operations\n- Diff functionality\n").unwrap();
69 fs::write(&main_path, "fn main() {\n println!(\"Hello, world!\");\n println!(\"Testing diff operations!\");\n}\n").unwrap();
70
71 let diff = repo.diff()?;
72 println!(" Unstaged changes found:");
73 println!(" Files changed: {}", diff.len());
74 for file in diff.iter() {
75 println!(" - {} ({})", file.path.display(), file.status);
76 }
77 println!(" {}", diff.stats);
78 println!();
79
80 // Test 3: Stage some changes and show staged vs unstaged
81 println!("3. Staging README.md and checking staged diff:");
82 repo.add(&[&readme_path])?;
83
84 let staged_diff = repo.diff_staged()?;
85 println!(" Staged changes:");
86 for file in staged_diff.iter() {
87 println!(" - {} ({})", file.path.display(), file.status);
88 }
89 println!(" {}", staged_diff.stats);
90
91 let unstaged_diff = repo.diff()?;
92 println!(" Remaining unstaged changes:");
93 for file in unstaged_diff.iter() {
94 println!(" - {} ({})", file.path.display(), file.status);
95 }
96 println!(" {}", unstaged_diff.stats);
97 println!();
98
99 // Test 4: Diff with options
100 println!("4. Using diff options (name-only):");
101 let name_only_diff = repo.diff_with_options(&DiffOptions::new().name_only())?;
102 println!(" Modified files (name-only):");
103 for file in name_only_diff.iter() {
104 println!(" - {}", file.path.display());
105 }
106 println!();
107
108 // Test 5: Diff with file filtering
109 println!("5. Diff with path filtering (src/ only):");
110 let src_paths = vec![src_dir.clone()];
111 let filtered_diff = repo.diff_with_options(&DiffOptions::new().paths(src_paths))?;
112 println!(" Changes in src/ directory:");
113 for file in filtered_diff.iter() {
114 println!(" - {} ({})", file.path.display(), file.status);
115 }
116 println!();
117
118 // Stage remaining changes and commit
119 repo.add_all()?;
120 let second_commit = repo.commit("feat: add features section and improve main function")?;
121 println!("Second commit: {}", second_commit.short());
122
123 // Test 6: Diff between commits
124 println!("\n6. Diff between commits:");
125 let commit_diff = repo.diff_commits(&initial_commit, &second_commit)?;
126 println!(
127 " Changes from {} to {}:",
128 initial_commit.short(),
129 second_commit.short()
130 );
131 for file in commit_diff.iter() {
132 println!(
133 " - {} ({}) +{} -{}",
134 file.path.display(),
135 file.status,
136 file.additions,
137 file.deletions
138 );
139 }
140 println!(" {}", commit_diff.stats);
141 println!();
142
143 // Test 7: Add a new file and show it in diff
144 println!("7. Adding new file and checking diff:");
145 let test_path = repo_path.join("test.txt");
146 fs::write(
147 &test_path,
148 "This is a new test file.\nWith multiple lines.\n",
149 )
150 .unwrap();
151
152 let new_file_diff = repo.diff()?;
153 println!(" New file detected:");
154 for file in new_file_diff.iter() {
155 println!(" - {} ({})", file.path.display(), file.status);
156 }
157 println!();
158
159 // Test 8: Delete a file and show in diff
160 println!("8. Deleting file and checking diff:");
161 fs::remove_file(&lib_path).unwrap();
162
163 let deleted_file_diff = repo.diff()?;
164 println!(" Changes after file deletion:");
165 for file in deleted_file_diff.iter() {
166 println!(" - {} ({})", file.path.display(), file.status);
167 }
168 println!();
169
170 // Test 9: Diff with ignore whitespace options
171 println!("9. Testing whitespace options:");
172
173 // Add some whitespace changes
174 fs::write(&main_path, "fn main() {\n println!(\"Hello, world!\");\n println!(\"Testing diff operations!\"); \n}\n").unwrap();
175
176 let normal_diff = repo.diff()?;
177 let whitespace_diff = repo.diff_with_options(&DiffOptions::new().ignore_whitespace())?;
178
179 println!(" Normal diff shows {} files changed", normal_diff.len());
180 println!(
181 " Whitespace-ignoring diff shows {} files changed",
182 whitespace_diff.len()
183 );
184 println!();
185
186 // Test 10: Show diff with HEAD
187 println!("10. Diff with HEAD (all changes since last commit):");
188 let head_diff = repo.diff_head()?;
189 println!(" All changes since last commit:");
190 for file in head_diff.iter() {
191 println!(" - {} ({})", file.path.display(), file.status);
192 }
193 println!(" {}", head_diff.stats);
194 println!();
195
196 // Test 11: Different diff output formats
197 println!("11. Testing different output formats:");
198
199 let stat_diff = repo.diff_with_options(&DiffOptions::new().stat_only())?;
200 println!(" Stat format:");
201 println!(" {}", stat_diff);
202
203 let numstat_diff = repo.diff_with_options(&DiffOptions::new().numstat())?;
204 println!(" Numstat format - {} files changed", numstat_diff.len());
205 for file in numstat_diff.iter() {
206 println!(
207 " {} +{} -{}",
208 file.path.display(),
209 file.additions,
210 file.deletions
211 );
212 }
213 println!();
214
215 // Test 12: Filtering by file status
216 println!("12. Filtering files by status:");
217 let all_changes = repo.diff_head()?;
218
219 let added_files: Vec<_> = all_changes.files_with_status(DiffStatus::Added).collect();
220 let modified_files: Vec<_> = all_changes
221 .files_with_status(DiffStatus::Modified)
222 .collect();
223 let deleted_files: Vec<_> = all_changes.files_with_status(DiffStatus::Deleted).collect();
224
225 println!(" Added files: {}", added_files.len());
226 for file in added_files {
227 println!(" - {}", file.path.display());
228 }
229
230 println!(" Modified files: {}", modified_files.len());
231 for file in modified_files {
232 println!(" - {}", file.path.display());
233 }
234
235 println!(" Deleted files: {}", deleted_files.len());
236 for file in deleted_files {
237 println!(" - {}", file.path.display());
238 }
239 println!();
240
241 println!("=== Diff Operations Demo Complete ===");
242 println!("All diff operations completed successfully!");
243 println!("Summary of tested features:");
244 println!("✓ Basic diff operations (working dir vs index)");
245 println!("✓ Staged diff operations (index vs HEAD)");
246 println!("✓ Diff between specific commits");
247 println!("✓ Diff with various options (name-only, stat, numstat)");
248 println!("✓ Path filtering");
249 println!("✓ Whitespace handling options");
250 println!("✓ File status filtering");
251 println!("✓ Comprehensive diff statistics");
252
253 println!("\nCleaning up temporary repository...");
254 fs::remove_dir_all(&repo_path).ok();
255
256 Ok(())
257}
examples/tag_operations.rs (line 32)
16fn main() -> Result<()> {
17 println!("Rustic Git - Tag Operations Example\n");
18
19 // Use a temporary directory for this example
20 let repo_path = env::temp_dir().join("rustic_git_tag_example");
21
22 // Clean up any previous run
23 if repo_path.exists() {
24 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
25 }
26
27 println!("Initializing repository at: {}", repo_path.display());
28
29 // Initialize repository and configure user
30 let repo = Repository::init(&repo_path, false)?;
31 repo.config()
32 .set_user("Tag Demo User", "tags@example.com")?;
33
34 // Create some commits to tag
35 println!("\nCreating initial commits...");
36
37 // First commit
38 fs::write(
39 repo_path.join("README.md"),
40 "# Tag Demo Project\n\nDemonstrating Git tag operations.\n",
41 )?;
42 repo.add(&["README.md"])?;
43 let first_commit_hash = repo.commit("Initial commit: Add README")?;
44 println!("Created commit: {}", first_commit_hash.short());
45
46 // Second commit
47 fs::create_dir_all(repo_path.join("src"))?;
48 fs::write(
49 repo_path.join("src/main.rs"),
50 "fn main() {\n println!(\"Hello, tags!\");\n}\n",
51 )?;
52 repo.add(&["src/main.rs"])?;
53 let second_commit_hash = repo.commit("Add main.rs with hello world")?;
54 println!("Created commit: {}", second_commit_hash.short());
55
56 // Third commit
57 fs::write(
58 repo_path.join("src/lib.rs"),
59 "//! Tag demo library\n\npub fn greet(name: &str) -> String {\n format!(\"Hello, {}!\", name)\n}\n",
60 )?;
61 repo.add(&["src/lib.rs"])?;
62 let third_commit_hash = repo.commit("Add library with greet function")?;
63 println!("Created commit: {}", third_commit_hash.short());
64
65 // Demonstrate tag creation
66 println!("\n=== Creating Tags ===");
67
68 // Create lightweight tags
69 println!("\n1. Creating lightweight tags:");
70
71 let v0_1_0 = repo.create_tag("v0.1.0", Some(&first_commit_hash))?;
72 println!(
73 "Created lightweight tag: {} -> {} ({})",
74 v0_1_0.name,
75 v0_1_0.hash.short(),
76 v0_1_0.tag_type
77 );
78
79 let v0_2_0 = repo.create_tag("v0.2.0", Some(&second_commit_hash))?;
80 println!(
81 "Created lightweight tag: {} -> {} ({})",
82 v0_2_0.name,
83 v0_2_0.hash.short(),
84 v0_2_0.tag_type
85 );
86
87 // Create annotated tags
88 println!("\n2. Creating annotated tags:");
89
90 let options =
91 TagOptions::new().with_message("First stable release with basic functionality".to_string());
92 let v1_0_0 = repo.create_tag_with_options("v1.0.0", Some(&third_commit_hash), options)?;
93 println!(
94 "Created annotated tag: {} -> {} ({})",
95 v1_0_0.name,
96 v1_0_0.hash.short(),
97 v1_0_0.tag_type
98 );
99 if let Some(message) = &v1_0_0.message {
100 println!(" Message: {}", message);
101 }
102
103 // Tag current HEAD
104 let latest_options = TagOptions::new().with_message("Latest development version".to_string());
105 let latest_tag = repo.create_tag_with_options("latest", None, latest_options)?;
106 println!(
107 "Created annotated tag on HEAD: {} -> {} ({})",
108 latest_tag.name,
109 latest_tag.hash.short(),
110 latest_tag.tag_type
111 );
112
113 // Create some feature tags
114 println!("\n3. Creating feature and release candidate tags:");
115
116 let feature_options = TagOptions::new().with_message("Feature branch snapshot".to_string());
117 repo.create_tag_with_options("feature/demo", None, feature_options)?;
118
119 let rc_options = TagOptions::new().with_message("Release candidate for v1.1.0".to_string());
120 repo.create_tag_with_options("v1.1.0-rc1", None, rc_options)?;
121
122 // Create a couple more version tags
123 repo.create_tag("v0.3.0", None)?;
124 repo.create_tag("v0.9.0", None)?;
125
126 // Demonstrate tag listing and filtering
127 println!("\n=== Tag Listing and Filtering ===");
128
129 let tags = repo.tags()?;
130 println!("\nAll tags ({} total):", tags.len());
131 for tag in tags.iter() {
132 let type_marker = match tag.tag_type {
133 TagType::Lightweight => "L",
134 TagType::Annotated => "A",
135 };
136 println!(" [{}] {} -> {}", type_marker, tag.name, tag.hash.short());
137 if let Some(message) = &tag.message {
138 println!(" Message: {}", message.lines().next().unwrap_or(""));
139 }
140 }
141
142 // Filter by type
143 println!("\nLightweight tags ({} total):", tags.lightweight_count());
144 for tag in tags.lightweight() {
145 println!(" {} -> {}", tag.name, tag.hash.short());
146 }
147
148 println!("\nAnnotated tags ({} total):", tags.annotated_count());
149 for tag in tags.annotated() {
150 println!(" {} -> {}", tag.name, tag.hash.short());
151 if let Some(message) = &tag.message {
152 println!(" Message: {}", message.lines().next().unwrap_or(""));
153 }
154 }
155
156 // Search and filtering
157 println!("\n=== Tag Searching ===");
158
159 // Find specific tag
160 if let Some(tag) = tags.find("v1.0.0") {
161 println!("\nFound tag 'v1.0.0':");
162 println!(" Type: {}", tag.tag_type);
163 println!(" Hash: {}", tag.hash.short());
164 if let Some(message) = &tag.message {
165 println!(" Message: {}", message);
166 }
167 }
168
169 // Find version tags
170 let version_tags: Vec<_> = tags.find_containing("v").collect();
171 println!(
172 "\nVersion tags (containing 'v'): {} found",
173 version_tags.len()
174 );
175 for tag in &version_tags {
176 println!(" {}", tag.name);
177 }
178
179 // Find release candidates
180 let rc_tags: Vec<_> = tags.find_containing("rc").collect();
181 println!("\nRelease candidate tags: {} found", rc_tags.len());
182 for tag in &rc_tags {
183 println!(" {}", tag.name);
184 }
185
186 // Find tags for specific commit
187 let tags_for_third_commit: Vec<_> = tags.for_commit(&third_commit_hash).collect();
188 println!(
189 "\nTags pointing to commit {}: {} found",
190 third_commit_hash.short(),
191 tags_for_third_commit.len()
192 );
193 for tag in &tags_for_third_commit {
194 println!(" {}", tag.name);
195 }
196
197 // Demonstrate tag details
198 println!("\n=== Tag Details ===");
199
200 let detailed_tag = repo.show_tag("v1.0.0")?;
201 println!("\nDetailed information for 'v1.0.0':");
202 println!(" Name: {}", detailed_tag.name);
203 println!(" Type: {}", detailed_tag.tag_type);
204 println!(" Commit: {}", detailed_tag.hash);
205 println!(" Short hash: {}", detailed_tag.hash.short());
206
207 if let Some(message) = &detailed_tag.message {
208 println!(" Message: {}", message);
209 }
210
211 if let Some(tagger) = &detailed_tag.tagger {
212 println!(" Tagger: {}", tagger);
213 println!(
214 " Tagged at: {}",
215 tagger.timestamp.format("%Y-%m-%d %H:%M:%S UTC")
216 );
217 }
218
219 if let Some(timestamp) = &detailed_tag.timestamp {
220 println!(" Timestamp: {}", timestamp.format("%Y-%m-%d %H:%M:%S UTC"));
221 }
222
223 // Demonstrate tag operations
224 println!("\n=== Tag Operations ===");
225
226 // Create and force overwrite a tag
227 println!("\n1. Testing tag overwrite:");
228
229 // This should fail (tag already exists)
230 match repo.create_tag("latest", None) {
231 Ok(_) => println!(" ERROR: Should have failed to create existing tag"),
232 Err(e) => println!(" Expected error creating existing tag: {}", e),
233 }
234
235 // Force overwrite
236 let force_options = TagOptions::new()
237 .with_force()
238 .with_message("Forcefully updated latest tag".to_string());
239
240 match repo.create_tag_with_options("latest", None, force_options) {
241 Ok(tag) => println!(" Successfully force-created tag: {}", tag.name),
242 Err(e) => println!(" Error force-creating tag: {}", e),
243 }
244
245 // Tag deletion
246 println!("\n2. Testing tag deletion:");
247
248 // Create a temporary tag to delete
249 repo.create_tag("temp-tag", None)?;
250 println!(" Created temporary tag: temp-tag");
251
252 // Verify it exists
253 let tags_before = repo.tags()?;
254 let temp_exists_before = tags_before.find("temp-tag").is_some();
255 println!(" Temp tag exists before deletion: {}", temp_exists_before);
256
257 // Delete it
258 repo.delete_tag("temp-tag")?;
259 println!(" Deleted temp-tag");
260
261 // Verify it's gone
262 let tags_after = repo.tags()?;
263 let temp_exists_after = tags_after.find("temp-tag").is_some();
264 println!(" Temp tag exists after deletion: {}", temp_exists_after);
265
266 // Summary
267 println!("\n=== Summary ===");
268 let final_tags = repo.tags()?;
269 println!("\nFinal repository state:");
270 println!(" Total tags: {}", final_tags.len());
271 println!(" Lightweight tags: {}", final_tags.lightweight_count());
272 println!(" Annotated tags: {}", final_tags.annotated_count());
273
274 println!("\nTag creation options demonstrated:");
275 println!(" ✓ Lightweight tags (simple references)");
276 println!(" ✓ Annotated tags (with messages and metadata)");
277 println!(" ✓ Tags on specific commits");
278 println!(" ✓ Tags on current HEAD");
279 println!(" ✓ Force tag creation/overwrite");
280
281 println!("\nTag listing and filtering demonstrated:");
282 println!(" ✓ List all tags");
283 println!(" ✓ Filter by tag type (lightweight/annotated)");
284 println!(" ✓ Search by name patterns");
285 println!(" ✓ Find tags by commit hash");
286 println!(" ✓ Show detailed tag information");
287
288 println!("\nTag management demonstrated:");
289 println!(" ✓ Tag creation with options");
290 println!(" ✓ Tag deletion");
291 println!(" ✓ Error handling for duplicate tags");
292
293 // Clean up
294 println!("\nCleaning up example repository...");
295 fs::remove_dir_all(&repo_path)?;
296 println!("Tag operations example completed successfully!");
297
298 Ok(())
299}
examples/stash_operations.rs (line 33)
17fn main() -> Result<()> {
18 println!("Rustic Git - Stash Operations Example\n");
19
20 // Use a temporary directory for this example
21 let repo_path = env::temp_dir().join("rustic_git_stash_example");
22
23 // Clean up any previous run
24 if repo_path.exists() {
25 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
26 }
27
28 println!("Initializing repository at: {}", repo_path.display());
29
30 // Initialize repository and configure user
31 let repo = Repository::init(&repo_path, false)?;
32 repo.config()
33 .set_user("Stash Demo User", "stash@example.com")?;
34
35 // Create initial commit to have a base
36 println!("\nCreating initial commit...");
37 fs::write(
38 repo_path.join("README.md"),
39 "# Stash Demo Project\n\nDemonstrating Git stash operations.\n",
40 )?;
41 repo.add(&["README.md"])?;
42 let initial_commit = repo.commit("Initial commit: Add README")?;
43 println!("Created initial commit: {}", initial_commit.short());
44
45 // Create some work to stash
46 println!("\n=== Creating Work to Stash ===");
47
48 // Create tracked file modifications
49 fs::write(
50 repo_path.join("README.md"),
51 "# Stash Demo Project\n\nDemonstrating Git stash operations.\n\nAdded some new content!\n",
52 )?;
53
54 // Create new tracked files
55 fs::create_dir_all(repo_path.join("src"))?;
56 fs::write(
57 repo_path.join("src/main.rs"),
58 "fn main() {\n println!(\"Hello, stash!\");\n}\n",
59 )?;
60
61 // Create untracked files
62 fs::write(
63 repo_path.join("untracked.txt"),
64 "This file is not tracked by git\n",
65 )?;
66 fs::write(repo_path.join("temp.log"), "Temporary log file\n")?;
67
68 // Stage some changes
69 repo.add(&["src/main.rs"])?;
70
71 println!("Created various types of changes:");
72 println!(" - Modified tracked file (README.md)");
73 println!(" - Added new file and staged it (src/main.rs)");
74 println!(" - Created untracked files (untracked.txt, temp.log)");
75
76 // Check repository status before stashing
77 let status = repo.status()?;
78 println!("\nRepository status before stashing:");
79 println!(" Staged files: {}", status.staged_files().count());
80 println!(" Unstaged files: {}", status.unstaged_files().count());
81 println!(" Untracked files: {}", status.untracked_entries().count());
82
83 // Demonstrate stash creation
84 println!("\n=== Creating Stashes ===");
85
86 // 1. Simple stash save
87 println!("\n1. Creating simple stash:");
88 let simple_stash = repo.stash_save("WIP: working on main function")?;
89 println!("Created stash: {}", simple_stash);
90 println!(" Index: {}", simple_stash.index);
91 println!(" Branch: {}", simple_stash.branch);
92 println!(" Hash: {}", simple_stash.hash.short());
93
94 // Check status after stash
95 let status_after_stash = repo.status()?;
96 println!("\nStatus after simple stash:");
97 println!(
98 " Staged files: {}",
99 status_after_stash.staged_files().count()
100 );
101 println!(
102 " Unstaged files: {}",
103 status_after_stash.unstaged_files().count()
104 );
105 println!(
106 " Untracked files: {}",
107 status_after_stash.untracked_entries().count()
108 );
109
110 // 2. Make more changes and create stash with untracked files
111 println!("\n2. Creating stash with untracked files:");
112
113 // Modify file again
114 fs::write(
115 repo_path.join("README.md"),
116 "# Stash Demo Project\n\nDemonstrating Git stash operations.\n\nSecond round of changes!\n",
117 )?;
118
119 // Create more untracked files
120 fs::write(repo_path.join("config.json"), "{\"debug\": true}\n")?;
121
122 let untracked_options = StashOptions::new().with_untracked().with_keep_index();
123 let untracked_stash = repo.stash_push(
124 "WIP: config changes with untracked files",
125 untracked_options,
126 )?;
127 println!("Created stash with untracked files: {}", untracked_stash);
128
129 // 3. Create stash with specific paths
130 println!("\n3. Creating stash with specific paths:");
131
132 // Make changes to multiple files and add them to git
133 fs::write(repo_path.join("file1.txt"), "Content for file 1\n")?;
134 fs::write(repo_path.join("file2.txt"), "Content for file 2\n")?;
135 fs::write(repo_path.join("file3.txt"), "Content for file 3\n")?;
136
137 // Add all files so they're tracked
138 repo.add(&["file1.txt", "file2.txt", "file3.txt"])?;
139
140 // Now modify them so there are changes to stash
141 fs::write(repo_path.join("file1.txt"), "Modified content for file 1\n")?;
142 fs::write(repo_path.join("file2.txt"), "Modified content for file 2\n")?;
143 fs::write(repo_path.join("file3.txt"), "Modified content for file 3\n")?;
144
145 let path_options = StashOptions::new().with_paths(vec!["file1.txt".into(), "file2.txt".into()]);
146 let path_stash = repo.stash_push("WIP: specific files only", path_options)?;
147 println!("Created stash with specific paths: {}", path_stash);
148
149 // Demonstrate stash listing and filtering
150 println!("\n=== Stash Listing and Filtering ===");
151
152 let stashes = repo.stash_list()?;
153 println!("\nAll stashes ({} total):", stashes.len());
154 for stash in stashes.iter() {
155 println!(
156 " [{}] {} -> {}",
157 stash.index,
158 stash.message,
159 stash.hash.short()
160 );
161 println!(
162 " Branch: {} | Created: {}",
163 stash.branch,
164 stash.timestamp.format("%Y-%m-%d %H:%M:%S")
165 );
166 }
167
168 // Test filtering
169 println!("\nFiltering examples:");
170
171 // Find stashes containing specific text
172 let wip_stashes: Vec<_> = stashes.find_containing("WIP").collect();
173 println!("Stashes containing 'WIP': {} found", wip_stashes.len());
174 for stash in &wip_stashes {
175 println!(" - {}", stash.message);
176 }
177
178 let config_stashes: Vec<_> = stashes.find_containing("config").collect();
179 println!(
180 "Stashes containing 'config': {} found",
181 config_stashes.len()
182 );
183
184 // Get latest stash
185 if let Some(latest) = stashes.latest() {
186 println!("Latest stash: {}", latest.message);
187 }
188
189 // Get specific stash by index
190 if let Some(second_stash) = stashes.get(1) {
191 println!("Second stash: {}", second_stash.message);
192 }
193
194 // Demonstrate stash content viewing
195 println!("\n=== Viewing Stash Contents ===");
196
197 println!("\nShowing contents of latest stash:");
198 let stash_contents = repo.stash_show(0)?;
199 println!("{}", stash_contents);
200
201 // Demonstrate stash application
202 println!("\n=== Applying and Popping Stashes ===");
203
204 println!("\n1. Testing stash apply (keeps stash in list):");
205 let stashes_before_apply = repo.stash_list()?;
206 println!("Stashes before apply: {}", stashes_before_apply.len());
207
208 // Apply the latest stash
209 repo.stash_apply(0, StashApplyOptions::new())?;
210 println!("Applied stash@{{0}}");
211
212 let stashes_after_apply = repo.stash_list()?;
213 println!("Stashes after apply: {}", stashes_after_apply.len());
214
215 // Check what was restored
216 let status_after_apply = repo.status()?;
217 println!("Status after apply:");
218 println!(
219 " Staged files: {}",
220 status_after_apply.staged_files().count()
221 );
222 println!(
223 " Unstaged files: {}",
224 status_after_apply.unstaged_files().count()
225 );
226 println!(
227 " Untracked files: {}",
228 status_after_apply.untracked_entries().count()
229 );
230
231 println!("\n2. Testing stash pop (removes stash from list):");
232
233 // First, stash current changes again to have something to pop
234 repo.stash_save("Temporary stash for pop test")?;
235
236 let stashes_before_pop = repo.stash_list()?;
237 println!("Stashes before pop: {}", stashes_before_pop.len());
238
239 // Pop the latest stash
240 repo.stash_pop(0, StashApplyOptions::new().with_quiet())?;
241 println!("Popped stash@{{0}}");
242
243 let stashes_after_pop = repo.stash_list()?;
244 println!("Stashes after pop: {}", stashes_after_pop.len());
245
246 // Demonstrate advanced apply options
247 println!("\n3. Testing apply with index restoration:");
248
249 // Create a stash with staged changes
250 fs::write(repo_path.join("staged_file.txt"), "This will be staged\n")?;
251 repo.add(&["staged_file.txt"])?;
252
253 fs::write(
254 repo_path.join("unstaged_file.txt"),
255 "This will be unstaged\n",
256 )?;
257
258 repo.stash_save("Stash with staged and unstaged changes")?;
259
260 // Apply with index restoration
261 let apply_options = StashApplyOptions::new().with_index();
262 repo.stash_apply(0, apply_options)?;
263 println!("Applied stash with index restoration");
264
265 let final_status = repo.status()?;
266 println!("Final status after index restoration:");
267 println!(" Staged files: {}", final_status.staged_files().count());
268 println!(
269 " Unstaged files: {}",
270 final_status.unstaged_files().count()
271 );
272
273 // Demonstrate stash management
274 println!("\n=== Stash Management ===");
275
276 // Create a few test stashes
277 for i in 1..=3 {
278 fs::write(
279 repo_path.join(format!("test{}.txt", i)),
280 format!("Test content {}\n", i),
281 )?;
282 repo.stash_save(&format!("Test stash {}", i))?;
283 }
284
285 let management_stashes = repo.stash_list()?;
286 println!(
287 "\nCreated {} test stashes for management demo",
288 management_stashes.len()
289 );
290
291 // Drop a specific stash
292 println!("\n1. Dropping middle stash:");
293 println!("Before drop: {} stashes", management_stashes.len());
294
295 repo.stash_drop(1)?; // Drop second stash (index 1)
296 println!("Dropped stash@{{1}}");
297
298 let after_drop = repo.stash_list()?;
299 println!("After drop: {} stashes", after_drop.len());
300
301 // Show remaining stashes
302 println!("Remaining stashes:");
303 for stash in after_drop.iter() {
304 println!(" [{}] {}", stash.index, stash.message);
305 }
306
307 // Clear all stashes
308 println!("\n2. Clearing all stashes:");
309 repo.stash_clear()?;
310 println!("Cleared all stashes");
311
312 let final_stashes = repo.stash_list()?;
313 println!("Stashes after clear: {}", final_stashes.len());
314
315 // Demonstrate error handling
316 println!("\n=== Error Handling ===");
317
318 println!("\n1. Testing operations on empty stash list:");
319
320 // Try to apply non-existent stash
321 match repo.stash_apply(0, StashApplyOptions::new()) {
322 Ok(_) => println!("ERROR: Should have failed to apply non-existent stash"),
323 Err(e) => println!("Expected error applying non-existent stash: {}", e),
324 }
325
326 // Try to show non-existent stash
327 match repo.stash_show(0) {
328 Ok(_) => println!("ERROR: Should have failed to show non-existent stash"),
329 Err(e) => println!("Expected error showing non-existent stash: {}", e),
330 }
331
332 // Try to drop non-existent stash
333 match repo.stash_drop(0) {
334 Ok(_) => println!("ERROR: Should have failed to drop non-existent stash"),
335 Err(e) => println!("Expected error dropping non-existent stash: {}", e),
336 }
337
338 // Summary
339 println!("\n=== Summary ===");
340 println!("\nStash operations demonstrated:");
341 println!(" ✓ Basic stash save and push with options");
342 println!(" ✓ Stash with untracked files and keep-index");
343 println!(" ✓ Stash specific paths only");
344 println!(" ✓ Comprehensive stash listing and filtering");
345 println!(" ✓ Stash content viewing");
346 println!(" ✓ Apply vs pop operations");
347 println!(" ✓ Index restoration during apply");
348 println!(" ✓ Stash dropping and clearing");
349 println!(" ✓ Error handling for edge cases");
350
351 println!("\nStash options demonstrated:");
352 println!(" ✓ with_untracked() - Include untracked files");
353 println!(" ✓ with_keep_index() - Keep staged changes");
354 println!(" ✓ with_paths() - Stash specific files only");
355 println!(" ✓ with_index() - Restore staged state on apply");
356 println!(" ✓ with_quiet() - Suppress output messages");
357
358 println!("\nStash filtering demonstrated:");
359 println!(" ✓ find_containing() - Search by message content");
360 println!(" ✓ latest() - Get most recent stash");
361 println!(" ✓ get() - Get stash by index");
362 println!(" ✓ for_branch() - Filter by branch name");
363
364 // Clean up
365 println!("\nCleaning up example repository...");
366 fs::remove_dir_all(&repo_path)?;
367 println!("Stash operations example completed successfully!");
368
369 Ok(())
370}
examples/file_lifecycle_operations.rs (line 36)
16fn main() -> Result<()> {
17 println!("Rustic Git - File Lifecycle Operations Example\n");
18
19 let base_path = env::temp_dir().join("rustic_git_files_example");
20 let repo_path = base_path.join("main_repo");
21
22 // Clean up any previous runs
23 if base_path.exists() {
24 fs::remove_dir_all(&base_path).expect("Failed to clean up previous example");
25 }
26 fs::create_dir_all(&base_path)?;
27
28 println!("=== Repository Setup ===\n");
29
30 // Initialize repository
31 println!("Initializing repository for file lifecycle demonstrations...");
32 let repo = Repository::init(&repo_path, false)?;
33 println!("Repository initialized at: {}", repo_path.display());
34
35 // Set up git configuration for commits
36 repo.config().set_user("Demo User", "demo@example.com")?;
37
38 // Create initial project structure
39 fs::create_dir_all(repo_path.join("src"))?;
40 fs::create_dir_all(repo_path.join("docs"))?;
41 fs::create_dir_all(repo_path.join("tests"))?;
42
43 let files = [
44 (
45 "README.md",
46 "# File Lifecycle Demo\n\nDemonstrating rustic-git file management capabilities.",
47 ),
48 (
49 "src/main.rs",
50 "fn main() {\n println!(\"Hello, world!\");\n}",
51 ),
52 (
53 "src/lib.rs",
54 "//! Library module\n\npub fn greet() {\n println!(\"Hello from lib!\");\n}",
55 ),
56 ("docs/guide.md", "# User Guide\n\nThis is the user guide."),
57 (
58 "tests/integration.rs",
59 "#[test]\nfn test_basic() {\n assert_eq!(2 + 2, 4);\n}",
60 ),
61 ];
62
63 for (path, content) in &files {
64 fs::write(repo_path.join(path), content)?;
65 }
66
67 repo.add(&files.iter().map(|(path, _)| *path).collect::<Vec<_>>())?;
68 let initial_commit = repo.commit("Initial project setup")?;
69 println!("Created initial commit: {}\n", initial_commit.short());
70
71 println!("=== File Restoration Operations ===\n");
72
73 // Modify some files
74 println!("Modifying files to demonstrate restoration...");
75 fs::write(
76 repo_path.join("README.md"),
77 "# Modified README\n\nThis content has been changed.",
78 )?;
79 fs::write(
80 repo_path.join("src/main.rs"),
81 "fn main() {\n println!(\"Modified main!\");\n println!(\"Added new line!\");\n}",
82 )?;
83
84 println!(" Modified README.md and src/main.rs");
85
86 // Show current status
87 let status = repo.status()?;
88 println!(
89 " Files with modifications: {}",
90 status.unstaged_files().count()
91 );
92 for entry in status.unstaged_files() {
93 println!(" - {}", entry.path.display());
94 }
95 println!();
96
97 // Restore single file with checkout_file
98 println!("Restoring README.md using checkout_file():");
99 repo.checkout_file("README.md")?;
100 let restored_content = fs::read_to_string(repo_path.join("README.md"))?;
101 println!(" ✓ README.md restored to original state");
102 println!(
103 " Content preview: {:?}",
104 restored_content.lines().next().unwrap_or("")
105 );
106 println!();
107
108 // Demonstrate advanced restore with options
109 println!("Creating second commit for restore demonstration...");
110 fs::write(
111 repo_path.join("src/advanced.rs"),
112 "//! Advanced module\n\npub fn advanced_function() {\n println!(\"Advanced functionality\");\n}",
113 )?;
114 repo.add(&["src/advanced.rs"])?;
115 let second_commit = repo.commit("Add advanced module")?;
116 println!(" Second commit: {}", second_commit.short());
117
118 // Modify the advanced file
119 fs::write(
120 repo_path.join("src/advanced.rs"),
121 "//! HEAVILY MODIFIED\n\npub fn broken_function() {\n panic!(\"This is broken!\");\n}",
122 )?;
123 println!(" Modified src/advanced.rs");
124
125 // Restore from specific commit using restore with options
126 println!("Restoring src/advanced.rs from specific commit using restore():");
127 let restore_options = RestoreOptions::new()
128 .with_source(format!("{}", second_commit))
129 .with_worktree();
130 repo.restore(&["src/advanced.rs"], restore_options)?;
131
132 let restored_advanced = fs::read_to_string(repo_path.join("src/advanced.rs"))?;
133 println!(" ✓ File restored from commit {}", second_commit.short());
134 println!(
135 " Content preview: {:?}",
136 restored_advanced.lines().next().unwrap_or("")
137 );
138 println!();
139
140 println!("=== Staging Area Operations ===\n");
141
142 // Modify and stage files
143 println!("Demonstrating staging area manipulation...");
144 fs::write(
145 repo_path.join("src/lib.rs"),
146 "//! STAGED CHANGES\n\npub fn new_function() {\n println!(\"This will be staged\");\n}",
147 )?;
148 repo.add(&["src/lib.rs"])?;
149 println!(" Modified and staged src/lib.rs");
150
151 let status = repo.status()?;
152 println!(" Staged files: {}", status.staged_files().count());
153 for entry in status.staged_files() {
154 println!(" - {}", entry.path.display());
155 }
156
157 // Unstage the file
158 println!("Unstaging src/lib.rs using reset_file():");
159 repo.reset_file("src/lib.rs")?;
160
161 let status_after_reset = repo.status()?;
162 println!(" ✓ File unstaged (now in modified files)");
163 println!(
164 " Staged files: {}",
165 status_after_reset.staged_files().count()
166 );
167 println!(
168 " Modified files: {}",
169 status_after_reset.unstaged_files().count()
170 );
171 println!();
172
173 println!("=== File Removal Operations ===\n");
174
175 // Create files for removal demonstration
176 println!("Creating files for removal demonstration...");
177 fs::write(repo_path.join("temp_file.txt"), "This is a temporary file")?;
178 fs::write(
179 repo_path.join("docs/old_doc.md"),
180 "# Old Documentation\n\nThis document is outdated.",
181 )?;
182 fs::create_dir_all(repo_path.join("old_directory"))?;
183 fs::write(
184 repo_path.join("old_directory/nested_file.txt"),
185 "Nested content",
186 )?;
187
188 // Add and commit these files
189 repo.add(&[
190 "temp_file.txt",
191 "docs/old_doc.md",
192 "old_directory/nested_file.txt",
193 ])?;
194 repo.commit("Add files for removal demo")?;
195 println!(" Created and committed files for removal");
196
197 // Basic file removal
198 println!("Removing temp_file.txt using rm():");
199 repo.rm(&["temp_file.txt"])?;
200 println!(" ✓ temp_file.txt removed from repository and working tree");
201 assert!(!repo_path.join("temp_file.txt").exists());
202
203 // Remove from index only (keep in working tree)
204 println!("Removing docs/old_doc.md from index only using rm_with_options():");
205 let cached_remove_options = RemoveOptions::new().with_cached();
206 repo.rm_with_options(&["docs/old_doc.md"], cached_remove_options)?;
207
208 println!(" ✓ File removed from index but kept in working tree");
209 assert!(repo_path.join("docs/old_doc.md").exists());
210 let content = fs::read_to_string(repo_path.join("docs/old_doc.md"))?;
211 println!(
212 " Working tree content still available: {:?}",
213 content.lines().next().unwrap_or("")
214 );
215
216 // Recursive removal
217 println!("Removing old_directory/ recursively:");
218 let recursive_options = RemoveOptions::new().with_recursive();
219 repo.rm_with_options(&["old_directory/"], recursive_options)?;
220 println!(" ✓ Directory and contents removed recursively");
221 assert!(!repo_path.join("old_directory").exists());
222 println!();
223
224 println!("=== File Move/Rename Operations ===\n");
225
226 // Create files for move demonstration
227 println!("Creating files for move/rename demonstration...");
228 fs::write(repo_path.join("old_name.txt"), "This file will be renamed")?;
229 fs::create_dir_all(repo_path.join("source_dir"))?;
230 fs::write(
231 repo_path.join("source_dir/movable.txt"),
232 "This file will be moved",
233 )?;
234 fs::create_dir_all(repo_path.join("target_dir"))?;
235
236 repo.add(&["old_name.txt", "source_dir/movable.txt"])?;
237 repo.commit("Add files for move demo")?;
238 println!(" Created files for move demonstration");
239
240 // Simple rename
241 println!("Renaming old_name.txt to new_name.txt using mv():");
242 repo.mv("old_name.txt", "new_name.txt")?;
243
244 assert!(!repo_path.join("old_name.txt").exists());
245 assert!(repo_path.join("new_name.txt").exists());
246 let content = fs::read_to_string(repo_path.join("new_name.txt"))?;
247 println!(" ✓ File renamed successfully");
248 println!(" Content preserved: {:?}", content.trim());
249
250 // Move file to different directory
251 println!("Moving source_dir/movable.txt to target_dir/ using mv():");
252 repo.mv("source_dir/movable.txt", "target_dir/movable.txt")?;
253
254 assert!(!repo_path.join("source_dir/movable.txt").exists());
255 assert!(repo_path.join("target_dir/movable.txt").exists());
256 println!(" ✓ File moved to different directory");
257
258 // Demonstrate move with options (dry run)
259 fs::write(repo_path.join("test_move.txt"), "Test content for dry run")?;
260 repo.add(&["test_move.txt"])?;
261 repo.commit("Add test file for dry run demo")?;
262
263 println!("Demonstrating dry run move (won't actually move):");
264 let dry_run_options = MoveOptions::new().with_dry_run().with_verbose();
265 repo.mv_with_options("test_move.txt", "would_be_moved.txt", dry_run_options)?;
266
267 // File should still exist at original location
268 assert!(repo_path.join("test_move.txt").exists());
269 assert!(!repo_path.join("would_be_moved.txt").exists());
270 println!(" ✓ Dry run completed - no actual move performed");
271 println!();
272
273 println!("=== .gitignore Management ===\n");
274
275 // Initially no ignore patterns
276 println!("Checking initial .gitignore state:");
277 let initial_patterns = repo.ignore_list()?;
278 println!(" Initial ignore patterns: {}", initial_patterns.len());
279
280 // Add ignore patterns
281 println!("Adding ignore patterns...");
282 repo.ignore_add(&[
283 "*.tmp",
284 "*.log",
285 "build/",
286 "node_modules/",
287 ".DS_Store",
288 "*.secret",
289 ])?;
290 println!(" Added 6 ignore patterns to .gitignore");
291
292 // List current patterns
293 let patterns = repo.ignore_list()?;
294 println!(" Current ignore patterns: {}", patterns.len());
295 for (i, pattern) in patterns.iter().enumerate() {
296 println!(" {}. {}", i + 1, pattern);
297 }
298
299 // Create test files to check ignore status
300 println!("\nCreating test files to check ignore status...");
301 let test_files = [
302 ("regular_file.txt", false),
303 ("temp_file.tmp", true),
304 ("debug.log", true),
305 ("important.secret", true),
306 ("normal.md", false),
307 ];
308
309 for (filename, _) in &test_files {
310 fs::write(repo_path.join(filename), "test content")?;
311 }
312
313 // Check ignore status for each file
314 println!("Checking ignore status for test files:");
315 for (filename, expected_ignored) in &test_files {
316 let is_ignored = repo.ignore_check(filename)?;
317 let status_symbol = if is_ignored { "🚫" } else { "✅" };
318 println!(
319 " {} {} - {}",
320 status_symbol,
321 filename,
322 if is_ignored { "IGNORED" } else { "TRACKED" }
323 );
324
325 // Verify expectation
326 assert_eq!(
327 is_ignored, *expected_ignored,
328 "Ignore status mismatch for {}",
329 filename
330 );
331 }
332 println!();
333
334 println!("=== Error Handling and Edge Cases ===\n");
335
336 // Test error cases
337 println!("Testing error conditions:");
338
339 // Try to checkout non-existent file
340 println!(" Attempting to checkout non-existent file:");
341 match repo.checkout_file("nonexistent.txt") {
342 Ok(_) => println!(" Unexpected success"),
343 Err(e) => println!(" ✓ Expected error: {}", e),
344 }
345
346 // Try to reset non-existent file
347 println!(" Attempting to reset non-staged file:");
348 match repo.reset_file("new_name.txt") {
349 Ok(_) => println!(" ✓ Reset succeeded (file not staged, no error)"),
350 Err(e) => println!(" Error: {}", e),
351 }
352
353 // Try to remove non-existent file
354 println!(" Attempting to remove non-existent file:");
355 match repo.rm(&["definitely_not_here.txt"]) {
356 Ok(_) => println!(" Unexpected success"),
357 Err(e) => println!(" ✓ Expected error: {}", e),
358 }
359
360 // Try to remove with ignore-unmatch option
361 println!(" Attempting to remove with ignore-unmatch option:");
362 let ignore_unmatch_options = RemoveOptions::new().with_ignore_unmatch();
363 match repo.rm_with_options(&["also_not_here.txt"], ignore_unmatch_options) {
364 Ok(_) => println!(" ✓ Succeeded with ignore-unmatch (no error)"),
365 Err(e) => println!(" Error: {}", e),
366 }
367
368 // Try to move to existing file without force
369 fs::write(repo_path.join("existing_target.txt"), "existing content")?;
370 repo.add(&["existing_target.txt"])?;
371 repo.commit("Add existing target")?;
372
373 println!(" Attempting to move to existing file without force:");
374 match repo.mv("test_move.txt", "existing_target.txt") {
375 Ok(_) => println!(" Unexpected success (git may have overwritten)"),
376 Err(e) => println!(" ✓ Expected error: {}", e),
377 }
378 println!();
379
380 println!("=== Advanced Restore Operations ===\n");
381
382 // Demonstrate restore with staged and worktree options
383 println!("Demonstrating advanced restore with staging area...");
384
385 // Modify file and stage it
386 fs::write(repo_path.join("new_name.txt"), "staged changes")?;
387 repo.add(&["new_name.txt"])?;
388
389 // Modify it again in working tree
390 fs::write(repo_path.join("new_name.txt"), "working tree changes")?;
391
392 println!(" File has both staged and working tree changes");
393
394 // Restore only staged area
395 println!(" Restoring staged changes only:");
396 let staged_restore = RestoreOptions::new().with_staged();
397 repo.restore(&["new_name.txt"], staged_restore)?;
398
399 let content_after_staged_restore = fs::read_to_string(repo_path.join("new_name.txt"))?;
400 println!(" ✓ Staged changes restored, working tree preserved");
401 println!(
402 " Working tree content: {:?}",
403 content_after_staged_restore.trim()
404 );
405
406 // Restore working tree
407 println!(" Restoring working tree:");
408 let worktree_restore = RestoreOptions::new().with_worktree();
409 repo.restore(&["new_name.txt"], worktree_restore)?;
410
411 let final_content = fs::read_to_string(repo_path.join("new_name.txt"))?;
412 println!(" ✓ Working tree restored to committed state");
413 println!(" Final content: {:?}", final_content.trim());
414 println!();
415
416 println!("=== Repository State Summary ===\n");
417
418 let final_status = repo.status()?;
419 println!("Final repository state:");
420 println!(" Clean repository: {}", final_status.is_clean());
421 println!(" Staged files: {}", final_status.staged_files().count());
422 println!(
423 " Modified files: {}",
424 final_status.unstaged_files().count()
425 );
426 println!(
427 " Untracked files: {}",
428 final_status.untracked_entries().count()
429 );
430
431 if !final_status.is_clean() {
432 println!("\n Remaining changes:");
433 for entry in final_status.staged_files() {
434 println!(" Staged: {}", entry.path.display());
435 }
436 for entry in final_status.unstaged_files() {
437 println!(" Modified: {}", entry.path.display());
438 }
439 for entry in final_status.untracked_entries() {
440 println!(" Untracked: {}", entry.path.display());
441 }
442 }
443
444 // Show .gitignore content
445 let final_patterns = repo.ignore_list()?;
446 println!("\n .gitignore patterns: {}", final_patterns.len());
447 for pattern in final_patterns {
448 println!(" - {}", pattern);
449 }
450
451 println!("\n=== Summary ===\n");
452
453 println!("File lifecycle operations demonstration completed!");
454 println!(" Repository: {}", repo_path.display());
455
456 println!("\nOperations demonstrated:");
457 println!(" ✓ File restoration from HEAD (checkout_file)");
458 println!(" ✓ Advanced file restoration with options (restore)");
459 println!(" ✓ Unstaging files (reset_file)");
460 println!(" ✓ File removal with various options (rm, rm_with_options)");
461 println!(" ✓ File moving and renaming (mv, mv_with_options)");
462 println!(" ✓ .gitignore pattern management (ignore_add, ignore_list, ignore_check)");
463 println!(" ✓ Staged vs working tree restoration");
464 println!(" ✓ Error handling for invalid operations");
465 println!(" ✓ Dry run and verbose options");
466 println!(" ✓ Recursive and cached removal options");
467
468 // Clean up
469 println!("\nCleaning up example repositories...");
470 fs::remove_dir_all(&base_path)?;
471 println!("File lifecycle operations example completed!");
472
473 Ok(())
474}
Sourcepub fn get_user(&self) -> Result<(String, String)>
pub fn get_user(&self) -> Result<(String, String)>
Get the current git user configuration
Returns a tuple of (name, email) from the repository configuration.
§Returns
A tuple containing the user name and email, or an error if either configuration value is not set.
Examples found in repository?
examples/config_operations.rs (line 40)
14fn main() -> Result<()> {
15 println!("Rustic Git - Repository Configuration Operations Example\n");
16
17 // Use a temporary directory for this example
18 let repo_path = env::temp_dir().join("rustic_git_config_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 println!("Initializing new repository at: {}", repo_path.display());
26
27 // Initialize a new repository
28 let repo = Repository::init(&repo_path, false)?;
29
30 // ==================== USER CONFIGURATION ====================
31
32 println!("\n[CONFIG] Configuring git user settings...");
33
34 // Set user configuration (convenience method)
35 repo.config()
36 .set_user("Alice Developer", "alice@example.com")?;
37 println!("Set user configuration");
38
39 // Verify user configuration
40 let (name, email) = repo.config().get_user()?;
41 println!("Current user: {} <{}>", name, email);
42
43 // ==================== GENERAL CONFIGURATION ====================
44
45 println!("\n[CONFIG] Setting repository configuration values...");
46
47 // Set various git configuration values
48 repo.config().set("core.autocrlf", "false")?;
49 repo.config().set("core.ignorecase", "true")?;
50 repo.config().set("pull.rebase", "true")?;
51 repo.config().set("push.default", "simple")?;
52 repo.config().set("branch.autosetupmerge", "always")?;
53
54 println!("Set core configuration values");
55
56 // Get and display configuration values
57 println!("\n[CONFIG] Current repository configuration:");
58
59 let configs = [
60 "core.autocrlf",
61 "core.ignorecase",
62 "pull.rebase",
63 "push.default",
64 "branch.autosetupmerge",
65 ];
66
67 for config_key in &configs {
68 match repo.config().get(config_key) {
69 Ok(value) => println!(" {} = {}", config_key, value),
70 Err(_) => println!(" {} = <not set>", config_key),
71 }
72 }
73
74 // ==================== CONFIGURATION WITH COMMITS ====================
75
76 println!("\n[COMMIT] Testing configuration with commit operations...");
77
78 // Create a test file
79 let test_file_path = repo_path.join("test.txt");
80 fs::write(
81 &test_file_path,
82 "Hello from rustic-git configuration example!",
83 )?;
84 println!("Created test file: test.txt");
85
86 // Stage the file
87 repo.add(&["test.txt"])?;
88 println!("Staged test.txt");
89
90 // Create a commit (this will use our configured user)
91 let commit_hash = repo.commit("Add test file with configuration example")?;
92 println!("Created commit: {}", commit_hash.short());
93
94 // ==================== CONFIGURATION MODIFICATION ====================
95
96 println!("\n[UPDATE] Modifying configuration values...");
97
98 // Change some configuration values
99 repo.config().set("core.autocrlf", "true")?;
100 repo.config()
101 .set("user.email", "alice.developer@newcompany.com")?;
102
103 println!("Updated configuration values");
104
105 // Display updated values
106 let autocrlf = repo.config().get("core.autocrlf")?;
107 let (updated_name, updated_email) = repo.config().get_user()?;
108
109 println!("Updated configuration:");
110 println!(" core.autocrlf = {}", autocrlf);
111 println!(" user: {} <{}>", updated_name, updated_email);
112
113 // ==================== CONFIGURATION REMOVAL ====================
114
115 println!("\n[REMOVE] Removing configuration values...");
116
117 // Remove a configuration value
118 repo.config().unset("branch.autosetupmerge")?;
119 println!("Removed branch.autosetupmerge");
120
121 // Try to get the removed value (should fail)
122 match repo.config().get("branch.autosetupmerge") {
123 Ok(value) => println!("Unexpected: branch.autosetupmerge = {}", value),
124 Err(_) => println!("Confirmed: branch.autosetupmerge is not set"),
125 }
126
127 // ==================== ADVANCED CONFIGURATION ====================
128
129 println!("\n[ADVANCED] Setting advanced configuration...");
130
131 // Set some advanced git configuration
132 repo.config().set("diff.tool", "vimdiff")?;
133 repo.config().set("merge.tool", "vimdiff")?;
134 repo.config().set("alias.st", "status")?;
135 repo.config().set("alias.co", "checkout")?;
136 repo.config().set("alias.br", "branch")?;
137 repo.config().set("alias.ci", "commit")?;
138
139 println!("Set advanced configuration (diff/merge tools and aliases)");
140
141 // Display all custom configuration
142 println!("\n[SUMMARY] Complete repository configuration summary:");
143
144 let all_configs = [
145 ("User", vec![("user.name", ""), ("user.email", "")]),
146 ("Core", vec![("core.autocrlf", ""), ("core.ignorecase", "")]),
147 ("Workflow", vec![("pull.rebase", ""), ("push.default", "")]),
148 ("Tools", vec![("diff.tool", ""), ("merge.tool", "")]),
149 (
150 "Aliases",
151 vec![
152 ("alias.st", ""),
153 ("alias.co", ""),
154 ("alias.br", ""),
155 ("alias.ci", ""),
156 ],
157 ),
158 ];
159
160 for (category, configs) in &all_configs {
161 println!("\n {}:", category);
162 for (key, _) in configs {
163 match repo.config().get(key) {
164 Ok(value) => println!(" {} = {}", key, value),
165 Err(_) => println!(" {} = <not set>", key),
166 }
167 }
168 }
169
170 // ==================== PRACTICAL EXAMPLE ====================
171
172 println!("\n[TEAM] Practical example: Setting up repository for a team...");
173
174 // Configure repository for team development
175 repo.config().set("user.name", "Team Member")?;
176 repo.config().set("user.email", "team@company.com")?;
177 repo.config().set("core.autocrlf", "input")?;
178 repo.config().set("core.safecrlf", "true")?;
179 repo.config().set("pull.rebase", "true")?;
180 repo.config().set("push.default", "current")?;
181 repo.config().set("init.defaultBranch", "main")?;
182
183 println!("Configured repository for team development");
184
185 // Create another commit with the team configuration
186 fs::write(
187 repo_path.join("team.md"),
188 "# Team Development\n\nThis repository is configured for team development.",
189 )?;
190 repo.add(&["team.md"])?;
191 let team_commit = repo.commit("Add team development documentation")?;
192
193 println!("Created team commit: {}", team_commit.short());
194
195 // Final verification
196 let (final_name, final_email) = repo.config().get_user()?;
197 println!("\n[FINAL] Final repository configuration:");
198 println!(" User: {} <{}>", final_name, final_email);
199 println!(" Repository configured for team development workflow");
200
201 // ==================== CLEANUP ====================
202
203 println!("\n[CLEANUP] Cleaning up...");
204 fs::remove_dir_all(&repo_path).expect("Failed to clean up example");
205 println!("Example completed successfully!");
206
207 Ok(())
208}
Sourcepub fn set(&self, key: &str, value: &str) -> Result<()>
pub fn set(&self, key: &str, value: &str) -> Result<()>
Set a git configuration value for this repository
§Arguments
key
- The configuration key (e.g., “user.name”, “core.autocrlf”)value
- The value to set
§Example
use rustic_git::Repository;
use std::{env, fs};
let test_path = env::temp_dir().join("config_set_test");
if test_path.exists() {
fs::remove_dir_all(&test_path).unwrap();
}
let repo = Repository::init(&test_path, false)?;
repo.config().set("core.autocrlf", "false")?;
repo.config().set("user.name", "Jane Doe")?;
// Clean up
fs::remove_dir_all(&test_path).unwrap();
Examples found in repository?
examples/config_operations.rs (line 48)
14fn main() -> Result<()> {
15 println!("Rustic Git - Repository Configuration Operations Example\n");
16
17 // Use a temporary directory for this example
18 let repo_path = env::temp_dir().join("rustic_git_config_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 println!("Initializing new repository at: {}", repo_path.display());
26
27 // Initialize a new repository
28 let repo = Repository::init(&repo_path, false)?;
29
30 // ==================== USER CONFIGURATION ====================
31
32 println!("\n[CONFIG] Configuring git user settings...");
33
34 // Set user configuration (convenience method)
35 repo.config()
36 .set_user("Alice Developer", "alice@example.com")?;
37 println!("Set user configuration");
38
39 // Verify user configuration
40 let (name, email) = repo.config().get_user()?;
41 println!("Current user: {} <{}>", name, email);
42
43 // ==================== GENERAL CONFIGURATION ====================
44
45 println!("\n[CONFIG] Setting repository configuration values...");
46
47 // Set various git configuration values
48 repo.config().set("core.autocrlf", "false")?;
49 repo.config().set("core.ignorecase", "true")?;
50 repo.config().set("pull.rebase", "true")?;
51 repo.config().set("push.default", "simple")?;
52 repo.config().set("branch.autosetupmerge", "always")?;
53
54 println!("Set core configuration values");
55
56 // Get and display configuration values
57 println!("\n[CONFIG] Current repository configuration:");
58
59 let configs = [
60 "core.autocrlf",
61 "core.ignorecase",
62 "pull.rebase",
63 "push.default",
64 "branch.autosetupmerge",
65 ];
66
67 for config_key in &configs {
68 match repo.config().get(config_key) {
69 Ok(value) => println!(" {} = {}", config_key, value),
70 Err(_) => println!(" {} = <not set>", config_key),
71 }
72 }
73
74 // ==================== CONFIGURATION WITH COMMITS ====================
75
76 println!("\n[COMMIT] Testing configuration with commit operations...");
77
78 // Create a test file
79 let test_file_path = repo_path.join("test.txt");
80 fs::write(
81 &test_file_path,
82 "Hello from rustic-git configuration example!",
83 )?;
84 println!("Created test file: test.txt");
85
86 // Stage the file
87 repo.add(&["test.txt"])?;
88 println!("Staged test.txt");
89
90 // Create a commit (this will use our configured user)
91 let commit_hash = repo.commit("Add test file with configuration example")?;
92 println!("Created commit: {}", commit_hash.short());
93
94 // ==================== CONFIGURATION MODIFICATION ====================
95
96 println!("\n[UPDATE] Modifying configuration values...");
97
98 // Change some configuration values
99 repo.config().set("core.autocrlf", "true")?;
100 repo.config()
101 .set("user.email", "alice.developer@newcompany.com")?;
102
103 println!("Updated configuration values");
104
105 // Display updated values
106 let autocrlf = repo.config().get("core.autocrlf")?;
107 let (updated_name, updated_email) = repo.config().get_user()?;
108
109 println!("Updated configuration:");
110 println!(" core.autocrlf = {}", autocrlf);
111 println!(" user: {} <{}>", updated_name, updated_email);
112
113 // ==================== CONFIGURATION REMOVAL ====================
114
115 println!("\n[REMOVE] Removing configuration values...");
116
117 // Remove a configuration value
118 repo.config().unset("branch.autosetupmerge")?;
119 println!("Removed branch.autosetupmerge");
120
121 // Try to get the removed value (should fail)
122 match repo.config().get("branch.autosetupmerge") {
123 Ok(value) => println!("Unexpected: branch.autosetupmerge = {}", value),
124 Err(_) => println!("Confirmed: branch.autosetupmerge is not set"),
125 }
126
127 // ==================== ADVANCED CONFIGURATION ====================
128
129 println!("\n[ADVANCED] Setting advanced configuration...");
130
131 // Set some advanced git configuration
132 repo.config().set("diff.tool", "vimdiff")?;
133 repo.config().set("merge.tool", "vimdiff")?;
134 repo.config().set("alias.st", "status")?;
135 repo.config().set("alias.co", "checkout")?;
136 repo.config().set("alias.br", "branch")?;
137 repo.config().set("alias.ci", "commit")?;
138
139 println!("Set advanced configuration (diff/merge tools and aliases)");
140
141 // Display all custom configuration
142 println!("\n[SUMMARY] Complete repository configuration summary:");
143
144 let all_configs = [
145 ("User", vec![("user.name", ""), ("user.email", "")]),
146 ("Core", vec![("core.autocrlf", ""), ("core.ignorecase", "")]),
147 ("Workflow", vec![("pull.rebase", ""), ("push.default", "")]),
148 ("Tools", vec![("diff.tool", ""), ("merge.tool", "")]),
149 (
150 "Aliases",
151 vec![
152 ("alias.st", ""),
153 ("alias.co", ""),
154 ("alias.br", ""),
155 ("alias.ci", ""),
156 ],
157 ),
158 ];
159
160 for (category, configs) in &all_configs {
161 println!("\n {}:", category);
162 for (key, _) in configs {
163 match repo.config().get(key) {
164 Ok(value) => println!(" {} = {}", key, value),
165 Err(_) => println!(" {} = <not set>", key),
166 }
167 }
168 }
169
170 // ==================== PRACTICAL EXAMPLE ====================
171
172 println!("\n[TEAM] Practical example: Setting up repository for a team...");
173
174 // Configure repository for team development
175 repo.config().set("user.name", "Team Member")?;
176 repo.config().set("user.email", "team@company.com")?;
177 repo.config().set("core.autocrlf", "input")?;
178 repo.config().set("core.safecrlf", "true")?;
179 repo.config().set("pull.rebase", "true")?;
180 repo.config().set("push.default", "current")?;
181 repo.config().set("init.defaultBranch", "main")?;
182
183 println!("Configured repository for team development");
184
185 // Create another commit with the team configuration
186 fs::write(
187 repo_path.join("team.md"),
188 "# Team Development\n\nThis repository is configured for team development.",
189 )?;
190 repo.add(&["team.md"])?;
191 let team_commit = repo.commit("Add team development documentation")?;
192
193 println!("Created team commit: {}", team_commit.short());
194
195 // Final verification
196 let (final_name, final_email) = repo.config().get_user()?;
197 println!("\n[FINAL] Final repository configuration:");
198 println!(" User: {} <{}>", final_name, final_email);
199 println!(" Repository configured for team development workflow");
200
201 // ==================== CLEANUP ====================
202
203 println!("\n[CLEANUP] Cleaning up...");
204 fs::remove_dir_all(&repo_path).expect("Failed to clean up example");
205 println!("Example completed successfully!");
206
207 Ok(())
208}
Sourcepub fn get(&self, key: &str) -> Result<String>
pub fn get(&self, key: &str) -> Result<String>
Get a git configuration value from this repository
§Arguments
key
- The configuration key to retrieve
§Returns
The configuration value as a string, or an error if the key is not found.
§Example
use rustic_git::Repository;
use std::{env, fs};
let test_path = env::temp_dir().join("config_get_test");
if test_path.exists() {
fs::remove_dir_all(&test_path).unwrap();
}
let repo = Repository::init(&test_path, false)?;
repo.config().set("user.name", "Jane Doe")?;
let name = repo.config().get("user.name")?;
assert_eq!(name, "Jane Doe");
// Clean up
fs::remove_dir_all(&test_path).unwrap();
Examples found in repository?
examples/config_operations.rs (line 68)
14fn main() -> Result<()> {
15 println!("Rustic Git - Repository Configuration Operations Example\n");
16
17 // Use a temporary directory for this example
18 let repo_path = env::temp_dir().join("rustic_git_config_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 println!("Initializing new repository at: {}", repo_path.display());
26
27 // Initialize a new repository
28 let repo = Repository::init(&repo_path, false)?;
29
30 // ==================== USER CONFIGURATION ====================
31
32 println!("\n[CONFIG] Configuring git user settings...");
33
34 // Set user configuration (convenience method)
35 repo.config()
36 .set_user("Alice Developer", "alice@example.com")?;
37 println!("Set user configuration");
38
39 // Verify user configuration
40 let (name, email) = repo.config().get_user()?;
41 println!("Current user: {} <{}>", name, email);
42
43 // ==================== GENERAL CONFIGURATION ====================
44
45 println!("\n[CONFIG] Setting repository configuration values...");
46
47 // Set various git configuration values
48 repo.config().set("core.autocrlf", "false")?;
49 repo.config().set("core.ignorecase", "true")?;
50 repo.config().set("pull.rebase", "true")?;
51 repo.config().set("push.default", "simple")?;
52 repo.config().set("branch.autosetupmerge", "always")?;
53
54 println!("Set core configuration values");
55
56 // Get and display configuration values
57 println!("\n[CONFIG] Current repository configuration:");
58
59 let configs = [
60 "core.autocrlf",
61 "core.ignorecase",
62 "pull.rebase",
63 "push.default",
64 "branch.autosetupmerge",
65 ];
66
67 for config_key in &configs {
68 match repo.config().get(config_key) {
69 Ok(value) => println!(" {} = {}", config_key, value),
70 Err(_) => println!(" {} = <not set>", config_key),
71 }
72 }
73
74 // ==================== CONFIGURATION WITH COMMITS ====================
75
76 println!("\n[COMMIT] Testing configuration with commit operations...");
77
78 // Create a test file
79 let test_file_path = repo_path.join("test.txt");
80 fs::write(
81 &test_file_path,
82 "Hello from rustic-git configuration example!",
83 )?;
84 println!("Created test file: test.txt");
85
86 // Stage the file
87 repo.add(&["test.txt"])?;
88 println!("Staged test.txt");
89
90 // Create a commit (this will use our configured user)
91 let commit_hash = repo.commit("Add test file with configuration example")?;
92 println!("Created commit: {}", commit_hash.short());
93
94 // ==================== CONFIGURATION MODIFICATION ====================
95
96 println!("\n[UPDATE] Modifying configuration values...");
97
98 // Change some configuration values
99 repo.config().set("core.autocrlf", "true")?;
100 repo.config()
101 .set("user.email", "alice.developer@newcompany.com")?;
102
103 println!("Updated configuration values");
104
105 // Display updated values
106 let autocrlf = repo.config().get("core.autocrlf")?;
107 let (updated_name, updated_email) = repo.config().get_user()?;
108
109 println!("Updated configuration:");
110 println!(" core.autocrlf = {}", autocrlf);
111 println!(" user: {} <{}>", updated_name, updated_email);
112
113 // ==================== CONFIGURATION REMOVAL ====================
114
115 println!("\n[REMOVE] Removing configuration values...");
116
117 // Remove a configuration value
118 repo.config().unset("branch.autosetupmerge")?;
119 println!("Removed branch.autosetupmerge");
120
121 // Try to get the removed value (should fail)
122 match repo.config().get("branch.autosetupmerge") {
123 Ok(value) => println!("Unexpected: branch.autosetupmerge = {}", value),
124 Err(_) => println!("Confirmed: branch.autosetupmerge is not set"),
125 }
126
127 // ==================== ADVANCED CONFIGURATION ====================
128
129 println!("\n[ADVANCED] Setting advanced configuration...");
130
131 // Set some advanced git configuration
132 repo.config().set("diff.tool", "vimdiff")?;
133 repo.config().set("merge.tool", "vimdiff")?;
134 repo.config().set("alias.st", "status")?;
135 repo.config().set("alias.co", "checkout")?;
136 repo.config().set("alias.br", "branch")?;
137 repo.config().set("alias.ci", "commit")?;
138
139 println!("Set advanced configuration (diff/merge tools and aliases)");
140
141 // Display all custom configuration
142 println!("\n[SUMMARY] Complete repository configuration summary:");
143
144 let all_configs = [
145 ("User", vec![("user.name", ""), ("user.email", "")]),
146 ("Core", vec![("core.autocrlf", ""), ("core.ignorecase", "")]),
147 ("Workflow", vec![("pull.rebase", ""), ("push.default", "")]),
148 ("Tools", vec![("diff.tool", ""), ("merge.tool", "")]),
149 (
150 "Aliases",
151 vec![
152 ("alias.st", ""),
153 ("alias.co", ""),
154 ("alias.br", ""),
155 ("alias.ci", ""),
156 ],
157 ),
158 ];
159
160 for (category, configs) in &all_configs {
161 println!("\n {}:", category);
162 for (key, _) in configs {
163 match repo.config().get(key) {
164 Ok(value) => println!(" {} = {}", key, value),
165 Err(_) => println!(" {} = <not set>", key),
166 }
167 }
168 }
169
170 // ==================== PRACTICAL EXAMPLE ====================
171
172 println!("\n[TEAM] Practical example: Setting up repository for a team...");
173
174 // Configure repository for team development
175 repo.config().set("user.name", "Team Member")?;
176 repo.config().set("user.email", "team@company.com")?;
177 repo.config().set("core.autocrlf", "input")?;
178 repo.config().set("core.safecrlf", "true")?;
179 repo.config().set("pull.rebase", "true")?;
180 repo.config().set("push.default", "current")?;
181 repo.config().set("init.defaultBranch", "main")?;
182
183 println!("Configured repository for team development");
184
185 // Create another commit with the team configuration
186 fs::write(
187 repo_path.join("team.md"),
188 "# Team Development\n\nThis repository is configured for team development.",
189 )?;
190 repo.add(&["team.md"])?;
191 let team_commit = repo.commit("Add team development documentation")?;
192
193 println!("Created team commit: {}", team_commit.short());
194
195 // Final verification
196 let (final_name, final_email) = repo.config().get_user()?;
197 println!("\n[FINAL] Final repository configuration:");
198 println!(" User: {} <{}>", final_name, final_email);
199 println!(" Repository configured for team development workflow");
200
201 // ==================== CLEANUP ====================
202
203 println!("\n[CLEANUP] Cleaning up...");
204 fs::remove_dir_all(&repo_path).expect("Failed to clean up example");
205 println!("Example completed successfully!");
206
207 Ok(())
208}
Sourcepub fn unset(&self, key: &str) -> Result<()>
pub fn unset(&self, key: &str) -> Result<()>
Remove a git configuration value from this repository
§Arguments
key
- The configuration key to remove
§Example
use rustic_git::Repository;
use std::{env, fs};
let test_path = env::temp_dir().join("config_unset_test");
if test_path.exists() {
fs::remove_dir_all(&test_path).unwrap();
}
let repo = Repository::init(&test_path, false)?;
repo.config().set("test.value", "temporary")?;
repo.config().unset("test.value")?;
// Clean up
fs::remove_dir_all(&test_path).unwrap();
Examples found in repository?
examples/config_operations.rs (line 118)
14fn main() -> Result<()> {
15 println!("Rustic Git - Repository Configuration Operations Example\n");
16
17 // Use a temporary directory for this example
18 let repo_path = env::temp_dir().join("rustic_git_config_example");
19
20 // Clean up any previous run
21 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 println!("Initializing new repository at: {}", repo_path.display());
26
27 // Initialize a new repository
28 let repo = Repository::init(&repo_path, false)?;
29
30 // ==================== USER CONFIGURATION ====================
31
32 println!("\n[CONFIG] Configuring git user settings...");
33
34 // Set user configuration (convenience method)
35 repo.config()
36 .set_user("Alice Developer", "alice@example.com")?;
37 println!("Set user configuration");
38
39 // Verify user configuration
40 let (name, email) = repo.config().get_user()?;
41 println!("Current user: {} <{}>", name, email);
42
43 // ==================== GENERAL CONFIGURATION ====================
44
45 println!("\n[CONFIG] Setting repository configuration values...");
46
47 // Set various git configuration values
48 repo.config().set("core.autocrlf", "false")?;
49 repo.config().set("core.ignorecase", "true")?;
50 repo.config().set("pull.rebase", "true")?;
51 repo.config().set("push.default", "simple")?;
52 repo.config().set("branch.autosetupmerge", "always")?;
53
54 println!("Set core configuration values");
55
56 // Get and display configuration values
57 println!("\n[CONFIG] Current repository configuration:");
58
59 let configs = [
60 "core.autocrlf",
61 "core.ignorecase",
62 "pull.rebase",
63 "push.default",
64 "branch.autosetupmerge",
65 ];
66
67 for config_key in &configs {
68 match repo.config().get(config_key) {
69 Ok(value) => println!(" {} = {}", config_key, value),
70 Err(_) => println!(" {} = <not set>", config_key),
71 }
72 }
73
74 // ==================== CONFIGURATION WITH COMMITS ====================
75
76 println!("\n[COMMIT] Testing configuration with commit operations...");
77
78 // Create a test file
79 let test_file_path = repo_path.join("test.txt");
80 fs::write(
81 &test_file_path,
82 "Hello from rustic-git configuration example!",
83 )?;
84 println!("Created test file: test.txt");
85
86 // Stage the file
87 repo.add(&["test.txt"])?;
88 println!("Staged test.txt");
89
90 // Create a commit (this will use our configured user)
91 let commit_hash = repo.commit("Add test file with configuration example")?;
92 println!("Created commit: {}", commit_hash.short());
93
94 // ==================== CONFIGURATION MODIFICATION ====================
95
96 println!("\n[UPDATE] Modifying configuration values...");
97
98 // Change some configuration values
99 repo.config().set("core.autocrlf", "true")?;
100 repo.config()
101 .set("user.email", "alice.developer@newcompany.com")?;
102
103 println!("Updated configuration values");
104
105 // Display updated values
106 let autocrlf = repo.config().get("core.autocrlf")?;
107 let (updated_name, updated_email) = repo.config().get_user()?;
108
109 println!("Updated configuration:");
110 println!(" core.autocrlf = {}", autocrlf);
111 println!(" user: {} <{}>", updated_name, updated_email);
112
113 // ==================== CONFIGURATION REMOVAL ====================
114
115 println!("\n[REMOVE] Removing configuration values...");
116
117 // Remove a configuration value
118 repo.config().unset("branch.autosetupmerge")?;
119 println!("Removed branch.autosetupmerge");
120
121 // Try to get the removed value (should fail)
122 match repo.config().get("branch.autosetupmerge") {
123 Ok(value) => println!("Unexpected: branch.autosetupmerge = {}", value),
124 Err(_) => println!("Confirmed: branch.autosetupmerge is not set"),
125 }
126
127 // ==================== ADVANCED CONFIGURATION ====================
128
129 println!("\n[ADVANCED] Setting advanced configuration...");
130
131 // Set some advanced git configuration
132 repo.config().set("diff.tool", "vimdiff")?;
133 repo.config().set("merge.tool", "vimdiff")?;
134 repo.config().set("alias.st", "status")?;
135 repo.config().set("alias.co", "checkout")?;
136 repo.config().set("alias.br", "branch")?;
137 repo.config().set("alias.ci", "commit")?;
138
139 println!("Set advanced configuration (diff/merge tools and aliases)");
140
141 // Display all custom configuration
142 println!("\n[SUMMARY] Complete repository configuration summary:");
143
144 let all_configs = [
145 ("User", vec![("user.name", ""), ("user.email", "")]),
146 ("Core", vec![("core.autocrlf", ""), ("core.ignorecase", "")]),
147 ("Workflow", vec![("pull.rebase", ""), ("push.default", "")]),
148 ("Tools", vec![("diff.tool", ""), ("merge.tool", "")]),
149 (
150 "Aliases",
151 vec![
152 ("alias.st", ""),
153 ("alias.co", ""),
154 ("alias.br", ""),
155 ("alias.ci", ""),
156 ],
157 ),
158 ];
159
160 for (category, configs) in &all_configs {
161 println!("\n {}:", category);
162 for (key, _) in configs {
163 match repo.config().get(key) {
164 Ok(value) => println!(" {} = {}", key, value),
165 Err(_) => println!(" {} = <not set>", key),
166 }
167 }
168 }
169
170 // ==================== PRACTICAL EXAMPLE ====================
171
172 println!("\n[TEAM] Practical example: Setting up repository for a team...");
173
174 // Configure repository for team development
175 repo.config().set("user.name", "Team Member")?;
176 repo.config().set("user.email", "team@company.com")?;
177 repo.config().set("core.autocrlf", "input")?;
178 repo.config().set("core.safecrlf", "true")?;
179 repo.config().set("pull.rebase", "true")?;
180 repo.config().set("push.default", "current")?;
181 repo.config().set("init.defaultBranch", "main")?;
182
183 println!("Configured repository for team development");
184
185 // Create another commit with the team configuration
186 fs::write(
187 repo_path.join("team.md"),
188 "# Team Development\n\nThis repository is configured for team development.",
189 )?;
190 repo.add(&["team.md"])?;
191 let team_commit = repo.commit("Add team development documentation")?;
192
193 println!("Created team commit: {}", team_commit.short());
194
195 // Final verification
196 let (final_name, final_email) = repo.config().get_user()?;
197 println!("\n[FINAL] Final repository configuration:");
198 println!(" User: {} <{}>", final_name, final_email);
199 println!(" Repository configured for team development workflow");
200
201 // ==================== CLEANUP ====================
202
203 println!("\n[CLEANUP] Cleaning up...");
204 fs::remove_dir_all(&repo_path).expect("Failed to clean up example");
205 println!("Example completed successfully!");
206
207 Ok(())
208}
Auto Trait Implementations§
impl<'a> Freeze for RepoConfig<'a>
impl<'a> RefUnwindSafe for RepoConfig<'a>
impl<'a> Send for RepoConfig<'a>
impl<'a> Sync for RepoConfig<'a>
impl<'a> Unpin for RepoConfig<'a>
impl<'a> UnwindSafe for RepoConfig<'a>
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