git: Add option to branch from default branch in branch picker (#34663)
Closes #33700 The option shows up as an icon that appears on entries that would create a new branch. You can also branch from the default by secondary confirming, which the icon has a tooltip for as well. We based the default branch on the results from this command: `git symbolic-ref refs/remotes/upstream/HEAD` and fallback to `git symbolic-ref refs/remotes/origin/HEAD` Release Notes: - Add option to create a branch from a default branch in git branch picker --------- Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
parent
fa8dd1c547
commit
9fa634f02f
7 changed files with 133 additions and 9 deletions
|
@ -13,7 +13,7 @@ use project::git_store::Repository;
|
|||
use std::sync::Arc;
|
||||
use time::OffsetDateTime;
|
||||
use time_format::format_local_timestamp;
|
||||
use ui::{HighlightedLabel, ListItem, ListItemSpacing, prelude::*};
|
||||
use ui::{HighlightedLabel, ListItem, ListItemSpacing, Tooltip, prelude::*};
|
||||
use util::ResultExt;
|
||||
use workspace::notifications::DetachAndPromptErr;
|
||||
use workspace::{ModalView, Workspace};
|
||||
|
@ -90,11 +90,21 @@ impl BranchList {
|
|||
let all_branches_request = repository
|
||||
.clone()
|
||||
.map(|repository| repository.update(cx, |repository, _| repository.branches()));
|
||||
let default_branch_request = repository
|
||||
.clone()
|
||||
.map(|repository| repository.update(cx, |repository, _| repository.default_branch()));
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let mut all_branches = all_branches_request
|
||||
.context("No active repository")?
|
||||
.await??;
|
||||
let default_branch = default_branch_request
|
||||
.context("No active repository")?
|
||||
.await
|
||||
.map(Result::ok)
|
||||
.ok()
|
||||
.flatten()
|
||||
.flatten();
|
||||
|
||||
let all_branches = cx
|
||||
.background_spawn(async move {
|
||||
|
@ -124,6 +134,7 @@ impl BranchList {
|
|||
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
this.picker.update(cx, |picker, cx| {
|
||||
picker.delegate.default_branch = default_branch;
|
||||
picker.delegate.all_branches = Some(all_branches);
|
||||
picker.refresh(window, cx);
|
||||
})
|
||||
|
@ -192,6 +203,7 @@ struct BranchEntry {
|
|||
pub struct BranchListDelegate {
|
||||
matches: Vec<BranchEntry>,
|
||||
all_branches: Option<Vec<Branch>>,
|
||||
default_branch: Option<SharedString>,
|
||||
repo: Option<Entity<Repository>>,
|
||||
style: BranchListStyle,
|
||||
selected_index: usize,
|
||||
|
@ -206,6 +218,7 @@ impl BranchListDelegate {
|
|||
repo,
|
||||
style,
|
||||
all_branches: None,
|
||||
default_branch: None,
|
||||
selected_index: 0,
|
||||
last_query: Default::default(),
|
||||
modifiers: Default::default(),
|
||||
|
@ -214,6 +227,7 @@ impl BranchListDelegate {
|
|||
|
||||
fn create_branch(
|
||||
&self,
|
||||
from_branch: Option<SharedString>,
|
||||
new_branch_name: SharedString,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Picker<Self>>,
|
||||
|
@ -223,6 +237,11 @@ impl BranchListDelegate {
|
|||
};
|
||||
let new_branch_name = new_branch_name.to_string().replace(' ', "-");
|
||||
cx.spawn(async move |_, cx| {
|
||||
if let Some(based_branch) = from_branch {
|
||||
repo.update(cx, |repo, _| repo.change_branch(based_branch.to_string()))?
|
||||
.await??;
|
||||
}
|
||||
|
||||
repo.update(cx, |repo, _| {
|
||||
repo.create_branch(new_branch_name.to_string())
|
||||
})?
|
||||
|
@ -353,12 +372,22 @@ impl PickerDelegate for BranchListDelegate {
|
|||
})
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
fn confirm(&mut self, secondary: bool, window: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
let Some(entry) = self.matches.get(self.selected_index()) else {
|
||||
return;
|
||||
};
|
||||
if entry.is_new {
|
||||
self.create_branch(entry.branch.name().to_owned().into(), window, cx);
|
||||
let from_branch = if secondary {
|
||||
self.default_branch.clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.create_branch(
|
||||
from_branch,
|
||||
entry.branch.name().to_owned().into(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -439,6 +468,28 @@ impl PickerDelegate for BranchListDelegate {
|
|||
})
|
||||
.unwrap_or_else(|| (None, None));
|
||||
|
||||
let icon = if let Some(default_branch) = self.default_branch.clone()
|
||||
&& entry.is_new
|
||||
{
|
||||
Some(
|
||||
IconButton::new("branch-from-default", IconName::GitBranchSmall)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.delegate.set_selected_index(ix, window, cx);
|
||||
this.delegate.confirm(true, window, cx);
|
||||
}))
|
||||
.tooltip(move |window, cx| {
|
||||
Tooltip::for_action(
|
||||
format!("Create branch based off default: {default_branch}"),
|
||||
&menu::SecondaryConfirm,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let branch_name = if entry.is_new {
|
||||
h_flex()
|
||||
.gap_1()
|
||||
|
@ -504,7 +555,8 @@ impl PickerDelegate for BranchListDelegate {
|
|||
.color(Color::Muted)
|
||||
}))
|
||||
}),
|
||||
),
|
||||
)
|
||||
.end_slot::<IconButton>(icon),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue