Skip to content
Closed
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
2 changes: 1 addition & 1 deletion crates/agent_ui/src/thread_worktree_archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ pub async fn restore_worktree_via_git(
if let Some(branch_name) = &row.branch_name {
// Attempt to check out the branch the worktree was previously on.
let checkout_result = wt_repo
.update(cx, |repo, _cx| repo.change_branch(branch_name.clone()))
.update(cx, |repo, cx| repo.change_branch(branch_name.clone(), cx))
.await;

match checkout_result.map_err(|e| anyhow!("{e}")).flatten() {
Expand Down
4 changes: 2 additions & 2 deletions crates/collab/tests/integration/git_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -907,8 +907,8 @@ async fn test_branch_list_sync(
.unwrap();

cx_b.update(|cx| {
repo_b.update(cx, |repository, _cx| {
repository.change_branch("totally-new-branch".to_string())
repo_b.update(cx, |repository, cx| {
repository.change_branch("totally-new-branch".to_string(), cx)
})
})
.await
Expand Down
8 changes: 4 additions & 4 deletions crates/collab/tests/integration/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7353,8 +7353,8 @@ async fn test_remote_git_branches(
assert_eq!(branches_b, branches_set);

cx_b.update(|cx| {
repo_b.update(cx, |repository, _cx| {
repository.change_branch(new_branch.to_string())
repo_b.update(cx, |repository, cx| {
repository.change_branch(new_branch.to_string(), cx)
})
})
.await
Expand Down Expand Up @@ -7391,8 +7391,8 @@ async fn test_remote_git_branches(
.unwrap();

cx_b.update(|cx| {
repo_b.update(cx, |repository, _cx| {
repository.change_branch("totally-new-branch".to_string())
repo_b.update(cx, |repository, cx| {
repository.change_branch("totally-new-branch".to_string(), cx)
})
})
.await
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ async fn test_ssh_collaboration_git_branches(
assert_eq!(&branches_b, &branches_set);

cx_b.update(|cx| {
repo_b.update(cx, |repo_b, _cx| {
repo_b.change_branch(new_branch.to_string())
repo_b.update(cx, |repo_b, cx| {
repo_b.change_branch(new_branch.to_string(), cx)
})
})
.await
Expand Down Expand Up @@ -351,8 +351,8 @@ async fn test_ssh_collaboration_git_branches(
.unwrap();

cx_b.update(|cx| {
repo_b.update(cx, |repo_b, _cx| {
repo_b.change_branch("totally-new-branch".to_string())
repo_b.update(cx, |repo_b, cx| {
repo_b.change_branch("totally-new-branch".to_string(), cx)
})
})
.await
Expand Down
6 changes: 4 additions & 2 deletions crates/git_ui/src/branch_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1566,8 +1566,10 @@ impl PickerDelegate for BranchListDelegate {

let branch = branch.clone();
cx.spawn(async move |_, cx| {
repo.update(cx, |repo, _| repo.change_branch(branch.name().to_string()))
.await??;
repo.update(cx, |repo, cx| {
repo.change_branch(branch.name().to_string(), cx)
})
.await??;

anyhow::Ok(())
})
Expand Down
36 changes: 31 additions & 5 deletions crates/project/src/git_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3607,8 +3607,8 @@ impl GitStore {
let branch_name = envelope.payload.branch_name;

repository_handle
.update(&mut cx, |repository_handle, _| {
repository_handle.change_branch(branch_name)
.update(&mut cx, |repository_handle, cx| {
repository_handle.change_branch(branch_name, cx)
})
.await??;

Expand Down Expand Up @@ -8673,9 +8673,13 @@ impl Repository {
)
}

pub fn change_branch(&mut self, branch_name: String) -> oneshot::Receiver<Result<()>> {
pub fn change_branch(
&mut self,
branch_name: String,
cx: &mut Context<Self>,
) -> oneshot::Receiver<Result<()>> {
let id = self.id;
self.send_job(
let receiver = self.send_job(
"change_branch",
Some(format!("git switch {branch_name}").into()),
move |repo, _cx| async move {
Expand All @@ -8696,7 +8700,29 @@ impl Repository {
}
}
},
)
);

// The worktree file watcher does not reliably observe the `.git/HEAD`
// change produced by `git switch` (notably over SSH, where the switch
// runs on the remote and the downstream `UpdateRepository` never gets
// sent). Refresh explicitly so the new branch propagates to the UI /
// downstream clients. Mirrors `reset`. `schedule_scan` is keyed by
// `ReloadGitState`, so any watcher-triggered scan is deduped.
let scan_updates_tx =
self.git_store()
.and_then(|git_store| match &git_store.read(cx).state {
GitStoreState::Local { downstream, .. } => Some(
downstream
.as_ref()
.map(|downstream| downstream.updates_tx.clone()),
),
_ => None,
});
if let Some(updates_tx) = scan_updates_tx {
self.schedule_scan(updates_tx, cx);
}

receiver
}

pub fn delete_branch(
Expand Down
33 changes: 29 additions & 4 deletions crates/remote_server/src/remote_editing_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3320,8 +3320,8 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA
assert_eq!(&remote_branches, &branches_set);

cx.update(|cx| {
repository.update(cx, |repository, _cx| {
repository.change_branch(new_branch.to_string())
repository.update(cx, |repository, cx| {
repository.change_branch(new_branch.to_string(), cx)
})
})
.await
Expand Down Expand Up @@ -3349,6 +3349,20 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA

assert_eq!(server_branch.name(), branches[2]);

// The downstream (client) repository must observe the new branch too —
// its snapshot is updated via the `UpdateRepository` the server sends
// after the scan triggered by `change_branch`.
let client_branch = cx.update(|cx| {
repository
.read(cx)
.branch
.as_ref()
.unwrap()
.name()
.to_string()
});
assert_eq!(client_branch, branches[2]);

// Also try creating a new branch
cx.update(|cx| {
repository.update(cx, |repo, _cx| {
Expand All @@ -3360,8 +3374,8 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA
.unwrap();

cx.update(|cx| {
repository.update(cx, |repo, _cx| {
repo.change_branch("totally-new-branch".to_string())
repository.update(cx, |repo, cx| {
repo.change_branch("totally-new-branch".to_string(), cx)
})
})
.await
Expand Down Expand Up @@ -3389,6 +3403,17 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA

assert_eq!(server_branch.name(), "totally-new-branch");

let client_branch = cx.update(|cx| {
repository
.read(cx)
.branch
.as_ref()
.unwrap()
.name()
.to_string()
});
assert_eq!(client_branch, "totally-new-branch");

let default_branch = cx
.update(|cx| repository.update(cx, |repository, _cx| repository.default_branch(false)))
.await
Expand Down