Skip to content

Commit 7641018

Browse files
feat(repo): Add AmendFastOptions::FromCommit
Existing `AmendFastOptions` only support amending from the working copy or index, but we can't use either of these for implementing something like squashing fixup commits because we need to use the entries from an existing commit.
1 parent 926008d commit 7641018

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

git-branchless-lib/src/git/repo.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ pub enum CreateCommitFastError {
427427

428428
/// Options for `Repo::amend_fast`
429429
#[derive(Debug)]
430-
pub enum AmendFastOptions {
430+
pub enum AmendFastOptions<'repo> {
431431
/// Amend a set of paths from the current state of the working copy.
432432
FromWorkingCopy {
433433
/// The status entries for the files to amend.
@@ -438,14 +438,20 @@ pub enum AmendFastOptions {
438438
/// The paths to amend.
439439
paths: Vec<PathBuf>,
440440
},
441+
/// Amend a set of paths from a different commit.
442+
FromCommit {
443+
/// The commit whose contents will be amended.
444+
commit: Commit<'repo>,
445+
},
441446
}
442447

443-
impl AmendFastOptions {
448+
impl<'repo> AmendFastOptions<'repo> {
444449
/// Returns whether there are any paths to be amended.
445450
pub fn is_empty(&self) -> bool {
446451
match &self {
447452
AmendFastOptions::FromIndex { paths } => paths.is_empty(),
448453
AmendFastOptions::FromWorkingCopy { status_entries } => status_entries.is_empty(),
454+
AmendFastOptions::FromCommit { commit } => commit.is_empty(),
449455
}
450456
}
451457
}
@@ -1422,10 +1428,14 @@ impl Repo {
14221428
/// See `Repo::cherry_pick_fast` for motivation for performing the operation
14231429
/// in-memory.
14241430
#[instrument]
1425-
pub fn amend_fast(&self, parent_commit: &Commit, opts: &AmendFastOptions) -> Result<Tree> {
1431+
pub fn amend_fast(
1432+
&self,
1433+
parent_commit: &Commit,
1434+
opts: &AmendFastOptions,
1435+
) -> std::result::Result<Tree, CreateCommitFastError> {
14261436
let parent_commit_pathbufs = self
14271437
.get_paths_touched_by_commit(parent_commit)?
1428-
.ok_or_else(|| Error::GetPatch {
1438+
.ok_or_else(|| CreateCommitFastError::GetPatch {
14291439
commit: parent_commit.get_oid(),
14301440
})?
14311441
.into_iter()
@@ -1439,6 +1449,11 @@ impl Repo {
14391449
result.extend(entry.paths().iter().cloned());
14401450
}
14411451
}
1452+
AmendFastOptions::FromCommit { commit } => {
1453+
if let Some(paths) = self.get_paths_touched_by_commit(commit)? {
1454+
result.extend(paths.iter().cloned());
1455+
}
1456+
}
14421457
};
14431458
result.into_iter().collect_vec()
14441459
};
@@ -1492,6 +1507,25 @@ impl Repo {
14921507
})
14931508
.collect::<HashMap<_, _>>()
14941509
}
1510+
AmendFastOptions::FromCommit { commit } => {
1511+
let amended_tree = self.cherry_pick_fast(
1512+
commit,
1513+
parent_commit,
1514+
&CherryPickFastOptions {
1515+
reuse_parent_tree_if_possible: false,
1516+
},
1517+
)?;
1518+
self.get_paths_touched_by_commit(commit)?
1519+
.unwrap_or_default()
1520+
.iter()
1521+
.filter_map(|path| match amended_tree.get_path(path) {
1522+
Ok(Some(entry)) => {
1523+
Some((path.clone(), Some((entry.get_oid(), entry.get_filemode()))))
1524+
}
1525+
Ok(None) | Err(_) => None,
1526+
})
1527+
.collect::<HashMap<_, _>>()
1528+
}
14951529
};
14961530

14971531
// Merge the new path entries into the existing set of parent tree.

git-branchless/src/commands/amend.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ pub fn amend(
373373
"Amended with {uncommitted_changes}.",
374374
)?;
375375
}
376+
AmendFastOptions::FromCommit { .. } => {
377+
unreachable!("BUG: AmendFastOptions::FromCommit should not have been constructed.")
378+
}
376379
}
377380

378381
Ok(Ok(()))

0 commit comments

Comments
 (0)