From 21fba447a130a18ac2ca43fc3dd01995bcb13fb6 Mon Sep 17 00:00:00 2001 From: Caleb Owens Date: Wed, 5 Feb 2025 12:08:41 +0100 Subject: [PATCH] but-rebase stub --- Cargo.lock | 12 +++++ Cargo.toml | 1 + crates/but-rebase/Cargo.toml | 26 +++++++++++ crates/but-rebase/src/lib.rs | 90 ++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 crates/but-rebase/Cargo.toml create mode 100644 crates/but-rebase/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 71d52bab9c..d94662279a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,6 +720,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "but-rebase" +version = "0.0.0" +dependencies = [ + "anyhow", + "bstr", + "gix", + "gix-testtools", + "insta", + "tracing", +] + [[package]] name = "but-workspace" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index ef81fd8b58..f36c8e1ed3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ but-debugging = { path = "crates/but-debugging" } but-core = { path = "crates/but-core" } but-workspace = { path = "crates/but-workspace" } but-hunk-dependency = { path = "crates/but-hunk-dependency" } +but-rebase = { path = "crates/but-rebase" } [profile.release] codegen-units = 1 # Compile crates one after another so the compiler can optimize better diff --git a/crates/but-rebase/Cargo.toml b/crates/but-rebase/Cargo.toml new file mode 100644 index 0000000000..d8483a3c52 --- /dev/null +++ b/crates/but-rebase/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "but-rebase" +version = "0.0.0" +edition = "2021" +authors = ["GitButler "] +publish = false + +[lib] +doctest = false + +[dependencies] +bstr.workspace = true +tracing.workspace = true +anyhow = "1.0.95" +gix = { workspace = true, features = [ + "dirwalk", + "credentials", + "parallel", + "serde", + "status", +] } + +[dev-dependencies] +gix-testtools.workspace = true +gix = { workspace = true, features = ["revision"] } +insta.workspace = true diff --git a/crates/but-rebase/src/lib.rs b/crates/but-rebase/src/lib.rs new file mode 100644 index 0000000000..2a169eccc4 --- /dev/null +++ b/crates/but-rebase/src/lib.rs @@ -0,0 +1,90 @@ +#![deny(missing_docs, rust_2018_idioms)] +//! Rebase for your flying but. + +use anyhow::Result; +use bstr::{BStr, BString}; + +#[derive(Debug)] +/// A step to be taken as part of rebase. +pub enum Step<'a> { + /// Reference updates the given reference to the commit beneath it. + /// + /// Should be a full reference identifer, IE: refs/heads/foo + Reference(&'a BStr), + /// Picks a commit and squashes it into the commit beneath it. + /// + /// If a name is provided, it will be used as the new commit's title. + /// Otherwise, the commit's title that is getting picked will be taken. + /// + /// TODO: ADD A VALIDATION STEP FOR THIS + /// Must never be the first operation. + /// Must never come after a Reference operation. + Ammend(gix::ObjectId, Option<&'a BStr>), + /// Picks a commit + /// + /// If a name is provided, it will be used as the new commit's title. + /// Otherwise, the commit's title that is getting picked will be taken. + Pick(gix::ObjectId, Option<&'a BStr>), + /// Merges in a commit and it's parents + /// + /// The name provided will be used as the merge commit's name + Merge(gix::ObjectId, &'a BStr), +} + +// vec![ +// Step::Pick(fdsaadfs), +// Step::Pick(fdsaadfs), +// Step::Ammend(fdsaadfs), +// Step::Reference("refs/heads/foo"), +// ] + +fn but_base(base: gix::ObjectId, steps: &[Step]) -> Result { + let mut references = vec![]; + let mut commits = vec![]; + + for step in steps { + match step { + Step::Reference(refname) => references.push(Reference { + name: refname.to_owned().into(), + oid: commits.last().unwrap_or(&base).to_owned(), + }), + Step::Pick(to_pick, commit_name) => { + let target_commit = commits.last().unwrap_or(&base).to_owned(); + let result = cherry_rebase_group(todo!(), target_commit, &[to_pick], true)?; + commits.push(result) + } + Step::Ammend(to_pick, commit_name) => { + let target_commit = commits + .last() + .expect("Ammend should never be the first operation"); + let result = cherry_rebase_group(todo!(), target_commit, &[to_pick], true)?; + commits.pop(); // Remove the commit that we ammended + commits.push(result) + } + Step::Merge(to_merge, commit_name) => { + // Do the same with gitbutler_merge_commits + } + } + } + + Ok(RebaseOutput { + references, + commits, + }) +} + +/// Describes a reference +pub struct Reference { + /// The reference identifier, IE: refs/heads/foo + name: BString, + /// The oid that the reference points to. + oid: gix::ObjectId, +} + +/// The result of a rebase +pub struct RebaseOutput { + /// The references, from child-most to parent-most. + references: Vec, + /// The commits, from child-most to parent-most. + commits: Vec, +}