use std::collections::HashSet;
use crate::commit_pretty::format_reference_line;
use crate::error::Result;
use crate::objects::{parse_commit, CommitData, ObjectId};
use crate::repo::Repository;
pub fn revision_set_newest_first(
repo: &Repository,
include: &[ObjectId],
exclude: &[ObjectId],
) -> Result<Vec<ObjectId>> {
let mut excluded: HashSet<ObjectId> = HashSet::new();
let mut stack: Vec<ObjectId> = exclude.to_vec();
while let Some(oid) = stack.pop() {
if !excluded.insert(oid) {
continue;
}
if let Ok(obj) = repo.odb.read(&oid) {
if let Ok(commit) = parse_commit(&obj.data) {
stack.extend(commit.parents.iter().copied());
}
}
}
let mut seen: HashSet<ObjectId> = HashSet::new();
let mut collected: Vec<(i64, ObjectId)> = Vec::new();
let mut stack: Vec<ObjectId> = include.to_vec();
while let Some(oid) = stack.pop() {
if excluded.contains(&oid) || !seen.insert(oid) {
continue;
}
let obj = repo.odb.read(&oid)?;
let commit = parse_commit(&obj.data)?;
let ts = committer_timestamp(&commit.committer);
collected.push((ts, oid));
stack.extend(commit.parents.iter().copied());
}
collected.sort_by(|a, b| b.0.cmp(&a.0));
Ok(collected.into_iter().map(|(_, oid)| oid).collect())
}
#[must_use]
pub fn committer_timestamp(ident: &str) -> i64 {
ident
.rsplitn(3, ' ')
.nth(1)
.and_then(|s| s.parse::<i64>().ok())
.unwrap_or(0)
}
#[must_use]
pub fn merge_commit_message_for_revert(
commit: &CommitData,
commit_oid: ObjectId,
use_reference: bool,
comment_char: char,
) -> (String, String) {
let subject_line = commit.message.lines().next().unwrap_or("");
let oid_full = commit_oid.to_hex();
if use_reference {
let title = format!("{comment_char} *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
let ref_line = format_reference_line(&commit_oid, subject_line, &commit.committer, 7);
let body = format!("This reverts commit {ref_line}.\n\n");
return (title, body);
}
let body = format!("This reverts commit {oid_full}.\n");
if let Some(rest) = subject_line.strip_prefix("Revert \"") {
if let Some(orig) = rest.strip_suffix('"') {
if !orig.starts_with("Revert \"") {
let title = format!("Reapply \"{orig}\"\n");
return (title, body);
}
}
}
let title = format!("Revert \"{subject_line}\"\n");
(title, body)
}