diff --git a/src/errors.rs b/src/errors.rs index 716b134..1d513ac 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -29,6 +29,9 @@ pub enum StError { Color::Blue.paint("st restack") )] NeedsRestack(String), + /// A commit message is required with --all or --update + #[error("Commit message is required with --all or --update")] + CommitMessageRequired, /// The working tree is dirty. #[error("Working tree is dirty. Please commit or stash changes before continuing.")] WorkingTreeDirty, diff --git a/src/subcommands/local/create.rs b/src/subcommands/local/create.rs index 7ec61d7..8d70c30 100644 --- a/src/subcommands/local/create.rs +++ b/src/subcommands/local/create.rs @@ -1,7 +1,12 @@ //! `create` subcommand. -use crate::{ctx::StContext, errors::StResult, git::RepositoryExt}; +use crate::{ + ctx::StContext, + errors::{StError, StResult}, + git::RepositoryExt, +}; use clap::Args; +use git2::IndexAddOption; use nu_ansi_term::Color; /// CLI arguments for the `create` subcommand. @@ -10,7 +15,17 @@ pub struct CreateCmd { /// Name of the new branch to create. #[clap(index = 1)] branch_name: Option, + /// Stage all changes before creating branch + #[clap(short = 'a', long = "all")] + all: bool, + /// Stage only tracked files before creating branch + #[clap(short, long = "update")] + update: bool, + /// Specify a commit message + #[clap(short, long, requires = "all", conflicts_with = "update")] + message: Option, } + impl CreateCmd { /// Run the `create` subcommand. pub fn run(self, mut ctx: StContext<'_>) -> StResult<()> { @@ -25,6 +40,33 @@ impl CreateCmd { None => inquire::Text::new("Name of new branch:").prompt()?, }; + // Stage changes if requested + if self.all || self.update { + let message = self.message.ok_or(StError::CommitMessageRequired)?; + + // Get the index. + let mut index = ctx.repository.index()?; + + // Stage changes based on flag. + if self.all { + index.add_all(vec!["*"], IndexAddOption::DEFAULT, None)?; + } else if self.update { + index.update_all(vec!["*"], None)?; + } + index.write()?; + + // Create the commit. + let sig = ctx.repository.signature()?; + // Get the tree. + let tree_id = ctx.repository.index()?.write_tree()?; + let tree = ctx.repository.find_tree(tree_id)?; + // Get the parent commit. + let parent_commit = ctx.repository.head()?.peel_to_commit()?; + // Create the commit. + ctx.repository + .commit(Some("HEAD"), &sig, &sig, &message, &tree, &[&parent_commit])?; + } + // Check if the working tree is clean. if !ctx.repository.is_working_tree_clean()? { return Err(crate::errors::StError::WorkingTreeDirty);