git_editor/rewrite/
rewrite_all.rs1use crate::utils::types::Result;
2use crate::{args::Args, utils::commit_history::get_commit_history};
3use chrono::NaiveDateTime;
4use colored::Colorize;
5use git2::{Repository, Signature, Sort, Time};
6use std::collections::HashMap;
7
8pub fn rewrite_all_commits(args: &Args, timestamps: Vec<NaiveDateTime>) -> Result<()> {
9 let repo = Repository::open(args.repo_path.as_ref().unwrap())?;
10 let head_ref = repo.head()?;
11 let branch_name = head_ref
12 .shorthand()
13 .ok_or("Detached HEAD or invalid branch")?;
14 let full_ref = format!("refs/heads/{branch_name}");
15
16 let mut revwalk = repo.revwalk()?;
17 revwalk.push_head()?;
18 revwalk.set_sorting(Sort::TOPOLOGICAL | Sort::TIME)?;
19 let mut orig_oids: Vec<_> = revwalk.filter_map(|id| id.ok()).collect();
20 orig_oids.reverse();
21
22 let mut new_map: HashMap<git2::Oid, git2::Oid> = HashMap::new();
23 let mut last_new_oid = None;
24
25 for (i, &oid) in orig_oids.iter().enumerate() {
26 let orig = repo.find_commit(oid)?;
27 let tree = orig.tree()?;
28
29 let new_parents: Result<Vec<_>> = orig
30 .parent_ids()
31 .map(|pid| {
32 let new_pid = *new_map.get(&pid).unwrap_or(&pid);
33 repo.find_commit(new_pid).map_err(|e| e.into())
34 })
35 .collect();
36
37 let timestamp: i64 = timestamps[i].and_utc().timestamp();
38 let sig = Signature::new(
39 args.name.as_ref().unwrap(),
40 args.email.as_ref().unwrap(),
41 &Time::new(timestamp, 0),
42 )?;
43
44 let new_oid = repo.commit(
45 None,
46 &sig,
47 &sig,
48 orig.message().unwrap_or_default(),
49 &tree,
50 &new_parents?.iter().collect::<Vec<_>>(),
51 )?;
52
53 new_map.insert(oid, new_oid);
54 last_new_oid = Some(new_oid);
55 }
56
57 if let Some(new_head) = last_new_oid {
58 repo.reference(&full_ref, new_head, true, "history rewritten")?;
59 println!(
60 "{} '{}' -> {}",
61 "Rewritten branch".green(),
62 branch_name.cyan(),
63 new_head.to_string().cyan()
64 );
65 if args.show_history {
66 get_commit_history(args, true)?;
67 }
68 }
69
70 Ok(())
71}