Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion crates/but-rebase/src/graph_rebase/commit.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Provides some slightly higher level tools to help with manipulating commits, in preparation for use in the editor.

use anyhow::Result;
use anyhow::{Context as _, Result};
use gix::prelude::ObjectIdExt;

use crate::{
Expand All @@ -22,4 +22,35 @@ impl Editor {
) -> Result<gix::ObjectId> {
create(&self.repo, commit.inner, date_mode)
}

/// Creates a commit with only the signature and author set correctly.
///
/// The ID of the commit is all zeros & the commit hasn't been written into any ODB
pub fn empty_commit(&self) -> Result<but_core::Commit<'_>> {
let kind = gix::hash::Kind::Sha1;
let committer = dbg!(self.repo.committer())
.transpose()?
.context("Need committer to be configured when creating a new commit")?
.into();
let author = self
.repo
.committer()
.transpose()?
.context("Need author to be configured when creating a new commit")?
.into();
let obj = gix::objs::Commit {
tree: gix::ObjectId::empty_tree(kind),
parents: vec![].into(),
committer,
author,
encoding: None,
message: b"".into(),
extra_headers: vec![],
};

Ok(but_core::Commit::<'_> {
id: gix::ObjectId::null(kind).attach(&self.repo),
inner: obj,
})
}
}
58 changes: 58 additions & 0 deletions crates/but-workspace/src/commit/insert_blank_commit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//! Insertion of a blank commit

use std::collections::HashMap;

/// Describes where the blank commit should be inserted relative to.
#[derive(Debug, Clone)]
pub enum RelativeTo<'a> {
/// Relative to a commit
Commit(gix::ObjectId),
/// Relative to a reference
Reference(&'a gix::refs::FullNameRef),
}

/// Describes the outcome of the rebase
#[derive(Debug, Clone)]
pub struct InsertCommitOutcome {
/// The blank commit that was creatd
pub blank_commit_id: gix::ObjectId,
/// Any commits that were mapped.
pub commit_mapping: HashMap<gix::ObjectId, gix::ObjectId>,
}

pub(crate) mod function {
use anyhow::Result;
use but_rebase::{
commit::DateMode,
graph_rebase::{GraphExt, Step, mutate::InsertSide},
};

use crate::commit::insert_blank_commit::{InsertCommitOutcome, RelativeTo};

/// Inserts a blank commit relative to either a reference or a commit
pub fn insert_blank_commit(
graph: &but_graph::Graph,
repo: &gix::Repository,
side: InsertSide,
relative_to: RelativeTo,
) -> Result<InsertCommitOutcome> {
let mut editor = graph.to_editor(repo)?;
let target_selector = match relative_to {
RelativeTo::Commit(id) => editor.select_commit(id)?,
RelativeTo::Reference(r) => editor.select_reference(r)?,
};

let commit = editor.empty_commit()?;
let new_id = editor.write_commit(commit, DateMode::CommitterUpdateAuthorUpdate)?;

editor.insert(&target_selector, Step::new_pick(new_id), side);

let outcome = editor.rebase()?;
let mat_output = outcome.materialize()?;

Ok(InsertCommitOutcome {
blank_commit_id: new_id,
commit_mapping: mat_output.commit_mapping,
})
}
}
2 changes: 2 additions & 0 deletions crates/but-workspace/src/commit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::WorkspaceCommit;

pub mod reword;
pub use reword::function::reword;
pub mod insert_blank_commit;
pub use insert_blank_commit::function::insert_blank_commit;

/// A minimal stack for use by [WorkspaceCommit::new_from_stacks()].
#[derive(Clone)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash

set -eu -o pipefail

echo "/remote/" > .gitignore
mkdir remote
pushd remote
git init
popd

git init

git remote add origin ./remote

git checkout -b one
echo "foo" > one.txt
git add .
git commit -m "commit one"

git checkout -b two
echo "foo" > two.txt
git add .
git commit -m "commit two"

git push -u origin two

git checkout -b three
echo "foo" > three.txt
git add .
git commit -m "commit three"
141 changes: 141 additions & 0 deletions crates/but-workspace/tests/workspace/commit/insert_blank_commit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use anyhow::Result;
use but_rebase::graph_rebase::mutate::InsertSide;
use but_testsupport::{assure_stable_env, visualize_commit_graph_all};
use but_workspace::commit::insert_blank_commit;
use but_workspace::commit::insert_blank_commit::RelativeTo;

use crate::ref_info::with_workspace_commit::utils::named_writable_scenario_with_description_and_graph as writable_scenario;

#[test]
fn insert_below_commit() -> Result<()> {
assure_stable_env();
let (_tmp, graph, repo, mut _meta, _description) =
writable_scenario("reword-three-commits", |_| {})?;
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* c9f444c (HEAD -> three) commit three
* 16fd221 (origin/two, two) commit two
* 8b426d0 (one) commit one
");

let head_tree = repo.head_tree_id()?;
let id = repo.rev_parse_single("two")?;

insert_blank_commit(
&graph,
&repo,
InsertSide::Below,
RelativeTo::Commit(id.detach()),
)?;

insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* 31dbfdc (HEAD -> three) commit three
* b65c813 (two) commit two
* d2b480d
| * 16fd221 (origin/two) commit two
|/
* 8b426d0 (one) commit one
");

assert_eq!(head_tree, repo.head_tree_id()?);

Ok(())
}

#[test]
fn insert_above_commit() -> Result<()> {
assure_stable_env();
let (_tmp, graph, repo, mut _meta, _description) =
writable_scenario("reword-three-commits", |_| {})?;
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* c9f444c (HEAD -> three) commit three
* 16fd221 (origin/two, two) commit two
* 8b426d0 (one) commit one
");

let head_tree = repo.head_tree_id()?;
let id = repo.rev_parse_single("two")?;

insert_blank_commit(
&graph,
&repo,
InsertSide::Above,
RelativeTo::Commit(id.detach()),
)?;

insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* 923c9cd (HEAD -> three) commit three
* 8bf04f0 (two)
* 16fd221 (origin/two) commit two
* 8b426d0 (one) commit one
");

assert_eq!(head_tree, repo.head_tree_id()?);

Ok(())
}

#[test]
fn insert_below_reference() -> Result<()> {
assure_stable_env();
let (_tmp, graph, repo, mut _meta, _description) =
writable_scenario("reword-three-commits", |_| {})?;
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* c9f444c (HEAD -> three) commit three
* 16fd221 (origin/two, two) commit two
* 8b426d0 (one) commit one
");

let head_tree = repo.head_tree_id()?;
let reference = repo.find_reference("two")?;

insert_blank_commit(
&graph,
&repo,
InsertSide::Below,
RelativeTo::Reference(reference.name()),
)?;

insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* 923c9cd (HEAD -> three) commit three
* 8bf04f0 (two)
* 16fd221 (origin/two) commit two
* 8b426d0 (one) commit one
");

assert_eq!(head_tree, repo.head_tree_id()?);

Ok(())
}

#[test]
fn insert_above_reference() -> Result<()> {
assure_stable_env();
let (_tmp, graph, repo, mut _meta, _description) =
writable_scenario("reword-three-commits", |_| {})?;
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* c9f444c (HEAD -> three) commit three
* 16fd221 (origin/two, two) commit two
* 8b426d0 (one) commit one
");

let head_tree = repo.head_tree_id()?;
let reference = repo.find_reference("two")?;

insert_blank_commit(
&graph,
&repo,
InsertSide::Above,
RelativeTo::Reference(reference.name()),
)?;

insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @r"
* 923c9cd (HEAD -> three) commit three
* 8bf04f0
* 16fd221 (origin/two, two) commit two
* 8b426d0 (one) commit one
");

assert_eq!(head_tree, repo.head_tree_id()?);

Ok(())
}
1 change: 1 addition & 0 deletions crates/but-workspace/tests/workspace/commit/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod insert_blank_commit;
mod reword;

mod from_new_merge_with_metadata {
Expand Down
Loading