Skip to content

Commit bfdee46

Browse files
committed
Reimplement insert blank commit
1 parent 498b7d4 commit bfdee46

File tree

6 files changed

+264
-1
lines changed

6 files changed

+264
-1
lines changed

crates/but-rebase/src/graph_rebase/commit.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Provides some slightly higher level tools to help with manipulating commits, in preparation for use in the editor.
22
3-
use anyhow::Result;
3+
use anyhow::{Context as _, Result};
44
use gix::prelude::ObjectIdExt;
55

66
use crate::{
@@ -22,4 +22,35 @@ impl Editor {
2222
) -> Result<gix::ObjectId> {
2323
create(&self.repo, commit.inner, date_mode)
2424
}
25+
26+
/// Creates a commit with only the signature and author set correctly.
27+
///
28+
/// The ID of the commit is all zeros & the commit hasn't been written into any ODB
29+
pub fn empty_commit(&self) -> Result<but_core::Commit<'_>> {
30+
let kind = gix::hash::Kind::Sha1;
31+
let committer = dbg!(self.repo.committer())
32+
.transpose()?
33+
.context("Need committer to be configured when creating a new commit")?
34+
.into();
35+
let author = self
36+
.repo
37+
.committer()
38+
.transpose()?
39+
.context("Need author to be configured when creating a new commit")?
40+
.into();
41+
let obj = gix::objs::Commit {
42+
tree: gix::ObjectId::empty_tree(kind),
43+
parents: vec![].into(),
44+
committer,
45+
author,
46+
encoding: None,
47+
message: b"".into(),
48+
extra_headers: vec![],
49+
};
50+
51+
Ok(but_core::Commit::<'_> {
52+
id: gix::ObjectId::null(kind).attach(&self.repo),
53+
inner: obj,
54+
})
55+
}
2556
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//! Insertion of a blank commit
2+
3+
use std::collections::HashMap;
4+
5+
/// Describes where the blank commit should be inserted relative to.
6+
#[derive(Debug, Clone)]
7+
pub enum RelativeTo<'a> {
8+
/// Relative to a commit
9+
Commit(gix::ObjectId),
10+
/// Relative to a reference
11+
Reference(&'a gix::refs::FullNameRef),
12+
}
13+
14+
/// Describes the outcome of the rebase
15+
#[derive(Debug, Clone)]
16+
pub struct InsertCommitOutcome {
17+
/// The blank commit that was creatd
18+
pub blank_commit_id: gix::ObjectId,
19+
/// Any commits that were mapped.
20+
pub commit_mapping: HashMap<gix::ObjectId, gix::ObjectId>,
21+
}
22+
23+
pub(crate) mod function {
24+
use anyhow::Result;
25+
use but_rebase::{
26+
commit::DateMode,
27+
graph_rebase::{GraphExt, Step, mutate::InsertSide},
28+
};
29+
30+
use crate::commit::insert_blank_commit::{InsertCommitOutcome, RelativeTo};
31+
32+
/// Inserts a blank commit relative to either a reference or a commit
33+
pub fn insert_blank_commit(
34+
graph: &but_graph::Graph,
35+
repo: &gix::Repository,
36+
side: InsertSide,
37+
relative_to: RelativeTo,
38+
) -> Result<InsertCommitOutcome> {
39+
let mut editor = graph.to_editor(repo)?;
40+
let target_selector = match relative_to {
41+
RelativeTo::Commit(id) => editor.select_commit(id)?,
42+
RelativeTo::Reference(r) => editor.select_reference(r)?,
43+
};
44+
45+
let commit = editor.empty_commit()?;
46+
let new_id = editor.write_commit(commit, DateMode::CommitterUpdateAuthorUpdate)?;
47+
48+
editor.insert(&target_selector, Step::new_pick(new_id), side);
49+
50+
let outcome = editor.rebase()?;
51+
let mat_output = outcome.materialize()?;
52+
53+
Ok(InsertCommitOutcome {
54+
blank_commit_id: new_id,
55+
commit_mapping: mat_output.commit_mapping,
56+
})
57+
}
58+
}

crates/but-workspace/src/commit/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use crate::WorkspaceCommit;
66

77
pub mod reword;
88
pub use reword::function::reword;
9+
pub mod insert_blank_commit;
10+
pub use insert_blank_commit::function::insert_blank_commit;
911

1012
/// A minimal stack for use by [WorkspaceCommit::new_from_stacks()].
1113
#[derive(Clone)]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu -o pipefail
4+
5+
echo "/remote/" > .gitignore
6+
mkdir remote
7+
pushd remote
8+
git init
9+
popd
10+
11+
git init
12+
13+
git remote add origin ./remote
14+
15+
git checkout -b one
16+
echo "foo" > one.txt
17+
git add .
18+
git commit -m "commit one"
19+
20+
git checkout -b two
21+
echo "foo" > two.txt
22+
git add .
23+
git commit -m "commit two"
24+
25+
git push -u origin two
26+
27+
git checkout -b three
28+
echo "foo" > three.txt
29+
git add .
30+
git commit -m "commit three"
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use anyhow::Result;
2+
use but_rebase::graph_rebase::mutate::InsertSide;
3+
use but_testsupport::{assure_stable_env, visualize_commit_graph_all};
4+
use but_workspace::commit::insert_blank_commit;
5+
use but_workspace::commit::insert_blank_commit::RelativeTo;
6+
7+
use crate::ref_info::with_workspace_commit::utils::named_writable_scenario_with_description_and_graph as writable_scenario;
8+
9+
#[test]
10+
fn insert_below_commit() -> Result<()> {
11+
assure_stable_env();
12+
let (_tmp, graph, repo, mut _meta, _description) =
13+
writable_scenario("reword-three-commits", |_| {})?;
14+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
15+
* c9f444c (HEAD -> three) commit three
16+
* 16fd221 (origin/two, two) commit two
17+
* 8b426d0 (one) commit one
18+
");
19+
20+
let head_tree = repo.head_tree_id()?;
21+
let id = repo.rev_parse_single("two")?;
22+
23+
insert_blank_commit(
24+
&graph,
25+
&repo,
26+
InsertSide::Below,
27+
RelativeTo::Commit(id.detach()),
28+
)?;
29+
30+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
31+
* 31dbfdc (HEAD -> three) commit three
32+
* b65c813 (two) commit two
33+
* d2b480d
34+
| * 16fd221 (origin/two) commit two
35+
|/
36+
* 8b426d0 (one) commit one
37+
");
38+
39+
assert_eq!(head_tree, repo.head_tree_id()?);
40+
41+
Ok(())
42+
}
43+
44+
#[test]
45+
fn insert_above_commit() -> Result<()> {
46+
assure_stable_env();
47+
let (_tmp, graph, repo, mut _meta, _description) =
48+
writable_scenario("reword-three-commits", |_| {})?;
49+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
50+
* c9f444c (HEAD -> three) commit three
51+
* 16fd221 (origin/two, two) commit two
52+
* 8b426d0 (one) commit one
53+
");
54+
55+
let head_tree = repo.head_tree_id()?;
56+
let id = repo.rev_parse_single("two")?;
57+
58+
insert_blank_commit(
59+
&graph,
60+
&repo,
61+
InsertSide::Above,
62+
RelativeTo::Commit(id.detach()),
63+
)?;
64+
65+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
66+
* 923c9cd (HEAD -> three) commit three
67+
* 8bf04f0 (two)
68+
* 16fd221 (origin/two) commit two
69+
* 8b426d0 (one) commit one
70+
");
71+
72+
assert_eq!(head_tree, repo.head_tree_id()?);
73+
74+
Ok(())
75+
}
76+
77+
#[test]
78+
fn insert_below_reference() -> Result<()> {
79+
assure_stable_env();
80+
let (_tmp, graph, repo, mut _meta, _description) =
81+
writable_scenario("reword-three-commits", |_| {})?;
82+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
83+
* c9f444c (HEAD -> three) commit three
84+
* 16fd221 (origin/two, two) commit two
85+
* 8b426d0 (one) commit one
86+
");
87+
88+
let head_tree = repo.head_tree_id()?;
89+
let reference = repo.find_reference("two")?;
90+
91+
insert_blank_commit(
92+
&graph,
93+
&repo,
94+
InsertSide::Below,
95+
RelativeTo::Reference(reference.name()),
96+
)?;
97+
98+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
99+
* 923c9cd (HEAD -> three) commit three
100+
* 8bf04f0 (two)
101+
* 16fd221 (origin/two) commit two
102+
* 8b426d0 (one) commit one
103+
");
104+
105+
assert_eq!(head_tree, repo.head_tree_id()?);
106+
107+
Ok(())
108+
}
109+
110+
#[test]
111+
fn insert_above_reference() -> Result<()> {
112+
assure_stable_env();
113+
let (_tmp, graph, repo, mut _meta, _description) =
114+
writable_scenario("reword-three-commits", |_| {})?;
115+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
116+
* c9f444c (HEAD -> three) commit three
117+
* 16fd221 (origin/two, two) commit two
118+
* 8b426d0 (one) commit one
119+
");
120+
121+
let head_tree = repo.head_tree_id()?;
122+
let reference = repo.find_reference("two")?;
123+
124+
insert_blank_commit(
125+
&graph,
126+
&repo,
127+
InsertSide::Above,
128+
RelativeTo::Reference(reference.name()),
129+
)?;
130+
131+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
132+
* 923c9cd (HEAD -> three) commit three
133+
* 8bf04f0
134+
* 16fd221 (origin/two, two) commit two
135+
* 8b426d0 (one) commit one
136+
");
137+
138+
assert_eq!(head_tree, repo.head_tree_id()?);
139+
140+
Ok(())
141+
}

crates/but-workspace/tests/workspace/commit/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod insert_blank_commit;
12
mod reword;
23

34
mod from_new_merge_with_metadata {

0 commit comments

Comments
 (0)