This commit is contained in:
吴杨帆 2026-05-17 16:50:04 +08:00 committed by GitHub
commit 3004d6d577
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 99 additions and 9 deletions

View file

@ -145,6 +145,13 @@ impl AsyncLog {
Ok(false)
}
///
pub fn invalidate(&self) {
if let Ok(mut head) = self.current_head.lock() {
*head = None;
}
}
///
pub fn fetch(&self) -> Result<FetchStatus> {
self.background.store(false, Ordering::Relaxed);

View file

@ -222,3 +222,15 @@ pub fn filter_commit_by_search(
},
))
}
///
pub fn filter_commits_exclude_merges() -> SharedCommitFilterFn {
Arc::new(Box::new(
move |repo: &Repository,
commit_id: &CommitId|
-> Result<bool> {
let commit = repo.find_commit((*commit_id).into())?;
Ok(commit.parent_count() <= 1)
},
))
}

View file

@ -51,7 +51,8 @@ pub use commit_details::{
};
pub use commit_files::get_commit_files;
pub use commit_filter::{
diff_contains_file, filter_commit_by_search, LogFilterSearch,
diff_contains_file, filter_commit_by_search,
filter_commits_exclude_merges, LogFilterSearch,
LogFilterSearchOptions, SearchFields, SearchOptions,
SharedCommitFilterFn,
};

View file

@ -62,6 +62,10 @@ pub struct CommitList {
impl CommitList {
///
pub fn set_title(&mut self, title: impl Into<Box<str>>) {
self.title = title.into();
}
pub fn new(env: &Environment, title: &str) -> Self {
Self {
repo: env.repo.clone(),

View file

@ -88,6 +88,7 @@ pub struct KeysList {
pub log_reset_commit: GituiKeyEvent,
pub log_reword_commit: GituiKeyEvent,
pub log_find: GituiKeyEvent,
pub log_hide_merges: GituiKeyEvent,
pub find_commit_sha: GituiKeyEvent,
pub commit_amend: GituiKeyEvent,
pub toggle_signoff: GituiKeyEvent,
@ -186,6 +187,7 @@ impl Default for KeysList {
log_reset_commit: GituiKeyEvent { code: KeyCode::Char('R'), modifiers: KeyModifiers::SHIFT },
log_reword_commit: GituiKeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::empty() },
log_find: GituiKeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::empty() },
log_hide_merges: GituiKeyEvent::new(KeyCode::Char('M'), KeyModifiers::SHIFT),
find_commit_sha: GituiKeyEvent::new(KeyCode::Char('j'), KeyModifiers::CONTROL),
commit_amend: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
toggle_signoff: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::CONTROL),

View file

@ -300,8 +300,12 @@ pub fn confirm_msg_force_push(
"Confirm force push to branch '{branch_ref}' ? This may rewrite history."
)
}
pub fn log_title(_key_config: &SharedKeyConfig) -> String {
"Commit".to_string()
pub fn log_title(hide_merge_commits: bool) -> String {
if hide_merge_commits {
"Commit (no merges)".to_string()
} else {
"Commit".to_string()
}
}
pub fn file_log_title(
file_path: &str,
@ -1576,6 +1580,24 @@ pub mod commands {
CMD_GROUP_LOG,
)
}
pub fn log_toggle_hide_merges(
key_config: &SharedKeyConfig,
hide_merge_commits: bool,
) -> CommandText {
let action = if hide_merge_commits {
"show merge commits"
} else {
"hide merge commits"
};
CommandText::new(
format!(
"No merges [{}]",
key_config.get_hint(key_config.keys.log_hide_merges),
),
action,
CMD_GROUP_LOG,
)
}
pub fn log_find_commit(
key_config: &SharedKeyConfig,
) -> CommandText {

View file

@ -16,8 +16,8 @@ use anyhow::Result;
use asyncgit::{
asyncjob::AsyncSingleJob,
sync::{
self, filter_commit_by_search, CommitId, LogFilterSearch,
LogFilterSearchOptions, RepoPathRef,
self, filter_commit_by_search, filter_commits_exclude_merges,
CommitId, LogFilterSearch, LogFilterSearchOptions, RepoPathRef,
},
AsyncBranchesJob, AsyncCommitFilterJob, AsyncGitNotification,
AsyncLog, AsyncTags, CommitFilesParams, FetchStatus,
@ -66,6 +66,7 @@ pub struct Revlog {
list: CommitList,
git_log: AsyncLog,
search: LogSearch,
hide_merge_commits: bool,
git_tags: AsyncTags,
git_local_branches: AsyncSingleJob<AsyncBranchesJob>,
git_remote_branches: AsyncSingleJob<AsyncBranchesJob>,
@ -83,16 +84,14 @@ impl Revlog {
repo: env.repo.clone(),
queue: env.queue.clone(),
commit_details: CommitDetailsComponent::new(env),
list: CommitList::new(
env,
&strings::log_title(&env.key_config),
),
list: CommitList::new(env, &strings::log_title(false)),
git_log: AsyncLog::new(
env.repo.borrow().clone(),
&env.sender_git,
None,
),
search: LogSearch::Off,
hide_merge_commits: false,
git_tags: AsyncTags::new(
env.repo.borrow().clone(),
&env.sender_git,
@ -404,6 +403,34 @@ impl Revlog {
fn can_start_search(&self) -> bool {
!self.git_log.is_pending() && !self.is_search_pending()
}
fn can_toggle_hide_merges(&self) -> bool {
matches!(self.search, LogSearch::Off) && !self.git_log.is_pending()
}
fn toggle_hide_merge_commits(&mut self) {
if !self.can_toggle_hide_merges() {
return;
}
self.hide_merge_commits = !self.hide_merge_commits;
let filter = if self.hide_merge_commits {
Some(filter_commits_exclude_merges())
} else {
None
};
self.git_log = AsyncLog::new(
self.repo.borrow().clone(),
&self.sender,
filter,
);
self.git_log.invalidate();
self.list.clear();
self.list
.set_title(strings::log_title(self.hide_merge_commits));
let _ = self.git_log.fetch();
}
}
impl DrawableComponent for Revlog {
@ -575,6 +602,13 @@ impl Component for Revlog {
self.queue
.push(InternalEvent::OpenLogSearchPopup);
return Ok(EventState::Consumed);
} else if key_match(
k,
self.key_config.keys.log_hide_merges,
) && self.can_toggle_hide_merges()
{
self.toggle_hide_merge_commits();
return Ok(EventState::Consumed);
} else if key_match(
k,
self.key_config.keys.compare_commits,
@ -729,6 +763,14 @@ impl Component for Revlog {
self.can_start_search(),
self.visible || force_all,
));
out.push(CommandInfo::new(
strings::commands::log_toggle_hide_merges(
&self.key_config,
self.hide_merge_commits,
),
self.can_toggle_hide_merges(),
self.visible || force_all,
));
visibility_blocking(self)
}