ubr/git/local_commit/
untracked_commit.rs

1use std::fmt::Debug;
2
3use anyhow::Context;
4use git2::{Commit, Repository};
5
6use crate::git::{local_commit::CommitMetadata, GitRepo};
7
8use super::TrackedCommit;
9
10pub struct UnTrackedCommit<'repo> {
11    repo: &'repo Repository,
12    git_repo: &'repo GitRepo,
13    commit: Commit<'repo>,
14}
15
16impl<'repo> UnTrackedCommit<'repo> {
17    pub fn new(repo: &'repo Repository, git_repo: &'repo GitRepo, commit: Commit<'repo>) -> Self {
18        Self {
19            repo,
20            git_repo,
21            commit,
22        }
23    }
24    pub fn as_commit(&self) -> &Commit {
25        &self.commit
26    }
27
28    pub fn commit(self) -> Commit<'repo> {
29        self.commit
30    }
31
32    pub(crate) fn rebase(self, parent_commit: &Commit<'_>) -> anyhow::Result<Self> {
33        let mut index = self
34            .repo
35            .cherrypick_commit(self.as_commit(), parent_commit, 0, None)?;
36        let new_commit = {
37            let signature = self.as_commit().author();
38            let tree_id = index.write_tree_to(self.repo)?;
39            let tree = self.repo.find_tree(tree_id)?;
40            let new_commit_id = self.repo.commit(
41                None,
42                &signature,
43                &signature,
44                self.commit.message().expect("Not valid UTF-8 message"),
45                &tree,
46                &[parent_commit],
47            )?;
48            self.repo.find_commit(new_commit_id)?
49        };
50        Ok(UnTrackedCommit {
51            repo: self.repo,
52            git_repo: self.git_repo,
53            commit: new_commit,
54        })
55    }
56
57    pub(crate) fn track(self) -> anyhow::Result<TrackedCommit<'repo>> {
58        let commit_msg = self
59            .as_commit()
60            .message()
61            .context("Commit message is not valid UTF-8")?;
62
63        let branch_name = self.generate_remote_branch_name(commit_msg)?;
64        let origin_main_commit = self.git_repo.base_commit()?;
65        let mut complete_index = self
66            .repo
67            .cherrypick_commit(self.as_commit(), &origin_main_commit, 0, None)
68            .context("Cherry picking directly on master")?;
69
70        if complete_index.has_conflicts() {
71            anyhow::bail!("There are conflicts");
72        }
73
74        let tree_id = complete_index.write_tree_to(self.repo)?;
75        let tree = self.repo.find_tree(tree_id)?;
76
77        let remote_commit = {
78            let signature = self.as_commit().author();
79            self.repo.commit(
80                None,
81                &signature,
82                &signature,
83                commit_msg,
84                &tree,
85                &[&origin_main_commit],
86            )?
87        };
88
89        //Create meta_data
90        let meta_data = CommitMetadata {
91            remote_branch_name: std::borrow::Cow::Owned(branch_name),
92            remote_commit,
93        };
94        self.git_repo.save_meta_data(self.as_commit(), &meta_data)?;
95        Ok(TrackedCommit::new(
96            self.repo,
97            self.git_repo,
98            self.commit,
99            meta_data,
100        ))
101    }
102
103    fn generate_remote_branch_name(&self, commit_msg: &str) -> anyhow::Result<String> {
104        let branch_name = {
105            let title = commit_msg
106                .lines()
107                .next()
108                .expect("Must have at least one line");
109            title
110                .replace(
111                    |c: char| !(c.is_ascii_alphanumeric() || c == '-' || c == '_'),
112                    "-",
113                )
114                .to_ascii_lowercase()
115        };
116        Ok(branch_name)
117    }
118}
119
120impl Debug for UnTrackedCommit<'_> {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        let commit = &self.commit;
123        write!(
124            f,
125            "Untracked Commit: {:?} {:?}",
126            commit.id(),
127            commit.message()
128        )
129    }
130}