Skip to content

Commit 92ef9f6

Browse files
authored
Respect .mailmap (#2485)
1 parent 3ede6b5 commit 92ef9f6

File tree

4 files changed

+78
-19
lines changed

4 files changed

+78
-19
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
* use OSC52 copying in case other methods fail [[@naseschwarz](https://github.com/naseschwarz)] ([#2366](https://github.com/gitui-org/gitui/issues/2366))
2020
* push: respect `branch.*.merge` when push default is upstream [[@vlad-anger](https://github.com/vlad-anger)] ([#2542](https://github.com/gitui-org/gitui/pull/2542))
2121
* set the terminal title to `gitui ({repo_path})` [[@acuteenvy](https://github.com/acuteenvy)] ([#2462](https://github.com/gitui-org/gitui/issues/2462))
22+
* respect `.mailmap` [[@acuteenvy](https://github.com/acuteenvy)] ([#2406](https://github.com/gitui-org/gitui/issues/2406))
2223

2324
## [0.27.0] - 2024-01-14
2425

asyncgit/src/sync/commit_details.rs

+44-2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,42 @@ impl CommitDetails {
8787
}
8888
}
8989

90+
/// Get the author of a commit.
91+
pub fn get_author_of_commit<'a>(
92+
commit: &'a git2::Commit<'a>,
93+
mailmap: &git2::Mailmap,
94+
) -> git2::Signature<'a> {
95+
match commit.author_with_mailmap(mailmap) {
96+
Ok(author) => author,
97+
Err(e) => {
98+
log::error!(
99+
"Couldn't get author with mailmap for {} (message: {:?}): {e}",
100+
commit.id(),
101+
commit.message(),
102+
);
103+
commit.author()
104+
}
105+
}
106+
}
107+
108+
/// Get the committer of a commit.
109+
pub fn get_committer_of_commit<'a>(
110+
commit: &'a git2::Commit<'a>,
111+
mailmap: &git2::Mailmap,
112+
) -> git2::Signature<'a> {
113+
match commit.committer_with_mailmap(mailmap) {
114+
Ok(committer) => committer,
115+
Err(e) => {
116+
log::error!(
117+
"Couldn't get committer with mailmap for {} (message: {:?}): {e}",
118+
commit.id(),
119+
commit.message(),
120+
);
121+
commit.committer()
122+
}
123+
}
124+
}
125+
90126
///
91127
pub fn get_commit_details(
92128
repo_path: &RepoPath,
@@ -95,11 +131,17 @@ pub fn get_commit_details(
95131
scope_time!("get_commit_details");
96132

97133
let repo = repo(repo_path)?;
134+
let mailmap = repo.mailmap()?;
98135

99136
let commit = repo.find_commit(id.into())?;
100137

101-
let author = CommitSignature::from(&commit.author());
102-
let committer = CommitSignature::from(&commit.committer());
138+
let author = CommitSignature::from(&get_author_of_commit(
139+
&commit, &mailmap,
140+
));
141+
let committer = CommitSignature::from(&get_committer_of_commit(
142+
&commit, &mailmap,
143+
));
144+
103145
let committer = if author == committer {
104146
None
105147
} else {

asyncgit/src/sync/commit_filter.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use super::{commit_files::get_commit_diff, CommitId};
1+
use super::{
2+
commit_details::get_author_of_commit,
3+
commit_files::get_commit_diff, CommitId,
4+
};
25
use crate::error::Result;
36
use bitflags::bitflags;
47
use fuzzy_matcher::FuzzyMatcher;
@@ -159,6 +162,7 @@ pub fn filter_commit_by_search(
159162
move |repo: &Repository,
160163
commit_id: &CommitId|
161164
-> Result<bool> {
165+
let mailmap = repo.mailmap()?;
162166
let commit = repo.find_commit((*commit_id).into())?;
163167

164168
let msg_summary_match = filter
@@ -199,16 +203,15 @@ pub fn filter_commit_by_search(
199203
.fields
200204
.contains(SearchFields::AUTHORS)
201205
.then(|| {
202-
let name_match = commit
203-
.author()
204-
.name()
205-
.is_some_and(|name| filter.match_text(name));
206-
let mail_match = commit
207-
.author()
208-
.email()
209-
.is_some_and(|name| filter.match_text(name));
210-
211-
name_match || mail_match
206+
let author =
207+
get_author_of_commit(&commit, &mailmap);
208+
[author.email(), author.name()].iter().any(
209+
|opt_haystack| {
210+
opt_haystack.is_some_and(|haystack| {
211+
filter.match_text(haystack)
212+
})
213+
},
214+
)
212215
})
213216
.unwrap_or_default();
214217

asyncgit/src/sync/commits_info.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use std::fmt::Display;
22

33
use super::RepoPath;
4-
use crate::{error::Result, sync::repository::repo};
4+
use crate::{
5+
error::Result,
6+
sync::{commit_details::get_author_of_commit, repository::repo},
7+
};
58
use git2::{Commit, Error, Oid};
69
use scopetime::scope_time;
710
use unicode_truncate::UnicodeTruncateStr;
@@ -91,6 +94,7 @@ pub fn get_commits_info(
9194
scope_time!("get_commits_info");
9295

9396
let repo = repo(repo_path)?;
97+
let mailmap = repo.mailmap()?;
9498

9599
let commits = ids
96100
.iter()
@@ -101,10 +105,12 @@ pub fn get_commits_info(
101105
let res = commits
102106
.map(|c: Commit| {
103107
let message = get_message(&c, Some(message_length_limit));
104-
let author = c.author().name().map_or_else(
105-
|| String::from("<unknown>"),
106-
String::from,
107-
);
108+
let author = get_author_of_commit(&c, &mailmap)
109+
.name()
110+
.map_or_else(
111+
|| String::from("<unknown>"),
112+
String::from,
113+
);
108114
CommitInfo {
109115
message,
110116
author,
@@ -125,9 +131,10 @@ pub fn get_commit_info(
125131
scope_time!("get_commit_info");
126132

127133
let repo = repo(repo_path)?;
134+
let mailmap = repo.mailmap()?;
128135

129136
let commit = repo.find_commit((*commit_id).into())?;
130-
let author = commit.author();
137+
let author = get_author_of_commit(&commit, &mailmap);
131138

132139
Ok(CommitInfo {
133140
message: commit.message().unwrap_or("").into(),
@@ -189,6 +196,12 @@ mod tests {
189196
assert_eq!(res[0].author.as_str(), "name");
190197
assert_eq!(res[1].message.as_str(), "commit1");
191198

199+
File::create(root.join(".mailmap"))?
200+
.write_all(b"new name <newemail> <email>")?;
201+
let res = get_commits_info(repo_path, &[c2], 50).unwrap();
202+
203+
assert_eq!(res[0].author.as_str(), "new name");
204+
192205
Ok(())
193206
}
194207

0 commit comments

Comments
 (0)