You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sudden Performance Degradation in Async RepoBuilder::clone (approx. 10 min delay)
Problem Description:
I am experiencing a significant and sudden performance degradation when cloning repositories using git2-rs. An operation that previously completed quickly now takes approximately 10 minutes. This slowdown started occurring recently without any intentional changes to my code or explicit dependency updates (Cargo.lock appears unchanged relative to when it was working fast).
Cloning the same repository using command-line git or downloading related resources via curl with the same token remains fast, suggesting the issue is specific to the git2-rs interaction or its underlying libgit2 usage in my setup, potentially related to the async context or authentication.
Environment:
git2-rs version: [0.20.1]
libgit2-sys version: [0.18.1+1.9.0]
Rust Version: rustc 1.86.0**]
Operating System: [e.g., Linux Ubuntu 22.04]
Code Snippet:
Here is the relevant function performing the clone:
fntest_git2(repo_url:&str,dest_path:&Path,token:Option<String>){println!("\n=== Testing git2 library (with detailed progress) ===");// Optional: Clean up destination directory before cloning if it exists// This prevents errors if the directory exists and is not empty,// especially since CheckoutBuilder.force() might be needed.if dest_path.exists(){println!("Removing existing directory: {}", dest_path.display());ifletErr(e) = std::fs::remove_dir_all(dest_path){println!("Warning: Failed to remove existing directory {}: {}", dest_path.display(), e);// Decide if you want to proceed or return an error here}}let start = Instant::now();let result = clone_with_git2(repo_url, dest_path, token);let elapsed = start.elapsed();match result {Ok(_) => println!("\ngit2 clone successful in {:.4} seconds", elapsed.as_secs_f64()),// Added newline for cleaner outputErr(e) => println!("\ngit2 clone failed: {:?}", e),// Added newline}}fnclone_with_git2(repo_url:&str,dest_path:&Path,token:Option<String>) -> Result<Repository, git2::Error>{// --- 1. Setup Fetch Options ---letmut fetch_options = FetchOptions::new();
fetch_options.update_fetchhead(false);// Don't update FETCH_HEAD (minor optimization)
fetch_options.depth(1);// Shallow clone - only get the latest commit// --- 2. Setup Remote Callbacks (Authentication & Fetch Progress) ---letmut callbacks = RemoteCallbacks::new();// Detailed Transfer (Fetch) Progress Reporting
callbacks.transfer_progress(|progress:Progress| {let network_pct = if progress.total_objects() > 0{(100* progress.received_objects()) / progress.total_objects()}else{0};let index_pct = if progress.total_objects() > 0{(100* progress.indexed_objects()) / progress.total_objects()}else{0};let kbytes = progress.received_bytes() / 1024;// Print progress information without a newline, using '\r' to overwrite the lineprint!("Fetch Progress: net {:3}% ({:4} kb, {:>5}/{:<5}) / idx {:3}% ({:>5}/{:<5})\r",
network_pct,
kbytes,
progress.received_objects(),
progress.total_objects(),
index_pct,
progress.indexed_objects(),
progress.total_objects());// Flush stdout to ensure the progress is displayed immediately
io::stdout().flush().unwrap();true// Return true to continue the transfer});// Authentication Callback (if token is provided)ifletSome(token_str) = token {// Clone the token string so it can be moved into the closurelet token_clone = token_str.clone();
callbacks.credentials(move |_, _, _| {// This closure will be called by libgit2 when authentication is needed// println!("Credentials callback invoked"); // Uncomment for debugging auth callsCred::userpass_plaintext("oauth2",&token_clone)});}// Apply the callbacks to the fetch options
fetch_options.remote_callbacks(callbacks);// --- 3. Setup Checkout Builder (Checkout Progress) ---letmut checkout_builder = CheckoutBuilder::new();
checkout_builder.force();// Force checkout to overwrite files if they exist// Equivalent to `git clone --force` behavior.// Remove if you want it to fail if the directory has conflicting files.// Detailed Checkout Progress Reporting
checkout_builder.progress(|path, current, total| {let path_str = path.map(|p| p.to_string_lossy()).unwrap_or_default();// Print progress, overwriting the line with '\r'print!("Checkout Progress: [{}/{}] {}\r", current, total, path_str);// Flush stdout to ensure the progress is displayed immediately
io::stdout().flush().unwrap();});// --- 4. Setup Repo Builder (combines fetch and checkout) ---letmut repo_builder = RepoBuilder::new();
repo_builder.bare(false);// Ensure it's not a bare repo (we want a working directory)
repo_builder.fetch_options(fetch_options);// Use the fetch options configured above
repo_builder.with_checkout(checkout_builder);// Use the checkout builder configured aboveprintln!("Starting git2 clone (shallow, depth=1) from {} to {}", repo_url, dest_path.display());// --- 5. Perform the Clone ---// This call will use the configured fetch_options (including callbacks)// and the configured checkout_builder (including its progress callback).let result = repo_builder.clone(repo_url, dest_path);// Print a newline character after the progress indicators are done to avoid messing up subsequent outputprintln!();
result // Return the result of the clone operation}
Could there be any known issues, potential deadlocks, or changes in recent libgit2 or git2-rs versions that might cause such a delay, especially when interacting with authentication callbacks or specific server responses within an async context (even if correctly using spawn_blocking)? Are there recommended steps for diagnosing network or callback-related hangs within libgit2 from git2-rs (e.g., enabling libgit2 tracing)?
Adding detailed progress callbacks (for fetch and checkout, as shown in other examples) might provide more granular clues, but I wanted to report the sudden change and the potential async interaction issue first.
Thank you for your time and insights!
The text was updated successfully, but these errors were encountered:
mrab72
changed the title
Clone process is very slow
Sudden ~10 min Delay in RepoBuilder::clone Without Code/Dependency Changes
Apr 30, 2025
Sudden Performance Degradation in Async
RepoBuilder::clone
(approx. 10 min delay)Problem Description:
I am experiencing a significant and sudden performance degradation when cloning repositories using
git2-rs
. An operation that previously completed quickly now takes approximately 10 minutes. This slowdown started occurring recently without any intentional changes to my code or explicit dependency updates (Cargo.lock
appears unchanged relative to when it was working fast).Cloning the same repository using command-line
git
or downloading related resources viacurl
with the same token remains fast, suggesting the issue is specific to thegit2-rs
interaction or its underlyinglibgit2
usage in my setup, potentially related to the async context or authentication.Environment:
git2-rs
version: [0.20.1]libgit2-sys
version: [0.18.1+1.9.0]Code Snippet:
Here is the relevant function performing the clone:
Could there be any known issues, potential deadlocks, or changes in recent libgit2 or git2-rs versions that might cause such a delay, especially when interacting with authentication callbacks or specific server responses within an async context (even if correctly using spawn_blocking)? Are there recommended steps for diagnosing network or callback-related hangs within
libgit2
fromgit2-rs
(e.g., enabling libgit2 tracing)?Adding detailed progress callbacks (for fetch and checkout, as shown in other examples) might provide more granular clues, but I wanted to report the sudden change and the potential async interaction issue first.
Thank you for your time and insights!
The text was updated successfully, but these errors were encountered: