Remote

Struct Remote 

Source
pub struct Remote {
    pub name: String,
    pub fetch_url: String,
    pub push_url: Option<String>,
}
Expand description

Represents a Git remote with its URLs

Fields§

§name: String

The name of the remote (e.g., “origin”)

§fetch_url: String

The fetch URL for the remote

§push_url: Option<String>

The push URL for the remote (if different from fetch URL)

Implementations§

Source§

impl Remote

Source

pub fn new(name: String, fetch_url: String, push_url: Option<String>) -> Self

Create a new Remote instance

Source

pub fn push_url(&self) -> &str

Get the effective push URL (returns push_url if set, otherwise fetch_url)

Examples found in repository?
examples/remote_operations.rs (line 245)
15fn main() -> Result<()> {
16    println!("Rustic Git - Remote Operations Example\n");
17
18    let base_path = env::temp_dir().join("rustic_git_remote_example");
19    let repo_path = base_path.join("main_repo");
20    let clone_path = base_path.join("cloned_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 remote demonstrations...");
32    let repo = Repository::init(&repo_path, false)?;
33    println!("Repository initialized at: {}", repo_path.display());
34
35    // Create initial commit so we have something to work with
36    fs::write(
37        repo_path.join("README.md"),
38        "# Remote Operations Demo\n\nDemonstrating rustic-git remote management capabilities.",
39    )?;
40    repo.add(&["README.md"])?;
41    repo.commit("Initial commit for remote operations demo")?;
42    println!("Created initial commit\n");
43
44    println!("=== Basic Remote Management ===\n");
45
46    // Check initial remote state
47    println!("Checking initial remote state:");
48    let remotes = repo.list_remotes()?;
49    println!("   Initial remotes count: {}", remotes.len());
50    if remotes.is_empty() {
51        println!("   No remotes configured (as expected)");
52    }
53    println!();
54
55    // Add remotes
56    println!("Adding remotes...");
57    repo.add_remote("origin", "https://github.com/user/demo-repo.git")?;
58    println!("   Added 'origin' remote");
59
60    repo.add_remote("upstream", "https://github.com/original/demo-repo.git")?;
61    println!("   Added 'upstream' remote");
62
63    repo.add_remote("fork", "git@github.com:user/fork-repo.git")?;
64    println!("   Added 'fork' remote (SSH URL)");
65    println!();
66
67    // List remotes
68    println!("Listing all remotes:");
69    let remotes = repo.list_remotes()?;
70    println!("   Total remotes: {}", remotes.len());
71
72    for remote in remotes.iter() {
73        println!("   {} -> {}", remote.name, remote.fetch_url);
74        if let Some(push_url) = &remote.push_url {
75            println!("     Push URL: {}", push_url);
76        }
77    }
78    println!();
79
80    // Get specific remote URLs
81    println!("Getting specific remote URLs:");
82    let origin_url = repo.get_remote_url("origin")?;
83    println!("   Origin URL: {}", origin_url);
84
85    let upstream_url = repo.get_remote_url("upstream")?;
86    println!("   Upstream URL: {}", upstream_url);
87    println!();
88
89    // Rename a remote
90    println!("Renaming 'fork' remote to 'my-fork'...");
91    repo.rename_remote("fork", "my-fork")?;
92    println!("   Remote renamed successfully");
93
94    // Verify rename
95    let remotes = repo.list_remotes()?;
96    let renamed_remote = remotes.find("my-fork");
97    match renamed_remote {
98        Some(remote) => println!(
99            "   Found renamed remote: {} -> {}",
100            remote.name, remote.fetch_url
101        ),
102        None => println!("   Error: Could not find renamed remote"),
103    }
104
105    // Verify old name is gone
106    if remotes.find("fork").is_none() {
107        println!("   Confirmed: old 'fork' remote no longer exists");
108    }
109    println!();
110
111    println!("=== Remote Operations with Options ===\n");
112
113    // Demonstrate fetch options
114    println!("Fetch operations (simulated - no actual network calls):");
115    println!("   Basic fetch from origin:");
116    match repo.fetch("origin") {
117        Ok(_) => println!("     ✓ Fetch completed successfully"),
118        Err(e) => println!("     ⚠ Fetch failed (expected): {}", e),
119    }
120
121    println!("   Fetch with options (prune + tags):");
122    let fetch_options = FetchOptions::new().with_prune().with_tags();
123    match repo.fetch_with_options("origin", fetch_options) {
124        Ok(_) => println!("     ✓ Fetch with options completed successfully"),
125        Err(e) => println!("     ⚠ Fetch with options failed (expected): {}", e),
126    }
127
128    println!("   Fetch all remotes:");
129    let fetch_all_options = FetchOptions::new().with_all_remotes();
130    match repo.fetch_with_options("", fetch_all_options) {
131        Ok(_) => println!("     ✓ Fetch all completed successfully"),
132        Err(e) => println!("     ⚠ Fetch all failed (expected): {}", e),
133    }
134    println!();
135
136    // Demonstrate push options
137    println!("Push operations (simulated - no actual network calls):");
138    println!("   Basic push to origin:");
139    match repo.push("origin", "main") {
140        Ok(_) => println!("     ✓ Push completed successfully"),
141        Err(e) => println!("     ⚠ Push failed (expected): {}", e),
142    }
143
144    println!("   Push with upstream tracking:");
145    let push_options = PushOptions::new().with_set_upstream();
146    match repo.push_with_options("origin", "main", push_options) {
147        Ok(_) => println!("     ✓ Push with upstream completed successfully"),
148        Err(e) => println!("     ⚠ Push with upstream failed (expected): {}", e),
149    }
150
151    println!("   Force push with tags:");
152    let force_push_options = PushOptions::new().with_force().with_tags();
153    match repo.push_with_options("my-fork", "feature-branch", force_push_options) {
154        Ok(_) => println!("     ✓ Force push with tags completed successfully"),
155        Err(e) => println!("     ⚠ Force push with tags failed (expected): {}", e),
156    }
157    println!();
158
159    println!("=== Clone Operations ===\n");
160
161    // Note: We can't actually clone from the URLs we added since they're fake,
162    // but we can demonstrate the API and show how it would work
163    println!("Clone operation demonstration:");
164    println!("   Attempting to clone a repository...");
165
166    // This will fail since the URL doesn't exist, but demonstrates the API
167    match Repository::clone("https://github.com/nonexistent/fake-repo.git", &clone_path) {
168        Ok(_repo) => {
169            println!("     ✓ Clone completed successfully");
170            println!("     Cloned repository location: {}", clone_path.display());
171        }
172        Err(e) => {
173            println!("     ⚠ Clone failed (expected for demo): {}", e);
174            println!("     In real usage, provide a valid repository URL");
175        }
176    }
177    println!();
178
179    println!("=== Error Handling and Edge Cases ===\n");
180
181    // Test error cases
182    println!("Testing error conditions:");
183
184    // Try to get URL for non-existent remote
185    println!("   Getting URL for non-existent remote:");
186    match repo.get_remote_url("nonexistent") {
187        Ok(url) => println!("     Unexpected success: {}", url),
188        Err(e) => println!("     ✓ Expected error: {}", e),
189    }
190
191    // Try to remove non-existent remote
192    println!("   Removing non-existent remote:");
193    match repo.remove_remote("nonexistent") {
194        Ok(_) => println!("     Unexpected success"),
195        Err(e) => println!("     ✓ Expected error: {}", e),
196    }
197
198    // Try to add duplicate remote
199    println!("   Adding duplicate remote:");
200    match repo.add_remote("origin", "https://github.com/duplicate/repo.git") {
201        Ok(_) => println!("     Unexpected success (git allows URL changes)"),
202        Err(e) => println!("     Error: {}", e),
203    }
204    println!();
205
206    println!("=== Remote Cleanup Operations ===\n");
207
208    // Remove remotes one by one
209    println!("Removing remotes:");
210
211    println!("   Removing 'upstream' remote...");
212    repo.remove_remote("upstream")?;
213
214    println!("   Removing 'my-fork' remote...");
215    repo.remove_remote("my-fork")?;
216
217    println!("   Removing 'origin' remote...");
218    repo.remove_remote("origin")?;
219
220    // Verify all remotes are gone
221    let final_remotes = repo.list_remotes()?;
222    println!("   Final remote count: {}", final_remotes.len());
223
224    if final_remotes.is_empty() {
225        println!("   ✓ All remotes successfully removed");
226    } else {
227        println!("   ⚠ Some remotes still remain:");
228        for remote in final_remotes.iter() {
229            println!("     - {}", remote.name);
230        }
231    }
232    println!();
233
234    println!("=== Advanced Remote Information ===\n");
235
236    // Re-add a remote for advanced operations demo
237    repo.add_remote("demo", "https://github.com/demo/advanced-repo.git")?;
238
239    // Show comprehensive remote information
240    let remotes = repo.list_remotes()?;
241    for remote in remotes.iter() {
242        println!("Remote Details:");
243        println!("   Name: {}", remote.name);
244        println!("   Fetch URL: {}", remote.fetch_url);
245        println!("   Push URL: {}", remote.push_url());
246        println!("   Uses separate push URL: {}", remote.push_url.is_some());
247
248        // Validate URL format
249        if remote.fetch_url.starts_with("https://") {
250            println!("   Protocol: HTTPS");
251        } else if remote.fetch_url.starts_with("git@") {
252            println!("   Protocol: SSH");
253        } else if remote.fetch_url.starts_with("git://") {
254            println!("   Protocol: Git");
255        } else {
256            println!("   Protocol: Other/Local");
257        }
258    }
259    println!();
260
261    println!("=== Summary ===\n");
262
263    println!("Remote operations demonstration completed!");
264    println!("  Repository: {}", repo_path.display());
265
266    let final_remotes = repo.list_remotes()?;
267    println!("  Final remotes configured: {}", final_remotes.len());
268
269    for remote in final_remotes.iter() {
270        println!("    - {} ({})", remote.name, remote.fetch_url);
271    }
272
273    println!("\nOperations demonstrated:");
274    println!("  ✓ Adding remotes with different URL formats");
275    println!("  ✓ Listing and inspecting remotes");
276    println!("  ✓ Getting specific remote URLs");
277    println!("  ✓ Renaming remotes");
278    println!("  ✓ Removing remotes");
279    println!("  ✓ Fetch operations with options");
280    println!("  ✓ Push operations with options");
281    println!("  ✓ Clone API demonstration");
282    println!("  ✓ Error handling for invalid operations");
283    println!("  ✓ Remote information analysis");
284
285    // Clean up
286    println!("\nCleaning up example repositories...");
287    fs::remove_dir_all(&base_path)?;
288    println!("Remote operations example completed!");
289
290    Ok(())
291}

Trait Implementations§

Source§

impl Clone for Remote

Source§

fn clone(&self) -> Remote

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Remote

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for Remote

Source§

fn eq(&self, other: &Remote) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for Remote

Auto Trait Implementations§

§

impl Freeze for Remote

§

impl RefUnwindSafe for Remote

§

impl Send for Remote

§

impl Sync for Remote

§

impl Unpin for Remote

§

impl UnwindSafe for Remote

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.