diff --git a/crates/tabby-git/src/lib.rs b/crates/tabby-git/src/lib.rs index affab71ea926..a8675f35157a 100644 --- a/crates/tabby-git/src/lib.rs +++ b/crates/tabby-git/src/lib.rs @@ -86,7 +86,20 @@ pub fn get_head_name(root: &Path) -> anyhow::Result { Ok(name.to_string()) } +/// Returns the URL with credentials (username and password) removed, for safe logging. +fn mask_url_credentials(url: &str) -> String { + url::Url::parse(url) + .map(|mut u| { + let _ = u.set_password(None); + let _ = u.set_username(""); + u.to_string() + }) + .unwrap_or_else(|_| url.to_string()) +} + pub fn sync_refs(root: &Path, url: &str, refs: &Vec) -> anyhow::Result<()> { + let display_url = mask_url_credentials(url); + if !root.exists() { fs::create_dir_all(root)?; let status = Command::new("git") @@ -100,13 +113,23 @@ pub fn sync_refs(root: &Path, url: &str, refs: &Vec) -> anyhow::Result<( if code != 0 { warn!( "Failed to clone `{}`. Please check your repository configuration.", - url + display_url ); fs::remove_dir_all(root).expect("Failed to remove directory"); - bail!("Failed to clone `{}`", url); + bail!("Failed to clone `{}`", display_url); } } + } else { + // Update the remote URL so that credential changes in config take effect + // without requiring a full re-clone. + let status = Command::new("git") + .current_dir(root) + .args(["remote", "set-url", "origin", url]) + .status(); + if let Err(e) = status { + warn!("Failed to update remote URL for `{}`: {}", display_url, e); + } } for ref_name in refs { diff --git a/crates/tabby-index/src/code/repository.rs b/crates/tabby-index/src/code/repository.rs index 04b5af6b6efb..2252e3db23c3 100644 --- a/crates/tabby-index/src/code/repository.rs +++ b/crates/tabby-index/src/code/repository.rs @@ -19,7 +19,7 @@ impl RepositoryExt for CodeRepository { fn sync(&self) -> anyhow::Result<()> { if let Err(e) = sync_refs( self.dir().as_path(), - &self.canonical_git_url(), + &self.git_url, &self.git_refs, ) { logkit::error!("Failed to clone repository: {}", e);