Create a branch from a specific commit
(
repo_path: &Path,
branch_name: &str,
commit_sha: &str,
)
| 360 | |
| 361 | /// Create a branch from a specific commit |
| 362 | pub async fn create_branch_from_commit( |
| 363 | repo_path: &Path, |
| 364 | branch_name: &str, |
| 365 | commit_sha: &str, |
| 366 | ) -> Result<(), String> { |
| 367 | tokio::task::spawn_blocking({ |
| 368 | let repo_path = repo_path.to_owned(); |
| 369 | let branch_name = branch_name.to_owned(); |
| 370 | let commit_sha = commit_sha.to_owned(); |
| 371 | move || -> Result<(), String> { |
| 372 | let repo = Repository::open(&repo_path) |
| 373 | .map_err(|e| format!("Failed to open repository: {e}"))?; |
| 374 | |
| 375 | let oid = |
| 376 | git2::Oid::from_str(&commit_sha).map_err(|e| format!("Invalid commit SHA: {e}"))?; |
| 377 | |
| 378 | let commit = repo |
| 379 | .find_commit(oid) |
| 380 | .map_err(|e| format!("Failed to find commit {commit_sha}: {e}"))?; |
| 381 | |
| 382 | repo.branch(&branch_name, &commit, false) |
| 383 | .map_err(|e| format!("Failed to create branch: {e}"))?; |
| 384 | |
| 385 | repo.set_head(&format!("refs/heads/{branch_name}")) |
| 386 | .map_err(|e| format!("Failed to checkout branch: {e}"))?; |
| 387 | |
| 388 | // Force update the working directory to match the commit |
| 389 | let mut checkout_opts = git2::build::CheckoutBuilder::new(); |
| 390 | checkout_opts.force(); |
| 391 | repo.checkout_head(Some(&mut checkout_opts)) |
| 392 | .map_err(|e| format!("Failed to update working directory: {e}"))?; |
| 393 | |
| 394 | Ok(()) |
| 395 | } |
| 396 | }) |
| 397 | .await |
| 398 | .map_err(|e| format!("Task join error: {e}"))? |
| 399 | } |
| 400 | |
| 401 | /// Get list of all non-ignored files in the working directory |
| 402 | /// This includes tracked files (with or without modifications), staged files, and untracked files |