This commit is contained in:
吴杨帆 2026-05-17 18:09:42 +08:00 committed by GitHub
commit 1cc37d5fd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 9 deletions

View file

@ -372,6 +372,23 @@ pub fn checkout_commit(
}
}
/// Whether `name` refers to a remote symbolic `HEAD` ref (e.g. `origin/HEAD`).
pub fn is_remote_head_ref(name: &str) -> bool {
name == "HEAD"
|| name
.split_once('/')
.is_some_and(|(_, local)| local == "HEAD")
}
fn local_branch_name_from_remote(remote_name: &str) -> Option<String> {
if is_remote_head_ref(remote_name) {
return None;
}
let local = remote_name.split_once('/')?.1;
Some(local.to_string())
}
///
pub fn checkout_remote_branch(
repo_path: &RepoPath,
@ -391,10 +408,11 @@ pub fn checkout_remote_branch(
return Err(Error::UncommittedChanges);
}
let name = branch.name.find('/').map_or_else(
|| branch.name.clone(),
|pos| branch.name[pos..].to_string(),
);
let name = local_branch_name_from_remote(&branch.name).ok_or_else(|| {
Error::Generic(
"cannot checkout remote HEAD reference".to_string(),
)
})?;
let commit = repo.find_commit(branch.top_commit.into())?;
let mut new_branch = repo.branch(&name, &commit, false)?;
@ -1021,6 +1039,40 @@ mod test_remote_branches {
);
}
#[test]
fn test_checkout_remote_head_fails() {
let (r1_dir, _repo) = repo_init_bare().unwrap();
let (clone1_dir, clone1) =
repo_clone(r1_dir.path().to_str().unwrap()).unwrap();
let clone1_dir = clone1_dir.path().to_str().unwrap();
write_commit_file(&clone1, "test.txt", "test", "commit1");
push_branch(
&clone1_dir.into(),
"origin",
"master",
false,
false,
None,
None,
)
.unwrap();
let (clone2_dir, _clone2) =
repo_clone(r1_dir.path().to_str().unwrap()).unwrap();
let clone2_dir = clone2_dir.path().to_str().unwrap();
let branches =
get_branches_info(&clone2_dir.into(), false).unwrap();
let head = branches
.iter()
.find(|b| b.name == "origin/HEAD")
.expect("origin/HEAD");
assert!(checkout_remote_branch(&clone2_dir.into(), head).is_err());
}
#[test]
fn test_checkout_remote_branch_hierarchical() {
let (r1_dir, _repo) = repo_init_bare().unwrap();

View file

@ -17,7 +17,8 @@ use asyncgit::{
sync::{
self,
branch::{
checkout_remote_branch, BranchDetails, LocalBranch,
checkout_remote_branch, is_remote_head_ref, BranchDetails,
LocalBranch,
RemoteBranch,
},
checkout_branch, get_branches_info,
@ -317,12 +318,9 @@ impl BranchListPopup {
self.check_remotes();
self.branches =
get_branches_info(&self.repo.borrow(), self.local)?;
//remove remote branch called `HEAD`
if !self.local {
self.branches
.iter()
.position(|b| b.name.ends_with("/HEAD"))
.map(|idx| self.branches.remove(idx));
.retain(|b| !is_remote_head_ref(&b.name));
}
self.set_selection(self.selection)?;
}