fix sorting of commits in diff view (#1747)

This commit is contained in:
Joshix-1 2024-02-12 19:33:46 +00:00 committed by GitHub
parent 1fa6f9b725
commit 7335cd1c5d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 105 additions and 61 deletions

View file

@ -77,6 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* fix expansion of `~` in `commit.template` ([#1745](https://github.com/extrawurst/gitui/pull/1745)) * fix expansion of `~` in `commit.template` ([#1745](https://github.com/extrawurst/gitui/pull/1745))
* fix hunk (un)staging/reset for # of context lines != 3 ([#1746](https://github.com/extrawurst/gitui/issues/1746)) * fix hunk (un)staging/reset for # of context lines != 3 ([#1746](https://github.com/extrawurst/gitui/issues/1746))
* fix delay when opening external editor ([#1506](https://github.com/extrawurst/gitui/issues/1506)) * fix delay when opening external editor ([#1506](https://github.com/extrawurst/gitui/issues/1506))
* fix ordering of commits in diff view [[@Joshix-1](https://github.com/Joshix-1)]([#1747](https://github.com/extrawurst/gitui/issues/1747))
### Changed ### Changed
* Copy full Commit Hash by default [[@AmmarAbouZor](https://github.com/AmmarAbouZor)] ([#1836](https://github.com/extrawurst/gitui/issues/1836)) * Copy full Commit Hash by default [[@AmmarAbouZor](https://github.com/AmmarAbouZor)] ([#1836](https://github.com/extrawurst/gitui/issues/1836))

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
error::Result, error::Result,
sync::{self, CommitId, RepoPath}, sync::{self, commit_files::OldNew, CommitId, RepoPath},
AsyncGitNotification, StatusItem, AsyncGitNotification, StatusItem,
}; };
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
@ -36,6 +36,15 @@ impl From<(CommitId, CommitId)> for CommitFilesParams {
} }
} }
impl From<OldNew<CommitId>> for CommitFilesParams {
fn from(old_new: OldNew<CommitId>) -> Self {
Self {
id: old_new.new,
other: Some(old_new.old),
}
}
}
/// ///
pub struct AsyncCommitFiles { pub struct AsyncCommitFiles {
current: current:

View file

@ -1,7 +1,10 @@
use crate::{ use crate::{
error::Result, error::Result,
hash, hash,
sync::{self, diff::DiffOptions, CommitId, RepoPath}, sync::{
self, commit_files::OldNew, diff::DiffOptions, CommitId,
RepoPath,
},
AsyncGitNotification, FileDiff, AsyncGitNotification, FileDiff,
}; };
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
@ -17,7 +20,7 @@ use std::{
#[derive(Debug, Hash, Clone, PartialEq, Eq)] #[derive(Debug, Hash, Clone, PartialEq, Eq)]
pub enum DiffType { pub enum DiffType {
/// diff two commits /// diff two commits
Commits((CommitId, CommitId)), Commits(OldNew<CommitId>),
/// diff in a given commit /// diff in a given commit
Commit(CommitId), Commit(CommitId),
/// diff against staged file /// diff against staged file

View file

@ -8,7 +8,37 @@ use crate::{
}; };
use git2::{Diff, Repository}; use git2::{Diff, Repository};
use scopetime::scope_time; use scopetime::scope_time;
use std::{cmp::Ordering, collections::HashSet}; use std::collections::HashSet;
/// struct containing a new and an old version
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct OldNew<T> {
/// The old version
pub old: T,
/// The new version
pub new: T,
}
/// Sort two commits.
pub fn sort_commits(
repo: &Repository,
commits: (CommitId, CommitId),
) -> Result<OldNew<CommitId>> {
if repo.graph_descendant_of(
commits.0.get_oid(),
commits.1.get_oid(),
)? {
Ok(OldNew {
old: commits.1,
new: commits.0,
})
} else {
Ok(OldNew {
old: commits.0,
new: commits.1,
})
}
}
/// get all files that are part of a commit /// get all files that are part of a commit
pub fn get_commit_files( pub fn get_commit_files(
@ -21,7 +51,12 @@ pub fn get_commit_files(
let repo = repo(repo_path)?; let repo = repo(repo_path)?;
let diff = if let Some(other) = other { let diff = if let Some(other) = other {
get_compare_commits_diff(&repo, (id, other), None, None)? get_compare_commits_diff(
&repo,
sort_commits(&repo, (id, other))?,
None,
None,
)?
} else { } else {
get_commit_diff( get_commit_diff(
&repo, &repo,
@ -55,26 +90,20 @@ pub fn get_commit_files(
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn get_compare_commits_diff( pub fn get_compare_commits_diff(
repo: &Repository, repo: &Repository,
ids: (CommitId, CommitId), ids: OldNew<CommitId>,
pathspec: Option<String>, pathspec: Option<String>,
options: Option<DiffOptions>, options: Option<DiffOptions>,
) -> Result<Diff<'_>> { ) -> Result<Diff<'_>> {
// scope_time!("get_compare_commits_diff"); // scope_time!("get_compare_commits_diff");
let commits = OldNew {
let commits = ( old: repo.find_commit(ids.old.into())?,
repo.find_commit(ids.0.into())?, new: repo.find_commit(ids.new.into())?,
repo.find_commit(ids.1.into())?,
);
let commits = if commits.0.time().cmp(&commits.1.time())
== Ordering::Greater
{
(commits.1, commits.0)
} else {
commits
}; };
let trees = (commits.0.tree()?, commits.1.tree()?); let trees = OldNew {
old: commits.old.tree()?,
new: commits.new.tree()?,
};
let mut opts = git2::DiffOptions::new(); let mut opts = git2::DiffOptions::new();
if let Some(options) = options { if let Some(options) = options {
@ -86,9 +115,9 @@ pub fn get_compare_commits_diff(
opts.pathspec(p.clone()); opts.pathspec(p.clone());
} }
let diff = repo.diff_tree_to_tree( let diff: Diff<'_> = repo.diff_tree_to_tree(
Some(&trees.0), Some(&trees.old),
Some(&trees.1), Some(&trees.new),
Some(&mut opts), Some(&mut opts),
)?; )?;

View file

@ -1,7 +1,9 @@
//! sync git api for fetching a diff //! sync git api for fetching a diff
use super::{ use super::{
commit_files::{get_commit_diff, get_compare_commits_diff}, commit_files::{
get_commit_diff, get_compare_commits_diff, OldNew,
},
utils::{get_head_repo, work_dir}, utils::{get_head_repo, work_dir},
CommitId, RepoPath, CommitId, RepoPath,
}; };
@ -240,7 +242,7 @@ pub fn get_diff_commit(
/// get file changes of a diff between two commits /// get file changes of a diff between two commits
pub fn get_diff_commits( pub fn get_diff_commits(
repo_path: &RepoPath, repo_path: &RepoPath,
ids: (CommitId, CommitId), ids: OldNew<CommitId>,
p: String, p: String,
options: Option<DiffOptions>, options: Option<DiffOptions>,
) -> Result<FileDiff> { ) -> Result<FileDiff> {
@ -248,12 +250,8 @@ pub fn get_diff_commits(
let repo = repo(repo_path)?; let repo = repo(repo_path)?;
let work_dir = work_dir(&repo)?; let work_dir = work_dir(&repo)?;
let diff = get_compare_commits_diff( let diff =
&repo, get_compare_commits_diff(&repo, ids, Some(p), options)?;
(ids.0, ids.1),
Some(p),
options,
)?;
raw_diff_to_file_diff(&diff, work_dir) raw_diff_to_file_diff(&diff, work_dir)
} }

View file

@ -13,7 +13,9 @@ use crate::{
ui::style::SharedTheme, ui::style::SharedTheme,
}; };
use anyhow::Result; use anyhow::Result;
use asyncgit::sync::{self, CommitDetails, CommitId, RepoPathRef}; use asyncgit::sync::{
self, commit_files::OldNew, CommitDetails, CommitId, RepoPathRef,
};
use crossterm::event::Event; use crossterm::event::Event;
use ratatui::{ use ratatui::{
backend::Backend, backend::Backend,
@ -24,7 +26,7 @@ use ratatui::{
pub struct CompareDetailsComponent { pub struct CompareDetailsComponent {
repo: RepoPathRef, repo: RepoPathRef,
data: Option<(CommitDetails, CommitDetails)>, data: Option<OldNew<CommitDetails>>,
theme: SharedTheme, theme: SharedTheme,
focused: bool, focused: bool,
} }
@ -40,24 +42,20 @@ impl CompareDetailsComponent {
} }
} }
pub fn set_commits(&mut self, ids: Option<(CommitId, CommitId)>) { pub fn set_commits(&mut self, ids: Option<OldNew<CommitId>>) {
self.data = ids.and_then(|ids| { self.data = ids.and_then(|ids| {
let c1 = let old = sync::get_commit_details(
sync::get_commit_details(&self.repo.borrow(), ids.0) &self.repo.borrow(),
.ok(); ids.old,
let c2 = )
sync::get_commit_details(&self.repo.borrow(), ids.1) .ok()?;
.ok(); let new = sync::get_commit_details(
&self.repo.borrow(),
ids.new,
)
.ok()?;
c1.and_then(|c1| { Some(OldNew { old, new })
c2.map(|c2| {
if c1.author.time < c2.author.time {
(c1, c2)
} else {
(c2, c1)
}
})
})
}); });
} }
@ -122,9 +120,9 @@ impl DrawableComponent for CompareDetailsComponent {
dialog_paragraph( dialog_paragraph(
&strings::commit::compare_details_info_title( &strings::commit::compare_details_info_title(
true, true,
data.0.short_hash(), data.old.short_hash(),
), ),
Text::from(self.get_commit_text(&data.0)), Text::from(self.get_commit_text(&data.old)),
&self.theme, &self.theme,
false, false,
), ),
@ -135,9 +133,9 @@ impl DrawableComponent for CompareDetailsComponent {
dialog_paragraph( dialog_paragraph(
&strings::commit::compare_details_info_title( &strings::commit::compare_details_info_title(
false, false,
data.1.short_hash(), data.new.short_hash(),
), ),
Text::from(self.get_commit_text(&data.1)), Text::from(self.get_commit_text(&data.new)),
&self.theme, &self.theme,
false, false,
), ),

View file

@ -14,7 +14,8 @@ use crate::{
}; };
use anyhow::Result; use anyhow::Result;
use asyncgit::{ use asyncgit::{
sync::CommitTags, AsyncCommitFiles, CommitFilesParams, sync::{commit_files::OldNew, CommitTags},
AsyncCommitFiles, CommitFilesParams,
}; };
use compare_details::CompareDetailsComponent; use compare_details::CompareDetailsComponent;
use crossterm::event::Event; use crossterm::event::Event;
@ -81,8 +82,10 @@ impl CommitDetailsComponent {
self.file_tree.set_commit(Some(id.id)); self.file_tree.set_commit(Some(id.id));
if let Some(other) = id.other { if let Some(other) = id.other {
self.compare_details self.compare_details.set_commits(Some(OldNew {
.set_commits(Some((id.id, other))); new: id.id,
old: other,
}));
} else { } else {
self.single_details self.single_details
.set_commit(Some(id.id), tags.clone()); .set_commit(Some(id.id), tags.clone());

View file

@ -13,7 +13,7 @@ use crate::{
}; };
use anyhow::Result; use anyhow::Result;
use asyncgit::{ use asyncgit::{
sync::{self, CommitId, RepoPathRef}, sync::{self, commit_files::OldNew, CommitId, RepoPathRef},
AsyncDiff, AsyncGitNotification, CommitFilesParams, DiffParams, AsyncDiff, AsyncGitNotification, CommitFilesParams, DiffParams,
DiffType, DiffType,
}; };
@ -222,16 +222,19 @@ impl CompareCommitsComponent {
Ok(()) Ok(())
} }
fn get_ids(&self) -> Option<(CommitId, CommitId)> { fn get_ids(&self) -> Option<OldNew<CommitId>> {
let other = self let other = self
.open_request .open_request
.as_ref() .as_ref()
.and_then(|open| open.compare_id); .and_then(|open| open.compare_id);
self.open_request let this =
.as_ref() self.open_request.as_ref().map(|open| open.commit_id);
.map(|open| open.commit_id)
.zip(other) Some(OldNew {
old: other?,
new: this?,
})
} }
/// called when any tree component changed selection /// called when any tree component changed selection