mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 01:18:21 +00:00
visualize outgoing/incoming changes (#364)
This commit is contained in:
parent
a2b26c30dc
commit
4ee4432f16
4 changed files with 91 additions and 9 deletions
|
|
@ -12,11 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- added gitui to [chocolatey](https://chocolatey.org/packages/gitui) on windows by [@nils-a](https://github.com/nils-a)
|
- added gitui to [chocolatey](https://chocolatey.org/packages/gitui) on windows by [@nils-a](https://github.com/nils-a)
|
||||||
- push to remote ([#265](https://github.com/extrawurst/gitui/issues/265)) ([#267](https://github.com/extrawurst/gitui/issues/267))
|
- push to remote ([#265](https://github.com/extrawurst/gitui/issues/265)) ([#267](https://github.com/extrawurst/gitui/issues/267))
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
- incoming/outgoing commits to upstream ([#362](https://github.com/extrawurst/gitui/issues/362))
|
||||||
- new branch list popup incl. checkout/delete/rename [[@WizardOhio24](https://github.com/WizardOhio24)] ([#303](https://github.com/extrawurst/gitui/issues/303)) ([#323](https://github.com/extrawurst/gitui/issues/323))
|
- new branch list popup incl. checkout/delete/rename [[@WizardOhio24](https://github.com/WizardOhio24)] ([#303](https://github.com/extrawurst/gitui/issues/303)) ([#323](https://github.com/extrawurst/gitui/issues/323))
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- scrollbar in long commit messages [[@timaliberdov](https://github.com/timaliberdov)] ([#308](https://github.com/extrawurst/gitui/issues/308))
|
- scrollbar in long commit messages [[@timaliberdov](https://github.com/timaliberdov)] ([#308](https://github.com/extrawurst/gitui/issues/308))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,12 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
sync::utils,
|
sync::{utils, CommitId},
|
||||||
};
|
};
|
||||||
use git2::BranchType;
|
use git2::BranchType;
|
||||||
use scopetime::scope_time;
|
use scopetime::scope_time;
|
||||||
use utils::get_head_repo;
|
use utils::get_head_repo;
|
||||||
|
|
||||||
use super::CommitId;
|
|
||||||
|
|
||||||
/// returns the branch-name head is currently pointing to
|
/// returns the branch-name head is currently pointing to
|
||||||
/// this might be expensive, see `cached::BranchName`
|
/// this might be expensive, see `cached::BranchName`
|
||||||
pub(crate) fn get_branch_name(repo_path: &str) -> Result<String> {
|
pub(crate) fn get_branch_name(repo_path: &str) -> Result<String> {
|
||||||
|
|
@ -79,6 +77,39 @@ pub fn get_branches_to_display(
|
||||||
Ok(branches_for_display)
|
Ok(branches_for_display)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct BranchCompare {
|
||||||
|
///
|
||||||
|
pub ahead: usize,
|
||||||
|
///
|
||||||
|
pub behind: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn branch_compare_upstream(
|
||||||
|
repo_path: &str,
|
||||||
|
branch: &str,
|
||||||
|
) -> Result<BranchCompare> {
|
||||||
|
scope_time!("branch_compare_upstream");
|
||||||
|
|
||||||
|
let repo = utils::repo(repo_path)?;
|
||||||
|
|
||||||
|
let branch = repo.find_branch(branch, BranchType::Local)?;
|
||||||
|
let upstream = branch.upstream()?;
|
||||||
|
|
||||||
|
let branch_commit =
|
||||||
|
branch.into_reference().peel_to_commit()?.id();
|
||||||
|
|
||||||
|
let upstream_commit =
|
||||||
|
upstream.into_reference().peel_to_commit()?.id();
|
||||||
|
|
||||||
|
let (ahead, behind) =
|
||||||
|
repo.graph_ahead_behind(branch_commit, upstream_commit)?;
|
||||||
|
|
||||||
|
Ok(BranchCompare { ahead, behind })
|
||||||
|
}
|
||||||
|
|
||||||
/// Modify HEAD to point to a branch then checkout head, does not work if there are uncommitted changes
|
/// Modify HEAD to point to a branch then checkout head, does not work if there are uncommitted changes
|
||||||
pub fn checkout_branch(
|
pub fn checkout_branch(
|
||||||
repo_path: &str,
|
repo_path: &str,
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@ pub mod utils;
|
||||||
|
|
||||||
pub(crate) use branch::get_branch_name;
|
pub(crate) use branch::get_branch_name;
|
||||||
pub use branch::{
|
pub use branch::{
|
||||||
checkout_branch, create_branch, delete_branch,
|
branch_compare_upstream, checkout_branch, create_branch,
|
||||||
get_branches_to_display, rename_branch, BranchForDisplay,
|
delete_branch, get_branches_to_display, rename_branch,
|
||||||
|
BranchCompare, BranchForDisplay,
|
||||||
};
|
};
|
||||||
pub use commit::{amend, commit, tag};
|
pub use commit::{amend, commit, tag};
|
||||||
pub use commit_details::{
|
pub use commit_details::{
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,17 @@ use crate::{
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use asyncgit::{
|
use asyncgit::{
|
||||||
|
sync::BranchCompare,
|
||||||
sync::{self, status::StatusType},
|
sync::{self, status::StatusType},
|
||||||
AsyncDiff, AsyncNotification, AsyncStatus, DiffParams, DiffType,
|
AsyncDiff, AsyncNotification, AsyncStatus, DiffParams, DiffType,
|
||||||
StatusParams, CWD,
|
StatusParams, CWD,
|
||||||
};
|
};
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use tui::layout::{Constraint, Direction, Layout};
|
use tui::{
|
||||||
|
layout::{Alignment, Constraint, Direction, Layout},
|
||||||
|
widgets::Paragraph,
|
||||||
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
|
@ -45,6 +49,7 @@ pub struct Status {
|
||||||
git_diff: AsyncDiff,
|
git_diff: AsyncDiff,
|
||||||
git_status_workdir: AsyncStatus,
|
git_status_workdir: AsyncStatus,
|
||||||
git_status_stage: AsyncStatus,
|
git_status_stage: AsyncStatus,
|
||||||
|
git_branch_state: BranchCompare,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
git_action_executed: bool,
|
git_action_executed: bool,
|
||||||
key_config: SharedKeyConfig,
|
key_config: SharedKeyConfig,
|
||||||
|
|
@ -95,6 +100,7 @@ impl DrawableComponent for Status {
|
||||||
self.index_wd.draw(f, left_chunks[0])?;
|
self.index_wd.draw(f, left_chunks[0])?;
|
||||||
self.index.draw(f, left_chunks[1])?;
|
self.index.draw(f, left_chunks[1])?;
|
||||||
self.diff.draw(f, chunks[1])?;
|
self.diff.draw(f, chunks[1])?;
|
||||||
|
self.draw_branch_state(f, &left_chunks);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -141,10 +147,38 @@ impl Status {
|
||||||
git_status_workdir: AsyncStatus::new(sender.clone()),
|
git_status_workdir: AsyncStatus::new(sender.clone()),
|
||||||
git_status_stage: AsyncStatus::new(sender.clone()),
|
git_status_stage: AsyncStatus::new(sender.clone()),
|
||||||
git_action_executed: false,
|
git_action_executed: false,
|
||||||
|
git_branch_state: BranchCompare::default(),
|
||||||
key_config,
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_branch_state<B: tui::backend::Backend>(
|
||||||
|
&self,
|
||||||
|
f: &mut tui::Frame<B>,
|
||||||
|
chunks: &[tui::layout::Rect],
|
||||||
|
) {
|
||||||
|
let w = Paragraph::new(format!(
|
||||||
|
"\u{2191}{} \u{2193}{}",
|
||||||
|
self.git_branch_state.ahead, self.git_branch_state.behind
|
||||||
|
))
|
||||||
|
.alignment(Alignment::Right);
|
||||||
|
|
||||||
|
let mut rect = if self.index_wd.focused() {
|
||||||
|
let mut rect = chunks[0];
|
||||||
|
rect.y += rect.height.saturating_sub(1);
|
||||||
|
rect
|
||||||
|
} else {
|
||||||
|
chunks[1]
|
||||||
|
};
|
||||||
|
|
||||||
|
rect.x += 1;
|
||||||
|
rect.width = rect.width.saturating_sub(2);
|
||||||
|
rect.height =
|
||||||
|
rect.height.saturating_sub(rect.height.saturating_sub(1));
|
||||||
|
|
||||||
|
f.render_widget(w, rect);
|
||||||
|
}
|
||||||
|
|
||||||
fn can_focus_diff(&self) -> bool {
|
fn can_focus_diff(&self) -> bool {
|
||||||
match self.focus {
|
match self.focus {
|
||||||
Focus::WorkDir => self.index_wd.is_file_seleted(),
|
Focus::WorkDir => self.index_wd.is_file_seleted(),
|
||||||
|
|
@ -216,6 +250,7 @@ impl Status {
|
||||||
.fetch(StatusParams::new(StatusType::Stage, true))?;
|
.fetch(StatusParams::new(StatusType::Stage, true))?;
|
||||||
|
|
||||||
self.index_wd.update()?;
|
self.index_wd.update()?;
|
||||||
|
self.check_branch_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -356,6 +391,20 @@ impl Status {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_branch_state(&mut self) {
|
||||||
|
self.git_branch_state = self.index_wd.branch_name().map_or(
|
||||||
|
BranchCompare::default(),
|
||||||
|
|branch| {
|
||||||
|
sync::branch_compare_upstream(CWD, branch.as_str())
|
||||||
|
.unwrap_or_default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn can_push(&self) -> bool {
|
||||||
|
self.git_branch_state.ahead > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Status {
|
impl Component for Status {
|
||||||
|
|
@ -381,7 +430,7 @@ impl Component for Status {
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
strings::commands::status_push(&self.key_config),
|
strings::commands::status_push(&self.key_config),
|
||||||
self.index_wd.branch_name().is_some(),
|
self.can_push(),
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue