mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 00:48:35 +00:00
fetch/prune branches (#1000)
This commit is contained in:
parent
ee7ec691f0
commit
33ac72c8e7
13 changed files with 412 additions and 20 deletions
77
asyncgit/src/fetch_job.rs
Normal file
77
asyncgit/src/fetch_job.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//!
|
||||
|
||||
use crate::{
|
||||
asyncjob::{AsyncJob, RunParams},
|
||||
error::Result,
|
||||
sync::cred::BasicAuthCredential,
|
||||
sync::remotes::fetch_all,
|
||||
AsyncGitNotification, ProgressPercent, CWD,
|
||||
};
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
enum JobState {
|
||||
Request(Option<BasicAuthCredential>),
|
||||
Response(Result<()>),
|
||||
}
|
||||
|
||||
///
|
||||
#[derive(Clone, Default)]
|
||||
pub struct AsyncFetchJob {
|
||||
state: Arc<Mutex<Option<JobState>>>,
|
||||
}
|
||||
|
||||
///
|
||||
impl AsyncFetchJob {
|
||||
///
|
||||
pub fn new(
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
) -> Self {
|
||||
Self {
|
||||
state: Arc::new(Mutex::new(Some(JobState::Request(
|
||||
basic_credential,
|
||||
)))),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn result(&self) -> Option<Result<()>> {
|
||||
if let Ok(mut state) = self.state.lock() {
|
||||
if let Some(state) = state.take() {
|
||||
return match state {
|
||||
JobState::Request(_) => None,
|
||||
JobState::Response(result) => Some(result),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncJob for AsyncFetchJob {
|
||||
type Notification = AsyncGitNotification;
|
||||
type Progress = ProgressPercent;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_params: RunParams<Self::Notification, Self::Progress>,
|
||||
) -> Result<Self::Notification> {
|
||||
if let Ok(mut state) = self.state.lock() {
|
||||
*state = state.take().map(|state| match state {
|
||||
JobState::Request(basic_credentials) => {
|
||||
//TODO: support progress
|
||||
let result =
|
||||
fetch_all(CWD, &basic_credentials, &None);
|
||||
|
||||
JobState::Response(result)
|
||||
}
|
||||
JobState::Response(result) => {
|
||||
JobState::Response(result)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(AsyncGitNotification::Fetch)
|
||||
}
|
||||
}
|
||||
|
|
@ -28,8 +28,9 @@ pub mod cached;
|
|||
mod commit_files;
|
||||
mod diff;
|
||||
mod error;
|
||||
mod fetch;
|
||||
mod fetch_job;
|
||||
mod progress;
|
||||
mod pull;
|
||||
mod push;
|
||||
mod push_tags;
|
||||
pub mod remote_progress;
|
||||
|
|
@ -44,8 +45,9 @@ pub use crate::{
|
|||
commit_files::{AsyncCommitFiles, CommitFilesParams},
|
||||
diff::{AsyncDiff, DiffParams, DiffType},
|
||||
error::{Error, Result},
|
||||
fetch::{AsyncFetch, FetchRequest},
|
||||
fetch_job::AsyncFetchJob,
|
||||
progress::ProgressPercent,
|
||||
pull::{AsyncPull, FetchRequest},
|
||||
push::{AsyncPush, PushRequest},
|
||||
push_tags::{AsyncPushTags, PushTagsRequest},
|
||||
remote_progress::{RemoteProgress, RemoteProgressState},
|
||||
|
|
@ -83,11 +85,13 @@ pub enum AsyncGitNotification {
|
|||
///
|
||||
PushTags,
|
||||
///
|
||||
Fetch,
|
||||
Pull,
|
||||
///
|
||||
Blame,
|
||||
///
|
||||
RemoteTags,
|
||||
///
|
||||
Fetch,
|
||||
}
|
||||
|
||||
/// current working directory `./`
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ pub struct FetchRequest {
|
|||
struct FetchState {}
|
||||
|
||||
///
|
||||
pub struct AsyncFetch {
|
||||
pub struct AsyncPull {
|
||||
state: Arc<Mutex<Option<FetchState>>>,
|
||||
last_result: Arc<Mutex<Option<(usize, String)>>>,
|
||||
progress: Arc<Mutex<Option<ProgressNotification>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
}
|
||||
|
||||
impl AsyncFetch {
|
||||
impl AsyncPull {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
Self {
|
||||
|
|
@ -84,7 +84,7 @@ impl AsyncFetch {
|
|||
let (progress_sender, receiver) = unbounded();
|
||||
|
||||
let handle = RemoteProgress::spawn_receiver_thread(
|
||||
AsyncGitNotification::Fetch,
|
||||
AsyncGitNotification::Pull,
|
||||
sender.clone(),
|
||||
receiver,
|
||||
arc_progress,
|
||||
|
|
@ -108,7 +108,7 @@ impl AsyncFetch {
|
|||
Self::clear_request(&arc_state).expect("clear error");
|
||||
|
||||
sender
|
||||
.send(AsyncGitNotification::Fetch)
|
||||
.send(AsyncGitNotification::Pull)
|
||||
.expect("AsyncNotification error");
|
||||
});
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
cred::BasicAuthCredential,
|
||||
remotes::push::ProgressNotification, utils,
|
||||
},
|
||||
ProgressPercent,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use git2::{BranchType, FetchOptions, Repository};
|
||||
|
|
@ -75,14 +76,68 @@ pub(crate) fn get_default_remote_in_repo(
|
|||
Err(Error::NoDefaultRemoteFound)
|
||||
}
|
||||
|
||||
/// fetches from upstream/remote for `branch`
|
||||
///
|
||||
fn fetch_from_remote(
|
||||
repo_path: &str,
|
||||
remote: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
progress_sender: Option<Sender<ProgressNotification>>,
|
||||
) -> Result<()> {
|
||||
let repo = utils::repo(repo_path)?;
|
||||
|
||||
let mut remote = repo.find_remote(remote)?;
|
||||
|
||||
let mut options = FetchOptions::new();
|
||||
let callbacks = Callbacks::new(progress_sender, basic_credential);
|
||||
options.prune(git2::FetchPrune::On);
|
||||
options.remote_callbacks(callbacks.callbacks());
|
||||
remote.fetch(&[] as &[&str], Some(&mut options), None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// updates/prunes all branches from all remotes
|
||||
pub fn fetch_all(
|
||||
repo_path: &str,
|
||||
basic_credential: &Option<BasicAuthCredential>,
|
||||
progress_sender: &Option<Sender<ProgressPercent>>,
|
||||
) -> Result<()> {
|
||||
scope_time!("fetch_all");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let remotes = repo
|
||||
.remotes()?
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(String::from)
|
||||
.collect::<Vec<_>>();
|
||||
let remotes_count = remotes.len();
|
||||
|
||||
for (idx, remote) in remotes.into_iter().enumerate() {
|
||||
fetch_from_remote(
|
||||
repo_path,
|
||||
&remote,
|
||||
basic_credential.clone(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
if let Some(sender) = progress_sender {
|
||||
let progress = ProgressPercent::new(idx, remotes_count);
|
||||
sender.send(progress)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// fetches from upstream/remote for local `branch`
|
||||
pub(crate) fn fetch(
|
||||
repo_path: &str,
|
||||
branch: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
progress_sender: Option<Sender<ProgressNotification>>,
|
||||
) -> Result<usize> {
|
||||
scope_time!("fetch_origin");
|
||||
scope_time!("fetch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let branch_ref = repo
|
||||
|
|
|
|||
30
src/app.rs
30
src/app.rs
|
|
@ -6,11 +6,12 @@ use crate::{
|
|||
BranchListComponent, CommandBlocking, CommandInfo,
|
||||
CommitComponent, CompareCommitsComponent, Component,
|
||||
ConfirmComponent, CreateBranchComponent, DrawableComponent,
|
||||
ExternalEditorComponent, FileFindPopup, HelpComponent,
|
||||
InspectCommitComponent, MsgComponent, OptionsPopupComponent,
|
||||
PullComponent, PushComponent, PushTagsComponent,
|
||||
RenameBranchComponent, RevisionFilesPopup, SharedOptions,
|
||||
StashMsgComponent, TagCommitComponent, TagListComponent,
|
||||
ExternalEditorComponent, FetchComponent, FileFindPopup,
|
||||
HelpComponent, InspectCommitComponent, MsgComponent,
|
||||
OptionsPopupComponent, PullComponent, PushComponent,
|
||||
PushTagsComponent, RenameBranchComponent, RevisionFilesPopup,
|
||||
SharedOptions, StashMsgComponent, TagCommitComponent,
|
||||
TagListComponent,
|
||||
},
|
||||
input::{Input, InputEvent, InputState},
|
||||
keys::{KeyConfig, SharedKeyConfig},
|
||||
|
|
@ -55,6 +56,7 @@ pub struct App {
|
|||
push_popup: PushComponent,
|
||||
push_tags_popup: PushTagsComponent,
|
||||
pull_popup: PullComponent,
|
||||
fetch_popup: FetchComponent,
|
||||
tag_commit_popup: TagCommitComponent,
|
||||
create_branch_popup: CreateBranchComponent,
|
||||
rename_branch_popup: RenameBranchComponent,
|
||||
|
|
@ -158,6 +160,12 @@ impl App {
|
|||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
fetch_popup: FetchComponent::new(
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
tag_commit_popup: TagCommitComponent::new(
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
|
|
@ -389,6 +397,7 @@ impl App {
|
|||
self.push_popup.update_git(ev)?;
|
||||
self.push_tags_popup.update_git(ev)?;
|
||||
self.pull_popup.update_git(ev);
|
||||
self.fetch_popup.update_git(ev);
|
||||
self.select_branch_popup.update_git(ev)?;
|
||||
}
|
||||
|
||||
|
|
@ -421,6 +430,7 @@ impl App {
|
|||
|| self.push_popup.any_work_pending()
|
||||
|| self.push_tags_popup.any_work_pending()
|
||||
|| self.pull_popup.any_work_pending()
|
||||
|| self.fetch_popup.any_work_pending()
|
||||
|| self.revision_files_popup.any_work_pending()
|
||||
|| self.tags_popup.any_work_pending()
|
||||
}
|
||||
|
|
@ -453,6 +463,7 @@ impl App {
|
|||
push_popup,
|
||||
push_tags_popup,
|
||||
pull_popup,
|
||||
fetch_popup,
|
||||
tag_commit_popup,
|
||||
create_branch_popup,
|
||||
rename_branch_popup,
|
||||
|
|
@ -489,6 +500,7 @@ impl App {
|
|||
push_popup,
|
||||
push_tags_popup,
|
||||
pull_popup,
|
||||
fetch_popup,
|
||||
options_popup,
|
||||
reset,
|
||||
msg
|
||||
|
|
@ -696,6 +708,14 @@ impl App {
|
|||
}
|
||||
flags.insert(NeedsUpdate::ALL);
|
||||
}
|
||||
InternalEvent::FetchRemotes => {
|
||||
if let Err(error) = self.fetch_popup.fetch() {
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(
|
||||
error.to_string(),
|
||||
));
|
||||
}
|
||||
flags.insert(NeedsUpdate::ALL);
|
||||
}
|
||||
InternalEvent::PushTags => {
|
||||
self.push_tags_popup.push_tags()?;
|
||||
flags.insert(NeedsUpdate::ALL);
|
||||
|
|
|
|||
|
|
@ -196,6 +196,12 @@ impl Component for BranchListComponent {
|
|||
true,
|
||||
self.local,
|
||||
));
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::fetch_remotes(&self.key_config),
|
||||
true,
|
||||
!self.local,
|
||||
));
|
||||
}
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
|
@ -290,6 +296,8 @@ impl Component for BranchListComponent {
|
|||
self.queue
|
||||
.push(InternalEvent::CompareCommits(b, None));
|
||||
}
|
||||
} else if e == self.key_config.keys.pull && !self.local {
|
||||
self.queue.push(InternalEvent::FetchRemotes);
|
||||
} else if e == self.key_config.keys.cmd_bar_toggle {
|
||||
//do not consume if its the more key
|
||||
return Ok(EventState::NotConsumed);
|
||||
|
|
|
|||
211
src/components/fetch.rs
Normal file
211
src/components/fetch.rs
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
use crate::{
|
||||
components::{
|
||||
cred::CredComponent, visibility_blocking, CommandBlocking,
|
||||
CommandInfo, Component, DrawableComponent, EventState,
|
||||
},
|
||||
keys::SharedKeyConfig,
|
||||
queue::{InternalEvent, NeedsUpdate, Queue},
|
||||
strings,
|
||||
ui::{self, style::SharedTheme},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
asyncjob::AsyncSingleJob,
|
||||
sync::cred::{
|
||||
extract_username_password, need_username_password,
|
||||
BasicAuthCredential,
|
||||
},
|
||||
AsyncFetchJob, AsyncGitNotification, ProgressPercent,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::Rect,
|
||||
text::Span,
|
||||
widgets::{Block, BorderType, Borders, Clear, Gauge},
|
||||
Frame,
|
||||
};
|
||||
|
||||
///
|
||||
pub struct FetchComponent {
|
||||
visible: bool,
|
||||
async_fetch: AsyncSingleJob<AsyncFetchJob>,
|
||||
progress: Option<ProgressPercent>,
|
||||
pending: bool,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
input_cred: CredComponent,
|
||||
}
|
||||
|
||||
impl FetchComponent {
|
||||
///
|
||||
pub fn new(
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
queue: queue.clone(),
|
||||
pending: false,
|
||||
visible: false,
|
||||
async_fetch: AsyncSingleJob::new(sender.clone()),
|
||||
progress: None,
|
||||
input_cred: CredComponent::new(
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
theme,
|
||||
key_config,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn fetch(&mut self) -> Result<()> {
|
||||
self.show()?;
|
||||
if need_username_password()? {
|
||||
let cred =
|
||||
extract_username_password().unwrap_or_else(|_| {
|
||||
BasicAuthCredential::new(None, None)
|
||||
});
|
||||
if cred.is_complete() {
|
||||
self.fetch_all(Some(cred));
|
||||
} else {
|
||||
self.input_cred.set_cred(cred);
|
||||
self.input_cred.show()?;
|
||||
}
|
||||
} else {
|
||||
self.fetch_all(None);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch_all(&mut self, cred: Option<BasicAuthCredential>) {
|
||||
self.pending = true;
|
||||
self.progress = None;
|
||||
self.progress = Some(ProgressPercent::empty());
|
||||
self.async_fetch.spawn(AsyncFetchJob::new(cred));
|
||||
}
|
||||
|
||||
///
|
||||
pub const fn any_work_pending(&self) -> bool {
|
||||
self.pending
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update_git(&mut self, ev: AsyncGitNotification) {
|
||||
if self.is_visible() && ev == AsyncGitNotification::Fetch {
|
||||
self.update();
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
fn update(&mut self) {
|
||||
self.pending = self.async_fetch.is_pending();
|
||||
self.progress = self.async_fetch.progress();
|
||||
|
||||
if !self.pending {
|
||||
self.hide();
|
||||
self.queue
|
||||
.push(InternalEvent::Update(NeedsUpdate::BRANCHES));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawableComponent for FetchComponent {
|
||||
fn draw<B: Backend>(
|
||||
&self,
|
||||
f: &mut Frame<B>,
|
||||
rect: Rect,
|
||||
) -> Result<()> {
|
||||
if self.visible {
|
||||
let progress = self.progress.unwrap_or_default().progress;
|
||||
|
||||
let area = ui::centered_rect_absolute(30, 3, f.size());
|
||||
|
||||
f.render_widget(Clear, area);
|
||||
f.render_widget(
|
||||
Gauge::default()
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled(
|
||||
strings::FETCH_POPUP_MSG,
|
||||
self.theme.title(true),
|
||||
))
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Thick)
|
||||
.border_style(self.theme.block(true)),
|
||||
)
|
||||
.gauge_style(self.theme.push_gauge())
|
||||
.percent(u16::from(progress)),
|
||||
area,
|
||||
);
|
||||
self.input_cred.draw(f, rect)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for FetchComponent {
|
||||
fn commands(
|
||||
&self,
|
||||
out: &mut Vec<CommandInfo>,
|
||||
force_all: bool,
|
||||
) -> CommandBlocking {
|
||||
if self.is_visible() || force_all {
|
||||
if !force_all {
|
||||
out.clear();
|
||||
}
|
||||
|
||||
if self.input_cred.is_visible() {
|
||||
return self.input_cred.commands(out, force_all);
|
||||
}
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::close_msg(&self.key_config),
|
||||
!self.pending,
|
||||
self.visible,
|
||||
));
|
||||
}
|
||||
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
||||
fn event(&mut self, ev: Event) -> Result<EventState> {
|
||||
if self.visible {
|
||||
if let Event::Key(_) = ev {
|
||||
if self.input_cred.is_visible() {
|
||||
self.input_cred.event(ev)?;
|
||||
|
||||
if self.input_cred.get_cred().is_complete()
|
||||
|| !self.input_cred.is_visible()
|
||||
{
|
||||
self.fetch_all(Some(
|
||||
self.input_cred.get_cred().clone(),
|
||||
));
|
||||
self.input_cred.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(EventState::Consumed);
|
||||
}
|
||||
Ok(EventState::NotConsumed)
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
self.visible
|
||||
}
|
||||
|
||||
fn hide(&mut self) {
|
||||
self.visible = false;
|
||||
}
|
||||
|
||||
fn show(&mut self) -> Result<()> {
|
||||
self.visible = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ mod create_branch;
|
|||
mod cred;
|
||||
mod diff;
|
||||
mod externaleditor;
|
||||
mod fetch;
|
||||
mod file_find_popup;
|
||||
mod filetree;
|
||||
mod help;
|
||||
|
|
@ -42,6 +43,7 @@ pub use compare_commits::CompareCommitsComponent;
|
|||
pub use create_branch::CreateBranchComponent;
|
||||
pub use diff::DiffComponent;
|
||||
pub use externaleditor::ExternalEditorComponent;
|
||||
pub use fetch::FetchComponent;
|
||||
pub use file_find_popup::FileFindPopup;
|
||||
pub use help::HelpComponent;
|
||||
pub use inspect_commit::InspectCommitComponent;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use asyncgit::{
|
|||
},
|
||||
get_default_remote,
|
||||
},
|
||||
AsyncFetch, AsyncGitNotification, FetchRequest, RemoteProgress,
|
||||
AsyncGitNotification, AsyncPull, FetchRequest, RemoteProgress,
|
||||
CWD,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
|
|
@ -35,7 +35,7 @@ use tui::{
|
|||
///
|
||||
pub struct PullComponent {
|
||||
visible: bool,
|
||||
git_fetch: AsyncFetch,
|
||||
git_fetch: AsyncPull,
|
||||
progress: Option<RemoteProgress>,
|
||||
pending: bool,
|
||||
branch: String,
|
||||
|
|
@ -58,7 +58,7 @@ impl PullComponent {
|
|||
pending: false,
|
||||
visible: false,
|
||||
branch: String::new(),
|
||||
git_fetch: AsyncFetch::new(sender),
|
||||
git_fetch: AsyncPull::new(sender),
|
||||
progress: None,
|
||||
input_cred: CredComponent::new(
|
||||
theme.clone(),
|
||||
|
|
@ -111,7 +111,7 @@ impl PullComponent {
|
|||
|
||||
///
|
||||
pub fn update_git(&mut self, ev: AsyncGitNotification) {
|
||||
if self.is_visible() && ev == AsyncGitNotification::Fetch {
|
||||
if self.is_visible() && ev == AsyncGitNotification::Pull {
|
||||
if let Err(error) = self.update() {
|
||||
self.pending = false;
|
||||
self.hide();
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ pub struct KeysListFile {
|
|||
}
|
||||
|
||||
impl KeysListFile {
|
||||
#[allow(dead_code)]
|
||||
pub fn read_file(config_file: PathBuf) -> Result<Self> {
|
||||
let mut f = File::open(config_file)?;
|
||||
let mut buffer = Vec::new();
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ pub enum InternalEvent {
|
|||
OpenFileFinder(Vec<TreeFile>),
|
||||
///
|
||||
FileFinderChanged(Option<PathBuf>),
|
||||
///
|
||||
FetchRemotes,
|
||||
}
|
||||
|
||||
/// single threaded simple queue for components to communicate with each other
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub mod order {
|
|||
pub static PUSH_POPUP_MSG: &str = "Push";
|
||||
pub static FORCE_PUSH_POPUP_MSG: &str = "Force Push";
|
||||
pub static PULL_POPUP_MSG: &str = "Pull";
|
||||
pub static FETCH_POPUP_MSG: &str = "Fetch";
|
||||
pub static PUSH_POPUP_PROGRESS_NONE: &str = "preparing...";
|
||||
pub static PUSH_POPUP_STATES_ADDING: &str = "adding objects (1/3)";
|
||||
pub static PUSH_POPUP_STATES_DELTAS: &str = "deltas (2/3)";
|
||||
|
|
@ -1266,4 +1267,17 @@ pub mod commands {
|
|||
CMD_GROUP_GENERAL,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn fetch_remotes(
|
||||
key_config: &SharedKeyConfig,
|
||||
) -> CommandText {
|
||||
CommandText::new(
|
||||
format!(
|
||||
"Fetch [{}]",
|
||||
key_config.get_hint(key_config.keys.pull),
|
||||
),
|
||||
"fetch/prune",
|
||||
CMD_GROUP_BRANCHES,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ impl Status {
|
|||
AsyncGitNotification::Diff => self.update_diff()?,
|
||||
AsyncGitNotification::Status => self.update_status()?,
|
||||
AsyncGitNotification::Push
|
||||
| AsyncGitNotification::Fetch
|
||||
| AsyncGitNotification::Pull
|
||||
| AsyncGitNotification::CommitFiles => {
|
||||
self.branch_compare();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue