| 187 | } |
| 188 | |
| 189 | pub async fn fetch_branch( |
| 190 | repo_path: &Path, |
| 191 | remote_name: &str, |
| 192 | branch_name: &str, |
| 193 | ) -> Result<(), String> { |
| 194 | tokio::task::spawn_blocking({ |
| 195 | let repo_path = repo_path.to_owned(); |
| 196 | let remote_name = remote_name.to_owned(); |
| 197 | let branch_name = branch_name.to_owned(); |
| 198 | move || -> Result<(), String> { |
| 199 | let repo = Repository::open(&repo_path) |
| 200 | .map_err(|e| format!("Failed to open repository: {e}"))?; |
| 201 | |
| 202 | let remote = repo |
| 203 | .find_remote(&remote_name) |
| 204 | .map_err(|e| format!("Failed to find remote: {e}"))?; |
| 205 | |
| 206 | let url = remote |
| 207 | .url() |
| 208 | .ok_or_else(|| "Remote has no URL".to_string())?; |
| 209 | |
| 210 | let output = std::process::Command::new("git") |
| 211 | .current_dir(&repo_path) |
| 212 | .arg("fetch") |
| 213 | .arg("--no-recurse-submodules") |
| 214 | .arg(url) |
| 215 | .arg(format!("refs/heads/{branch_name}:refs/heads/{branch_name}")) |
| 216 | .output() |
| 217 | .map_err(|e| format!("Failed to execute git fetch: {e}"))?; |
| 218 | |
| 219 | if !output.status.success() { |
| 220 | return Err(format!( |
| 221 | "Failed to fetch changes: {}", |
| 222 | String::from_utf8_lossy(&output.stderr) |
| 223 | )); |
| 224 | } |
| 225 | |
| 226 | Ok(()) |
| 227 | } |
| 228 | }) |
| 229 | .await |
| 230 | .map_err(|e| format!("Task join error: {e}"))? |
| 231 | } |
| 232 | |
| 233 | pub async fn remove_remote(repo_path: &Path, remote_name: &str) -> Result<(), String> { |
| 234 | tokio::task::spawn_blocking({ |