mirror of
https://github.com/zed-industries/zed.git
synced 2026-08-31 02:21:14 +00:00
multiworkspace: Don't destroy workspace when git worktree is detached head (#51977)
When a git worktree is in a detached HEAD state (e.g. after `git checkout --detach`), the workspace for that worktree would disappear from the sidebar UI, and if the workspace was currently open your UI would just disappear. This happened because `parse_worktrees_from_str` silently dropped any worktree entries without a `branch` line in the porcelain output, which cascaded through the `linked_worktrees` list and caused `prune_stale_worktree_workspaces` to remove the workspace. This PR: - Makes `Worktree::ref_name` an `Option<SharedString>` so detached worktrees can be represented - Renames `Worktree::branch()` to `Worktree::display_name()`, which returns the branch name when available or the short SHA as a fallback (mirroring how the title bar already handles detached HEAD for repositories) - Updates `parse_worktrees_from_str` to include detached and bare worktree entries instead of dropping them - Filters detached worktrees out of the worktree picker UI, preserving the existing product decision to only show branch-based worktrees there ## Self-Review Checklist - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - N/A
This commit is contained in:
parent
1dfe836d3d
commit
2d7c7200cf
9 changed files with 107 additions and 67 deletions
|
|
@ -235,7 +235,10 @@ async fn test_remote_git_worktrees(
|
|||
assert_eq!(worktrees.len(), 2);
|
||||
assert_eq!(worktrees[0].path, PathBuf::from(path!("/project")));
|
||||
assert_eq!(worktrees[1].path, worktree_directory.join("feature-branch"));
|
||||
assert_eq!(worktrees[1].ref_name.as_ref(), "refs/heads/feature-branch");
|
||||
assert_eq!(
|
||||
worktrees[1].ref_name,
|
||||
Some("refs/heads/feature-branch".into())
|
||||
);
|
||||
assert_eq!(worktrees[1].sha.as_ref(), "abc123");
|
||||
|
||||
// Verify from the host side that the worktree was actually created
|
||||
|
|
@ -287,7 +290,7 @@ async fn test_remote_git_worktrees(
|
|||
|
||||
let feature_worktree = worktrees
|
||||
.iter()
|
||||
.find(|worktree| worktree.ref_name.as_ref() == "refs/heads/feature-branch")
|
||||
.find(|worktree| worktree.ref_name == Some("refs/heads/feature-branch".into()))
|
||||
.expect("should find feature-branch worktree");
|
||||
assert_eq!(
|
||||
feature_worktree.path,
|
||||
|
|
@ -296,7 +299,7 @@ async fn test_remote_git_worktrees(
|
|||
|
||||
let bugfix_worktree = worktrees
|
||||
.iter()
|
||||
.find(|worktree| worktree.ref_name.as_ref() == "refs/heads/bugfix-branch")
|
||||
.find(|worktree| worktree.ref_name == Some("refs/heads/bugfix-branch".into()))
|
||||
.expect("should find bugfix-branch worktree");
|
||||
assert_eq!(
|
||||
bugfix_worktree.path,
|
||||
|
|
@ -396,17 +399,17 @@ async fn test_linked_worktrees_sync(
|
|||
.with_git_state(Path::new(path!("/project/.git")), true, |state| {
|
||||
state.worktrees.push(GitWorktree {
|
||||
path: PathBuf::from(path!("/project")),
|
||||
ref_name: "refs/heads/main".into(),
|
||||
ref_name: Some("refs/heads/main".into()),
|
||||
sha: "aaa111".into(),
|
||||
});
|
||||
state.worktrees.push(GitWorktree {
|
||||
path: PathBuf::from(path!("/project/feature-branch")),
|
||||
ref_name: "refs/heads/feature-branch".into(),
|
||||
ref_name: Some("refs/heads/feature-branch".into()),
|
||||
sha: "bbb222".into(),
|
||||
});
|
||||
state.worktrees.push(GitWorktree {
|
||||
path: PathBuf::from(path!("/project/bugfix-branch")),
|
||||
ref_name: "refs/heads/bugfix-branch".into(),
|
||||
ref_name: Some("refs/heads/bugfix-branch".into()),
|
||||
sha: "ccc333".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -434,15 +437,18 @@ async fn test_linked_worktrees_sync(
|
|||
PathBuf::from(path!("/project/feature-branch"))
|
||||
);
|
||||
assert_eq!(
|
||||
host_linked[0].ref_name.as_ref(),
|
||||
"refs/heads/feature-branch"
|
||||
host_linked[0].ref_name,
|
||||
Some("refs/heads/feature-branch".into())
|
||||
);
|
||||
assert_eq!(host_linked[0].sha.as_ref(), "bbb222");
|
||||
assert_eq!(
|
||||
host_linked[1].path,
|
||||
PathBuf::from(path!("/project/bugfix-branch"))
|
||||
);
|
||||
assert_eq!(host_linked[1].ref_name.as_ref(), "refs/heads/bugfix-branch");
|
||||
assert_eq!(
|
||||
host_linked[1].ref_name,
|
||||
Some("refs/heads/bugfix-branch".into())
|
||||
);
|
||||
assert_eq!(host_linked[1].sha.as_ref(), "ccc333");
|
||||
|
||||
// Share the project and have client B join.
|
||||
|
|
@ -472,7 +478,7 @@ async fn test_linked_worktrees_sync(
|
|||
.with_git_state(Path::new(path!("/project/.git")), true, |state| {
|
||||
state.worktrees.push(GitWorktree {
|
||||
path: PathBuf::from(path!("/project/hotfix-branch")),
|
||||
ref_name: "refs/heads/hotfix-branch".into(),
|
||||
ref_name: Some("refs/heads/hotfix-branch".into()),
|
||||
sha: "ddd444".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -514,7 +520,7 @@ async fn test_linked_worktrees_sync(
|
|||
.with_git_state(Path::new(path!("/project/.git")), true, |state| {
|
||||
state
|
||||
.worktrees
|
||||
.retain(|wt| wt.ref_name.as_ref() != "refs/heads/bugfix-branch");
|
||||
.retain(|wt| wt.ref_name != Some("refs/heads/bugfix-branch".into()));
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -534,7 +540,7 @@ async fn test_linked_worktrees_sync(
|
|||
assert!(
|
||||
host_linked_after_removal
|
||||
.iter()
|
||||
.all(|wt| wt.ref_name.as_ref() != "refs/heads/bugfix-branch"),
|
||||
.all(|wt| wt.ref_name != Some("refs/heads/bugfix-branch".into())),
|
||||
"bugfix-branch should have been removed"
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -491,7 +491,10 @@ async fn test_ssh_collaboration_git_worktrees(
|
|||
.unwrap();
|
||||
assert_eq!(worktrees.len(), 2);
|
||||
assert_eq!(worktrees[1].path, worktree_directory.join("feature-branch"));
|
||||
assert_eq!(worktrees[1].ref_name.as_ref(), "refs/heads/feature-branch");
|
||||
assert_eq!(
|
||||
worktrees[1].ref_name,
|
||||
Some("refs/heads/feature-branch".into())
|
||||
);
|
||||
assert_eq!(worktrees[1].sha.as_ref(), "abc123");
|
||||
|
||||
let server_worktrees = {
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ impl GitRepository for FakeGitRepository {
|
|||
.unwrap_or_else(|| "refs/heads/main".to_string());
|
||||
let main_worktree = Worktree {
|
||||
path: work_dir,
|
||||
ref_name: branch_ref.into(),
|
||||
ref_name: Some(branch_ref.into()),
|
||||
sha: head_sha.into(),
|
||||
};
|
||||
let mut all = vec![main_worktree];
|
||||
|
|
@ -468,7 +468,7 @@ impl GitRepository for FakeGitRepository {
|
|||
state.refs.insert(ref_name.clone(), sha.clone());
|
||||
state.worktrees.push(Worktree {
|
||||
path,
|
||||
ref_name: ref_name.into(),
|
||||
ref_name: Some(ref_name.into()),
|
||||
sha: sha.into(),
|
||||
});
|
||||
state.branches.insert(branch_name);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,10 @@ async fn test_fake_worktree_lifecycle(cx: &mut TestAppContext) {
|
|||
assert_eq!(worktrees.len(), 2);
|
||||
assert_eq!(worktrees[0].path, PathBuf::from("/project"));
|
||||
assert_eq!(worktrees[1].path, worktree_1_dir);
|
||||
assert_eq!(worktrees[1].ref_name.as_ref(), "refs/heads/feature-branch");
|
||||
assert_eq!(
|
||||
worktrees[1].ref_name,
|
||||
Some("refs/heads/feature-branch".into())
|
||||
);
|
||||
assert_eq!(worktrees[1].sha.as_ref(), "abc123");
|
||||
|
||||
// Directory should exist in FakeFs after create
|
||||
|
|
|
|||
|
|
@ -212,18 +212,25 @@ impl Branch {
|
|||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Worktree {
|
||||
pub path: PathBuf,
|
||||
pub ref_name: SharedString,
|
||||
pub ref_name: Option<SharedString>,
|
||||
// todo(git_worktree) This type should be a Oid
|
||||
pub sha: SharedString,
|
||||
}
|
||||
|
||||
impl Worktree {
|
||||
pub fn branch(&self) -> &str {
|
||||
self.ref_name
|
||||
.as_ref()
|
||||
.strip_prefix("refs/heads/")
|
||||
.or_else(|| self.ref_name.as_ref().strip_prefix("refs/remotes/"))
|
||||
.unwrap_or(self.ref_name.as_ref())
|
||||
/// Returns a display name for the worktree, suitable for use in the UI.
|
||||
///
|
||||
/// If the worktree is attached to a branch, returns the branch name.
|
||||
/// Otherwise, returns the short SHA of the worktree's HEAD commit.
|
||||
pub fn display_name(&self) -> &str {
|
||||
match self.ref_name {
|
||||
Some(ref ref_name) => ref_name
|
||||
.strip_prefix("refs/heads/")
|
||||
.or_else(|| ref_name.strip_prefix("refs/remotes/"))
|
||||
.unwrap_or(ref_name),
|
||||
// Detached HEAD — show the short SHA as a fallback.
|
||||
None => &self.sha[..self.sha.len().min(SHORT_SHA_LENGTH)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -251,12 +258,10 @@ pub fn parse_worktrees_from_str<T: AsRef<str>>(raw_worktrees: T) -> Vec<Worktree
|
|||
// Ignore other lines: detached, bare, locked, prunable, etc.
|
||||
}
|
||||
|
||||
// todo(git_worktree) We should add a test for detach head state
|
||||
// a detach head will have ref_name as none so we would skip it
|
||||
if let (Some(path), Some(sha), Some(ref_name)) = (path, sha, ref_name) {
|
||||
if let (Some(path), Some(sha)) = (path, sha) {
|
||||
worktrees.push(Worktree {
|
||||
path: PathBuf::from(path),
|
||||
ref_name: ref_name.into(),
|
||||
ref_name: ref_name.map(Into::into),
|
||||
sha: sha.into(),
|
||||
})
|
||||
}
|
||||
|
|
@ -3793,7 +3798,7 @@ mod tests {
|
|||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result[0].sha.as_ref(), "abc123def");
|
||||
assert_eq!(result[0].ref_name.as_ref(), "refs/heads/main");
|
||||
assert_eq!(result[0].ref_name, Some("refs/heads/main".into()));
|
||||
|
||||
// Multiple worktrees
|
||||
let input = "worktree /home/user/project\nHEAD abc123\nbranch refs/heads/main\n\n\
|
||||
|
|
@ -3801,23 +3806,30 @@ mod tests {
|
|||
let result = parse_worktrees_from_str(input);
|
||||
assert_eq!(result.len(), 2);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result[0].ref_name.as_ref(), "refs/heads/main");
|
||||
assert_eq!(result[0].ref_name, Some("refs/heads/main".into()));
|
||||
assert_eq!(result[1].path, PathBuf::from("/home/user/project-wt"));
|
||||
assert_eq!(result[1].ref_name.as_ref(), "refs/heads/feature");
|
||||
assert_eq!(result[1].ref_name, Some("refs/heads/feature".into()));
|
||||
|
||||
// Detached HEAD entry (should be skipped since ref_name won't parse)
|
||||
// Detached HEAD entry (included with ref_name: None)
|
||||
let input = "worktree /home/user/project\nHEAD abc123\nbranch refs/heads/main\n\n\
|
||||
worktree /home/user/detached\nHEAD def456\ndetached\n\n";
|
||||
let result = parse_worktrees_from_str(input);
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result.len(), 2);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result[0].ref_name, Some("refs/heads/main".into()));
|
||||
assert_eq!(result[1].path, PathBuf::from("/home/user/detached"));
|
||||
assert_eq!(result[1].ref_name, None);
|
||||
assert_eq!(result[1].sha.as_ref(), "def456");
|
||||
|
||||
// Bare repo entry (should be skipped)
|
||||
// Bare repo entry (included with ref_name: None)
|
||||
let input = "worktree /home/user/bare.git\nHEAD abc123\nbare\n\n\
|
||||
worktree /home/user/project\nHEAD def456\nbranch refs/heads/main\n\n";
|
||||
let result = parse_worktrees_from_str(input);
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result.len(), 2);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/bare.git"));
|
||||
assert_eq!(result[0].ref_name, None);
|
||||
assert_eq!(result[1].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result[1].ref_name, Some("refs/heads/main".into()));
|
||||
|
||||
// Extra porcelain lines (locked, prunable) should be ignored
|
||||
let input = "worktree /home/user/project\nHEAD abc123\nbranch refs/heads/main\n\n\
|
||||
|
|
@ -3826,11 +3838,14 @@ mod tests {
|
|||
let result = parse_worktrees_from_str(input);
|
||||
assert_eq!(result.len(), 3);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result[0].ref_name.as_ref(), "refs/heads/main");
|
||||
assert_eq!(result[0].ref_name, Some("refs/heads/main".into()));
|
||||
assert_eq!(result[1].path, PathBuf::from("/home/user/locked-wt"));
|
||||
assert_eq!(result[1].ref_name.as_ref(), "refs/heads/locked-branch");
|
||||
assert_eq!(result[1].ref_name, Some("refs/heads/locked-branch".into()));
|
||||
assert_eq!(result[2].path, PathBuf::from("/home/user/prunable-wt"));
|
||||
assert_eq!(result[2].ref_name.as_ref(), "refs/heads/prunable-branch");
|
||||
assert_eq!(
|
||||
result[2].ref_name,
|
||||
Some("refs/heads/prunable-branch".into())
|
||||
);
|
||||
|
||||
// Leading/trailing whitespace on lines should be tolerated
|
||||
let input =
|
||||
|
|
@ -3839,7 +3854,7 @@ mod tests {
|
|||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result[0].sha.as_ref(), "abc123");
|
||||
assert_eq!(result[0].ref_name.as_ref(), "refs/heads/main");
|
||||
assert_eq!(result[0].ref_name, Some("refs/heads/main".into()));
|
||||
|
||||
// Windows-style line endings should be handled
|
||||
let input = "worktree /home/user/project\r\nHEAD abc123\r\nbranch refs/heads/main\r\n\r\n";
|
||||
|
|
@ -3847,7 +3862,7 @@ mod tests {
|
|||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0].path, PathBuf::from("/home/user/project"));
|
||||
assert_eq!(result[0].sha.as_ref(), "abc123");
|
||||
assert_eq!(result[0].ref_name.as_ref(), "refs/heads/main");
|
||||
assert_eq!(result[0].ref_name, Some("refs/heads/main".into()));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
|
@ -3914,7 +3929,7 @@ mod tests {
|
|||
|
||||
let new_worktree = worktrees
|
||||
.iter()
|
||||
.find(|w| w.branch() == "test-branch")
|
||||
.find(|w| w.display_name() == "test-branch")
|
||||
.expect("should find worktree with test-branch");
|
||||
assert_eq!(
|
||||
new_worktree.path.canonicalize().unwrap(),
|
||||
|
|
@ -3976,7 +3991,7 @@ mod tests {
|
|||
let worktrees = repo.worktrees().await.unwrap();
|
||||
assert_eq!(worktrees.len(), 1);
|
||||
assert!(
|
||||
worktrees.iter().all(|w| w.branch() != "to-remove"),
|
||||
worktrees.iter().all(|w| w.display_name() != "to-remove"),
|
||||
"removed worktree should not appear in list"
|
||||
);
|
||||
assert!(!worktree_path.exists());
|
||||
|
|
@ -4078,7 +4093,7 @@ mod tests {
|
|||
assert_eq!(worktrees.len(), 2);
|
||||
let moved_worktree = worktrees
|
||||
.iter()
|
||||
.find(|w| w.branch() == "old-name")
|
||||
.find(|w| w.display_name() == "old-name")
|
||||
.expect("should find worktree by branch name");
|
||||
assert_eq!(
|
||||
moved_worktree.path.canonicalize().unwrap(),
|
||||
|
|
|
|||
|
|
@ -96,9 +96,12 @@ impl WorktreeList {
|
|||
});
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let all_worktrees = all_worktrees_request
|
||||
let all_worktrees: Vec<_> = all_worktrees_request
|
||||
.context("No active repository")?
|
||||
.await??;
|
||||
.await??
|
||||
.into_iter()
|
||||
.filter(|worktree| worktree.ref_name.is_some()) // hide worktrees without a branch
|
||||
.collect();
|
||||
|
||||
let default_branch = default_branch_request
|
||||
.context("No active repository")?
|
||||
|
|
@ -182,7 +185,7 @@ impl WorktreeList {
|
|||
return;
|
||||
}
|
||||
picker.delegate.create_worktree(
|
||||
entry.worktree.branch(),
|
||||
entry.worktree.display_name(),
|
||||
replace_current_window,
|
||||
Some(default_branch.into()),
|
||||
window,
|
||||
|
|
@ -649,7 +652,7 @@ impl PickerDelegate for WorktreeListDelegate {
|
|||
let candidates = all_worktrees
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(ix, worktree)| StringMatchCandidate::new(ix, worktree.branch()))
|
||||
.map(|(ix, worktree)| StringMatchCandidate::new(ix, worktree.display_name()))
|
||||
.collect::<Vec<StringMatchCandidate>>();
|
||||
fuzzy::match_strings(
|
||||
&candidates,
|
||||
|
|
@ -674,13 +677,13 @@ impl PickerDelegate for WorktreeListDelegate {
|
|||
if !query.is_empty()
|
||||
&& !matches
|
||||
.first()
|
||||
.is_some_and(|entry| entry.worktree.branch() == query)
|
||||
.is_some_and(|entry| entry.worktree.display_name() == query)
|
||||
{
|
||||
let query = query.replace(' ', "-");
|
||||
matches.push(WorktreeEntry {
|
||||
worktree: GitWorktree {
|
||||
path: Default::default(),
|
||||
ref_name: format!("refs/heads/{query}").into(),
|
||||
ref_name: Some(format!("refs/heads/{query}").into()),
|
||||
sha: Default::default(),
|
||||
},
|
||||
positions: Vec::new(),
|
||||
|
|
@ -706,7 +709,7 @@ impl PickerDelegate for WorktreeListDelegate {
|
|||
return;
|
||||
};
|
||||
if entry.is_new {
|
||||
self.create_worktree(&entry.worktree.branch(), secondary, None, window, cx);
|
||||
self.create_worktree(&entry.worktree.display_name(), secondary, None, window, cx);
|
||||
} else {
|
||||
self.open_worktree(&entry.worktree.path, secondary, window, cx);
|
||||
}
|
||||
|
|
@ -737,16 +740,19 @@ impl PickerDelegate for WorktreeListDelegate {
|
|||
|
||||
let (branch_name, sublabel) = if entry.is_new {
|
||||
(
|
||||
Label::new(format!("Create Worktree: \"{}\"…", entry.worktree.branch()))
|
||||
.truncate()
|
||||
.into_any_element(),
|
||||
Label::new(format!(
|
||||
"Create Worktree: \"{}\"…",
|
||||
entry.worktree.display_name()
|
||||
))
|
||||
.truncate()
|
||||
.into_any_element(),
|
||||
format!(
|
||||
"based off {}",
|
||||
self.base_branch(cx).unwrap_or("the current branch")
|
||||
),
|
||||
)
|
||||
} else {
|
||||
let branch = entry.worktree.branch();
|
||||
let branch = entry.worktree.display_name();
|
||||
let branch_first_line = branch.lines().next().unwrap_or(branch);
|
||||
let positions: Vec<_> = entry
|
||||
.positions
|
||||
|
|
|
|||
|
|
@ -7018,7 +7018,11 @@ fn branch_to_proto(branch: &git::repository::Branch) -> proto::Branch {
|
|||
fn worktree_to_proto(worktree: &git::repository::Worktree) -> proto::Worktree {
|
||||
proto::Worktree {
|
||||
path: worktree.path.to_string_lossy().to_string(),
|
||||
ref_name: worktree.ref_name.to_string(),
|
||||
ref_name: worktree
|
||||
.ref_name
|
||||
.as_ref()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default(),
|
||||
sha: worktree.sha.to_string(),
|
||||
}
|
||||
}
|
||||
|
|
@ -7026,7 +7030,7 @@ fn worktree_to_proto(worktree: &git::repository::Worktree) -> proto::Worktree {
|
|||
fn proto_to_worktree(proto: &proto::Worktree) -> git::repository::Worktree {
|
||||
git::repository::Worktree {
|
||||
path: PathBuf::from(proto.path.clone()),
|
||||
ref_name: proto.ref_name.clone().into(),
|
||||
ref_name: Some(SharedString::from(&proto.ref_name)),
|
||||
sha: proto.sha.clone().into(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1287,7 +1287,10 @@ mod git_worktrees {
|
|||
assert_eq!(worktrees.len(), 2);
|
||||
assert_eq!(worktrees[0].path, PathBuf::from(path!("/root")));
|
||||
assert_eq!(worktrees[1].path, worktree_1_directory);
|
||||
assert_eq!(worktrees[1].ref_name.as_ref(), "refs/heads/feature-branch");
|
||||
assert_eq!(
|
||||
worktrees[1].ref_name,
|
||||
Some("refs/heads/feature-branch".into())
|
||||
);
|
||||
assert_eq!(worktrees[1].sha.as_ref(), "abc123");
|
||||
|
||||
let worktree_2_directory = worktrees_directory.join("bugfix-branch");
|
||||
|
|
@ -1316,13 +1319,13 @@ mod git_worktrees {
|
|||
|
||||
let worktree_1 = worktrees
|
||||
.iter()
|
||||
.find(|worktree| worktree.ref_name.as_ref() == "refs/heads/feature-branch")
|
||||
.find(|worktree| worktree.ref_name == Some("refs/heads/feature-branch".into()))
|
||||
.expect("should find feature-branch worktree");
|
||||
assert_eq!(worktree_1.path, worktree_1_directory);
|
||||
|
||||
let worktree_2 = worktrees
|
||||
.iter()
|
||||
.find(|worktree| worktree.ref_name.as_ref() == "refs/heads/bugfix-branch")
|
||||
.find(|worktree| worktree.ref_name == Some("refs/heads/bugfix-branch".into()))
|
||||
.expect("should find bugfix-branch worktree");
|
||||
assert_eq!(worktree_2.path, worktree_2_directory);
|
||||
assert_eq!(worktree_2.sha.as_ref(), "fake-sha");
|
||||
|
|
|
|||
|
|
@ -4965,7 +4965,7 @@ mod tests {
|
|||
.with_git_state(std::path::Path::new("/project/.git"), false, |state| {
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt/rosewood"),
|
||||
ref_name: "refs/heads/rosewood".into(),
|
||||
ref_name: Some("refs/heads/rosewood".into()),
|
||||
sha: "abc".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -5026,7 +5026,7 @@ mod tests {
|
|||
.with_git_state(std::path::Path::new("/project/.git"), true, |state| {
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt/rosewood"),
|
||||
ref_name: "refs/heads/rosewood".into(),
|
||||
ref_name: Some("refs/heads/rosewood".into()),
|
||||
sha: "abc".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -5130,12 +5130,12 @@ mod tests {
|
|||
fs.with_git_state(std::path::Path::new("/project/.git"), false, |state| {
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt-feature-a"),
|
||||
ref_name: "refs/heads/feature-a".into(),
|
||||
ref_name: Some("refs/heads/feature-a".into()),
|
||||
sha: "aaa".into(),
|
||||
});
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt-feature-b"),
|
||||
ref_name: "refs/heads/feature-b".into(),
|
||||
ref_name: Some("refs/heads/feature-b".into()),
|
||||
sha: "bbb".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -5232,7 +5232,7 @@ mod tests {
|
|||
fs.with_git_state(std::path::Path::new("/project/.git"), false, |state| {
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt-feature-a"),
|
||||
ref_name: "refs/heads/feature-a".into(),
|
||||
ref_name: Some("refs/heads/feature-a".into()),
|
||||
sha: "aaa".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -5348,7 +5348,7 @@ mod tests {
|
|||
fs.with_git_state(std::path::Path::new("/project/.git"), false, |state| {
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt-feature-a"),
|
||||
ref_name: "refs/heads/feature-a".into(),
|
||||
ref_name: Some("refs/heads/feature-a".into()),
|
||||
sha: "aaa".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -5457,7 +5457,7 @@ mod tests {
|
|||
fs.with_git_state(std::path::Path::new("/project/.git"), false, |state| {
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt-feature-a"),
|
||||
ref_name: "refs/heads/feature-a".into(),
|
||||
ref_name: Some("refs/heads/feature-a".into()),
|
||||
sha: "aaa".into(),
|
||||
});
|
||||
})
|
||||
|
|
@ -5563,7 +5563,7 @@ mod tests {
|
|||
fs.with_git_state(std::path::Path::new("/project/.git"), false, |state| {
|
||||
state.worktrees.push(git::repository::Worktree {
|
||||
path: std::path::PathBuf::from("/wt-feature-a"),
|
||||
ref_name: "refs/heads/feature-a".into(),
|
||||
ref_name: Some("refs/heads/feature-a".into()),
|
||||
sha: "aaa".into(),
|
||||
});
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue