Skip to content

Commit 34bef06

Browse files
feat(rebase): Add RebaseCommand::FixUp
1 parent ddf45bf commit 34bef06

File tree

2 files changed

+340
-49
lines changed

2 files changed

+340
-49
lines changed

git-branchless-lib/src/core/rewrite/execute.rs

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,8 @@ mod in_memory {
354354
use crate::core::rewrite::move_branches;
355355
use crate::core::rewrite::plan::{OidOrLabel, RebaseCommand, RebasePlan};
356356
use crate::git::{
357-
CherryPickFastError, CherryPickFastOptions, GitRunInfo, MaybeZeroOid, NonZeroOid, Repo,
357+
AmendFastOptions, CherryPickFastError, CherryPickFastOptions, GitRunInfo, MaybeZeroOid,
358+
NonZeroOid, Repo,
358359
};
359360
use crate::util::ExitCode;
360361

@@ -404,6 +405,7 @@ mod in_memory {
404405
| RebaseCommand::CreateLabel { .. }
405406
| RebaseCommand::Reset { .. }
406407
| RebaseCommand::Pick { .. }
408+
| RebaseCommand::FixUp { .. }
407409
| RebaseCommand::RegisterExtraPostRewriteHook
408410
| RebaseCommand::DetectEmptyCommit { .. }
409411
| RebaseCommand::SkipUpstreamAppliedCommit { .. } => None,
@@ -453,6 +455,7 @@ mod in_memory {
453455
| RebaseCommand::RegisterExtraPostRewriteHook
454456
| RebaseCommand::DetectEmptyCommit { .. } => false,
455457
RebaseCommand::Pick { .. }
458+
| RebaseCommand::FixUp { .. }
456459
| RebaseCommand::Merge { .. }
457460
| RebaseCommand::SkipUpstreamAppliedCommit { .. } => true,
458461
})
@@ -572,9 +575,8 @@ mod in_memory {
572575

573576
writeln!(
574577
effects.get_output_stream(),
575-
"[{}/{}] Skipped now-empty commit: {}",
576-
i,
577-
num_picks,
578+
"{} Skipped now-empty commit: {}",
579+
commit_num,
578580
commit_description
579581
)?;
580582
} else {
@@ -593,6 +595,131 @@ mod in_memory {
593595
}
594596
}
595597

598+
RebaseCommand::FixUp {
599+
commit_to_fixup_oid,
600+
fixup_commit_oid,
601+
} => {
602+
// FIXME this was mostly copied from RebaseCommand::Pick;
603+
// review before push to make sure it really makes sense or
604+
// can be simplified
605+
let current_commit = repo
606+
.find_commit_or_fail(current_oid)
607+
.wrap_err("Finding current commit")?;
608+
let commit_to_fixup = match rewritten_oids.get(commit_to_fixup_oid) {
609+
Some(MaybeZeroOid::NonZero(rewritten_oid)) => repo
610+
.find_commit_or_fail(*rewritten_oid)
611+
.wrap_err("Finding commit to apply")?,
612+
Some(MaybeZeroOid::Zero) => todo!("FIXME fixing up deleted commit"),
613+
None => repo
614+
.find_commit_or_fail(*commit_to_fixup_oid)
615+
.wrap_err("Finding commit to apply")?,
616+
};
617+
let fixup_commit = repo
618+
.find_commit_or_fail(*fixup_commit_oid)
619+
.wrap_err("Finding commit to apply")?;
620+
i += 1;
621+
622+
let commit_description = printable_styled_string(
623+
effects.get_glyphs(),
624+
commit_to_fixup.friendly_describe(effects.get_glyphs())?,
625+
)?;
626+
let commit_num = format!("[{}/{}]", i, num_picks);
627+
progress.notify_progress(i, num_picks);
628+
629+
if fixup_commit.get_parent_count() > 1 {
630+
warn!(
631+
?fixup_commit_oid,
632+
"BUG: Merge commit should have been detected during planning phase"
633+
);
634+
return Ok(RebaseInMemoryResult::CannotRebaseMergeCommit {
635+
commit_oid: *fixup_commit_oid,
636+
});
637+
};
638+
639+
progress.notify_status(format!(
640+
"Applying patch for commit: {}",
641+
commit_description
642+
));
643+
644+
let commit_tree = repo.amend_fast(
645+
&commit_to_fixup,
646+
&AmendFastOptions::FromCommit {
647+
commit: fixup_commit,
648+
},
649+
)?;
650+
651+
let commit_message = commit_to_fixup.get_message_raw()?;
652+
let commit_message = commit_message.to_str().with_context(|| {
653+
eyre::eyre!(
654+
"Could not decode commit message for commit: {:?}",
655+
fixup_commit_oid
656+
)
657+
})?;
658+
659+
progress
660+
.notify_status(format!("Committing to repository: {}", commit_description));
661+
let committer_signature = if *preserve_timestamps {
662+
commit_to_fixup.get_committer()
663+
} else {
664+
commit_to_fixup.get_committer().update_timestamp(*now)?
665+
};
666+
let parent_commit = current_commit.get_parents()[0].clone();
667+
let rebased_commit_oid = repo
668+
.create_commit(
669+
None,
670+
&commit_to_fixup.get_author(),
671+
&committer_signature,
672+
commit_message,
673+
&commit_tree,
674+
vec![&parent_commit],
675+
)
676+
.wrap_err("Applying rebased commit")?;
677+
678+
let rebased_commit = repo
679+
.find_commit_or_fail(rebased_commit_oid)
680+
.wrap_err("Looking up just-rebased commit")?;
681+
let commit_description = printable_styled_string(
682+
effects.get_glyphs(),
683+
repo.friendly_describe_commit_from_oid(
684+
effects.get_glyphs(),
685+
rebased_commit_oid,
686+
)?,
687+
)?;
688+
if rebased_commit.is_empty() {
689+
rewritten_oids.insert(*commit_to_fixup_oid, MaybeZeroOid::Zero);
690+
maybe_set_skipped_head_new_oid(*commit_to_fixup_oid, current_oid);
691+
692+
writeln!(
693+
effects.get_output_stream(),
694+
"{} Skipped now-empty commit: {}",
695+
commit_num,
696+
commit_description
697+
)?;
698+
} else {
699+
rewritten_oids.insert(
700+
*commit_to_fixup_oid,
701+
MaybeZeroOid::NonZero(rebased_commit_oid),
702+
);
703+
rewritten_oids.insert(
704+
*fixup_commit_oid,
705+
match head_oid {
706+
Some(head_oid) if head_oid == *fixup_commit_oid => {
707+
MaybeZeroOid::NonZero(rebased_commit_oid)
708+
}
709+
None | Some(_) => MaybeZeroOid::Zero,
710+
},
711+
);
712+
current_oid = rebased_commit_oid;
713+
714+
writeln!(
715+
effects.get_output_stream(),
716+
"{} Amended as: {}",
717+
commit_num,
718+
commit_description
719+
)?;
720+
}
721+
}
722+
596723
RebaseCommand::Merge {
597724
replacement_commit_oid: None,
598725
commit_oid,

0 commit comments

Comments
 (0)