mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 17:08:21 +00:00
Display mark for remote branches with tracking branches (#861)
This commit is contained in:
parent
1faba1760c
commit
13a0f4e9e2
2 changed files with 108 additions and 18 deletions
|
|
@ -5,6 +5,8 @@ pub mod merge_ff;
|
||||||
pub mod merge_rebase;
|
pub mod merge_rebase;
|
||||||
pub mod rename;
|
pub mod rename;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
remotes::get_default_remote_in_repo, utils::bytes2string,
|
remotes::get_default_remote_in_repo, utils::bytes2string,
|
||||||
};
|
};
|
||||||
|
|
@ -55,13 +57,20 @@ pub struct LocalBranch {
|
||||||
pub remote: Option<String>,
|
pub remote: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RemoteBranch {
|
||||||
|
///
|
||||||
|
pub has_tracking: bool,
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BranchDetails {
|
pub enum BranchDetails {
|
||||||
///
|
///
|
||||||
Local(LocalBranch),
|
Local(LocalBranch),
|
||||||
///
|
///
|
||||||
Remote,
|
Remote(RemoteBranch),
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
@ -107,13 +116,26 @@ pub fn get_branches_info(
|
||||||
) -> Result<Vec<BranchInfo>> {
|
) -> Result<Vec<BranchInfo>> {
|
||||||
scope_time!("get_branches_info");
|
scope_time!("get_branches_info");
|
||||||
|
|
||||||
let filter = if local {
|
let repo = utils::repo(repo_path)?;
|
||||||
BranchType::Local
|
|
||||||
|
let (filter, remotes_with_tracking) = if local {
|
||||||
|
(BranchType::Local, HashSet::default())
|
||||||
} else {
|
} else {
|
||||||
BranchType::Remote
|
let remotes: HashSet<_> = repo
|
||||||
|
.branches(Some(BranchType::Local))?
|
||||||
|
.filter_map(|b| {
|
||||||
|
let branch = b.ok()?.0;
|
||||||
|
let upstream = branch.upstream();
|
||||||
|
upstream
|
||||||
|
.ok()?
|
||||||
|
.name_bytes()
|
||||||
|
.ok()
|
||||||
|
.map(ToOwned::to_owned)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
(BranchType::Remote, remotes)
|
||||||
};
|
};
|
||||||
|
|
||||||
let repo = utils::repo(repo_path)?;
|
|
||||||
let mut branches_for_display: Vec<BranchInfo> = repo
|
let mut branches_for_display: Vec<BranchInfo> = repo
|
||||||
.branches(Some(filter))?
|
.branches(Some(filter))?
|
||||||
.map(|b| {
|
.map(|b| {
|
||||||
|
|
@ -129,6 +151,8 @@ pub fn get_branches_info(
|
||||||
.and_then(git2::Buf::as_str)
|
.and_then(git2::Buf::as_str)
|
||||||
.map(String::from);
|
.map(String::from);
|
||||||
|
|
||||||
|
let name_bytes = branch.name_bytes()?;
|
||||||
|
|
||||||
let details = if local {
|
let details = if local {
|
||||||
BranchDetails::Local(LocalBranch {
|
BranchDetails::Local(LocalBranch {
|
||||||
is_head: branch.is_head(),
|
is_head: branch.is_head(),
|
||||||
|
|
@ -136,11 +160,14 @@ pub fn get_branches_info(
|
||||||
remote,
|
remote,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
BranchDetails::Remote
|
BranchDetails::Remote(RemoteBranch {
|
||||||
|
has_tracking: remotes_with_tracking
|
||||||
|
.contains(name_bytes),
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(BranchInfo {
|
Ok(BranchInfo {
|
||||||
name: bytes2string(branch.name_bytes()?)?,
|
name: bytes2string(name_bytes)?,
|
||||||
reference,
|
reference,
|
||||||
top_commit_message: bytes2string(
|
top_commit_message: bytes2string(
|
||||||
top_commit.summary_bytes().unwrap_or_default(),
|
top_commit.summary_bytes().unwrap_or_default(),
|
||||||
|
|
@ -668,6 +695,17 @@ mod test_remote_branches {
|
||||||
repo_clone, repo_init_bare, write_commit_file,
|
repo_clone, repo_init_bare, write_commit_file,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
impl BranchInfo {
|
||||||
|
/// returns details about remote branch or None
|
||||||
|
const fn remote_details(&self) -> Option<&RemoteBranch> {
|
||||||
|
if let BranchDetails::Remote(details) = &self.details {
|
||||||
|
Some(details)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_remote_branches() {
|
fn test_remote_branches() {
|
||||||
let (r1_dir, _repo) = repo_init_bare().unwrap();
|
let (r1_dir, _repo) = repo_init_bare().unwrap();
|
||||||
|
|
@ -756,4 +794,49 @@ mod test_remote_branches {
|
||||||
|
|
||||||
assert_eq!(&get_branch_name(clone2_dir).unwrap(), "foo");
|
assert_eq!(&get_branch_name(clone2_dir).unwrap(), "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_has_tracking() {
|
||||||
|
let (r1_dir, _repo) = repo_init_bare().unwrap();
|
||||||
|
|
||||||
|
let (clone1_dir, clone1) =
|
||||||
|
repo_clone(r1_dir.path().to_str().unwrap()).unwrap();
|
||||||
|
let clone1_dir = clone1_dir.path().to_str().unwrap();
|
||||||
|
|
||||||
|
// clone1
|
||||||
|
|
||||||
|
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||||
|
push(
|
||||||
|
clone1_dir, "origin", "master", false, false, None, None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
create_branch(clone1_dir, "foo").unwrap();
|
||||||
|
write_commit_file(&clone1, "test.txt", "test2", "commit2");
|
||||||
|
push(clone1_dir, "origin", "foo", false, false, None, None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let branches_1 =
|
||||||
|
get_branches_info(clone1_dir, false).unwrap();
|
||||||
|
|
||||||
|
assert!(branches_1[0].remote_details().unwrap().has_tracking);
|
||||||
|
assert!(branches_1[1].remote_details().unwrap().has_tracking);
|
||||||
|
|
||||||
|
// clone2
|
||||||
|
|
||||||
|
let (clone2_dir, _clone2) =
|
||||||
|
repo_clone(r1_dir.path().to_str().unwrap()).unwrap();
|
||||||
|
|
||||||
|
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||||
|
|
||||||
|
let branches_2 =
|
||||||
|
get_branches_info(clone2_dir, false).unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!branches_2[0].remote_details().unwrap().has_tracking
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!branches_2[1].remote_details().unwrap().has_tracking
|
||||||
|
);
|
||||||
|
assert!(branches_2[2].remote_details().unwrap().has_tracking);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,12 @@ use crate::{
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use asyncgit::{
|
use asyncgit::{
|
||||||
sync::{
|
sync::{
|
||||||
self, branch::checkout_remote_branch, checkout_branch,
|
self,
|
||||||
get_branches_info, BranchInfo, CommitId,
|
branch::{
|
||||||
|
checkout_remote_branch, BranchDetails, LocalBranch,
|
||||||
|
RemoteBranch,
|
||||||
|
},
|
||||||
|
checkout_branch, get_branches_info, BranchInfo, CommitId,
|
||||||
},
|
},
|
||||||
AsyncGitNotification, CWD,
|
AsyncGitNotification, CWD,
|
||||||
};
|
};
|
||||||
|
|
@ -415,6 +419,7 @@ impl BranchListComponent {
|
||||||
height: usize,
|
height: usize,
|
||||||
) -> Text {
|
) -> Text {
|
||||||
const UPSTREAM_SYMBOL: char = '\u{2191}';
|
const UPSTREAM_SYMBOL: char = '\u{2191}';
|
||||||
|
const TRACKING_SYMBOL: char = '\u{2193}';
|
||||||
const HEAD_SYMBOL: char = '*';
|
const HEAD_SYMBOL: char = '*';
|
||||||
const EMPTY_SYMBOL: char = ' ';
|
const EMPTY_SYMBOL: char = ' ';
|
||||||
const THREE_DOTS: &str = "...";
|
const THREE_DOTS: &str = "...";
|
||||||
|
|
@ -473,18 +478,20 @@ impl BranchListComponent {
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let is_head_str =
|
let is_head_str =
|
||||||
if is_head { HEAD_SYMBOL } else { EMPTY_SYMBOL };
|
if is_head { HEAD_SYMBOL } else { EMPTY_SYMBOL };
|
||||||
let has_upstream_str = if displaybranch
|
let upstream_tracking_str = match displaybranch.details {
|
||||||
.local_details()
|
BranchDetails::Local(LocalBranch {
|
||||||
.map(|details| details.has_upstream)
|
has_upstream,
|
||||||
.unwrap_or_default()
|
..
|
||||||
{
|
}) if has_upstream => UPSTREAM_SYMBOL,
|
||||||
UPSTREAM_SYMBOL
|
BranchDetails::Remote(RemoteBranch {
|
||||||
} else {
|
has_tracking,
|
||||||
EMPTY_SYMBOL
|
..
|
||||||
|
}) if has_tracking => TRACKING_SYMBOL,
|
||||||
|
_ => EMPTY_SYMBOL,
|
||||||
};
|
};
|
||||||
|
|
||||||
let span_prefix = Span::styled(
|
let span_prefix = Span::styled(
|
||||||
format!("{}{} ", is_head_str, has_upstream_str),
|
format!("{}{} ", is_head_str, upstream_tracking_str),
|
||||||
theme.commit_author(selected),
|
theme.commit_author(selected),
|
||||||
);
|
);
|
||||||
let span_hash = Span::styled(
|
let span_hash = Span::styled(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue