From 04b82f1aa6f2aa6c3a9cebbe86e83074405fbb3f Mon Sep 17 00:00:00 2001 From: HouXiaoxuan Date: Sat, 23 Dec 2023 15:43:05 +0800 Subject: [PATCH] =?UTF-8?q?merge=20ff=20=E6=9C=AA=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cli.rs | 13 ++++++-- src/commands/merge.rs | 72 +++++++++++++++++++++++++++++++++++++++++++ src/commands/mod.rs | 1 + 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 src/commands/merge.rs diff --git a/src/cli.rs b/src/cli.rs index b244a87..ac13a48 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,7 +1,7 @@ use clap::{ArgGroup, Parser, Subcommand}; use mit::commands::{ - add::add, branch::branch, commit::commit, init::init, log::log, remove::remove, restore::restore, status::status, - switch::switch, + add::add, branch::branch, commit::commit, init::init, log::log, merge::merge, remove::remove, restore::restore, + status::status, switch::switch, }; /// Rust实现的简易版本的Git,用于学习Rust语言 @@ -117,6 +117,12 @@ enum Command { #[clap(long, short = 'S', action)] staged: bool, }, + /// merge + Merge { + /// 要合并的分支 + #[clap(required = true)] + branch: String, + }, } pub fn handle_command() { let cli = Cli::parse(); @@ -162,5 +168,8 @@ pub fn handle_command() { } restore(path, source.unwrap(), worktree, staged); } + Command::Merge { branch } => { + merge(branch); + } } } diff --git a/src/commands/merge.rs b/src/commands/merge.rs new file mode 100644 index 0000000..e258827 --- /dev/null +++ b/src/commands/merge.rs @@ -0,0 +1,72 @@ +use clap::builder::Str; + +use crate::{ + commands, head, + models::{commit::Commit, object::Hash}, + store::Store, + utils::util, +}; + +enum MergeError { + NoFastForward, +} + +fn check_ff(current: &Hash, target: Hash) -> Result { + let target_commit = Commit::load(&target); + // 检查current是否是target的祖先 + if *current == target_commit.get_hash() { + return Ok(true); + } + for parent in target_commit.get_parent_hash() { + let result = check_ff(current, parent); + if result.is_ok() { + return result; + } + } + return Err(MergeError::NoFastForward); +} + +/** commit 以fast forward到形式合并到当前分支 */ +fn merge_ff(commit_hash: String) -> Result<(), MergeError> { + // 检查当前分支是否可以fast forward到commit + let current_commit = head::current_head_commit(); + let check = check_ff(¤t_commit, commit_hash.clone()); + if check.is_err() { + return Err(check.unwrap_err()); + } + + // 执行fast forward + let head = head::current_head(); + match head { + head::Head::Branch(branch) => { + head::update_branch(&branch, &commit_hash.clone()); + commands::restore::restore(vec![], commit_hash.clone(), true, true) + } + head::Head::Detached(_) => { + // 相当于切换到了commit_hash,什么都没有发生 + commands::switch::switch(Some(commit_hash.clone()), None, true); + } + } + unimplemented!(); +} + +/** merge,暂时只支持fast forward */ +pub fn merge(branch: String) { + let merge_commit = { + if head::list_local_branches().contains(&branch) { + // Branch Name, e.g. master + head::get_branch_head(&branch) + } else { + // Commit Hash, e.g. a1b2c3d4 + let store = Store::new(); + let commit = store.search(&branch); + if commit.is_none() || !util::is_typeof_commit(commit.clone().unwrap()) { + println!("fatal: 非法的 commit hash: '{}'", branch); + return; + } + commit.unwrap() + } + }; + // 暂时只支持fast forward + let _ = merge_ff(merge_commit); +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index f9cf21c..f5c1f45 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -3,6 +3,7 @@ pub mod branch; pub mod commit; pub mod init; pub mod log; +pub mod merge; pub mod remove; pub mod restore; pub mod status;