Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 39 additions & 16 deletions libra/src/command/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ use std::cell::Cell;
use std::path::PathBuf;
use std::{env, fs};

const ORIGIN: &str = "origin"; // default remote name, prevent spelling mistakes

#[derive(Parser, Debug)]
pub struct CloneArgs {
/// The remote repository location to clone from, usually a URL with HTTPS or SSH
Expand Down Expand Up @@ -98,10 +96,10 @@ pub async fn execute(args: CloneArgs) {
name: "origin".to_string(),
url: remote_repo.clone(),
};
fetch::fetch_repository(remote_config, args.branch.clone()).await;
fetch::fetch_repository(remote_config.clone(), args.branch.clone()).await;

/* setup */
if let Err(e) = setup_repository(remote_repo.clone(), args.branch.clone()).await {
if let Err(e) = setup_repository(remote_config, args.branch.clone()).await {
eprintln!("fatal: {}", e);
return;
}
Expand All @@ -112,11 +110,11 @@ pub async fn execute(args: CloneArgs) {
/// Sets up the local repository after a clone by configuring the remote,
/// setting up the initial branch and HEAD, and creating the first reflog entry.
async fn setup_repository(
remote_repo: String,
remote_config: RemoteConfig,
specified_branch: Option<String>,
) -> Result<(), String> {
let db = crate::internal::db::get_db_conn_instance().await;
let remote_head = Head::remote_current_with_conn(db, ORIGIN).await;
let remote_head = Head::remote_current_with_conn(db, &remote_config.name).await;

// Determine which branch to check out.
let branch_to_checkout = match specified_branch {
Expand All @@ -131,13 +129,14 @@ async fn setup_repository(
};

if let Some(branch_name) = branch_to_checkout {
let origin_branch = Branch::find_branch_with_conn(db, &branch_name, Some(ORIGIN))
.await
.ok_or_else(|| format!("fatal: remote branch '{}' not found.", branch_name))?;
let origin_branch =
Branch::find_branch_with_conn(db, &branch_name, Some(&remote_config.name))
.await
.ok_or_else(|| format!("fatal: remote branch '{}' not found.", branch_name))?;

// Prepare the reflog context *before* the transaction
let action = ReflogAction::Clone {
from: remote_repo.clone(),
from: remote_config.url.clone(),
};

let context = ReflogContext {
Expand Down Expand Up @@ -174,12 +173,24 @@ async fn setup_repository(
&merge_ref,
)
.await;
Config::insert_with_conn(txn, "branch", Some(&branch_name), "remote", ORIGIN)
.await;
Config::insert_with_conn(
txn,
"branch",
Some(&branch_name),
"remote",
&remote_config.name,
)
.await;

// 4. Configure the remote URL
Config::insert_with_conn(txn, "remote", Some(ORIGIN), "url", &remote_repo)
.await;
Config::insert_with_conn(
txn,
"remote",
Some(&remote_config.name),
"url",
&remote_config.url,
)
.await;
Ok(())
})
},
Expand All @@ -200,13 +211,25 @@ async fn setup_repository(
println!("warning: You appear to have cloned an empty repository.");

// We only need to set the remote URL. No reflog is created as there are no commits.
Config::insert("remote", Some(ORIGIN), "url", &remote_repo).await;
Config::insert(
"remote",
Some(&remote_config.name),

Copilot AI Aug 27, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line correctly uses &remote_config.name, but it's inconsistent with line 191 which uses hardcoded ORIGIN. Both should use the same approach for consistency.

Copilot uses AI. Check for mistakes.
"url",
&remote_config.url,
)
.await;

// Optionally set up a default branch config for a future 'master' or 'main'
let default_branch = "master";
let merge_ref = format!("refs/heads/{}", default_branch);
Config::insert("branch", Some(default_branch), "merge", &merge_ref).await;
Config::insert("branch", Some(default_branch), "remote", ORIGIN).await;
Config::insert(
"branch",
Some(default_branch),
"remote",
&remote_config.name,
)
.await;
}

Ok(())
Expand Down
28 changes: 19 additions & 9 deletions libra/src/command/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use tokio::io::{AsyncRead, AsyncReadExt};
use tokio_util::io::StreamReader;
use url::Url;

use crate::command::load_object;
use crate::command::{load_object, HEAD};
use crate::internal::db::get_db_conn_instance;
use crate::internal::reflog;
use crate::internal::reflog::{zero_sha1, ReflogAction, ReflogContext, ReflogError};
Expand Down Expand Up @@ -235,24 +235,34 @@ pub async fn fetch_repository(remote_config: RemoteConfig, branch: Option<String

// Determine the full ref name (e.g., "refs/remotes/origin/main")
if let Some(branch_name) = r._ref.strip_prefix("refs/heads/") {
full_ref_name =
format!("refs/remotes/{}/{}", remote_config.name, branch_name);
full_ref_name = branch_name.to_owned();
} else if let Some(mr_name) = r._ref.strip_prefix("refs/mr/") {
// Handle merge requests if your system supports them
full_ref_name =
format!("refs/remotes/{}/mr/{}", remote_config.name, mr_name);
full_ref_name = format!("mr/{}", mr_name);
} else if r._ref == HEAD {

Copilot AI Aug 27, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comparison r._ref == HEAD will fail because HEAD is imported as a constant but r._ref is likely a string literal "HEAD". This should be r._ref == "HEAD" or ensure HEAD constant matches the expected string value.

Suggested change
} else if r._ref == HEAD {
} else if r._ref == "HEAD" {

Copilot uses AI. Check for mistakes.
continue;
} else {
tracing::warn!("Unsupported ref type during fetch: {}", r._ref);
continue; // Skip unsupported ref types
}

// Get the old OID *before* updating the branch
let old_oid = Branch::find_branch_with_conn(txn, &full_ref_name, None)
.await
.map_or(zero_sha1().to_string(), |b| b.commit.to_string());
let old_oid = Branch::find_branch_with_conn(
txn,
&full_ref_name,
Some(&remote_config.name),
)
.await
.map_or(zero_sha1().to_string(), |b| b.commit.to_string());

// Update the branch pointer
Branch::update_branch_with_conn(txn, &full_ref_name, &r._hash, None).await;
Branch::update_branch_with_conn(
txn,
&full_ref_name,
&r._hash,
Some(&remote_config.name),
)
.await;

// Prepare and insert the reflog entry for this specific remote-tracking branch
let context = ReflogContext {
Expand Down
1 change: 1 addition & 0 deletions libra/src/internal/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::internal::model::config::{self, ActiveModel, Model};

pub struct Config;

#[derive(Clone)]
pub struct RemoteConfig {
pub name: String,
pub url: String,
Expand Down
Loading