Skip to content

Commit 9ac8f72

Browse files
Caleb-T-Owensschacon
authored andcommitted
Add moving files between commits
1 parent 5531548 commit 9ac8f72

File tree

2 files changed

+76
-17
lines changed

2 files changed

+76
-17
lines changed

crates/but/src/rub/commits.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use anyhow::{Context, Result};
2+
use bstr::ByteSlice;
3+
use but_core::diff::tree_changes;
4+
use but_workspace::DiffSpec;
5+
use gitbutler_branch_actions::update_workspace_commit;
6+
use gitbutler_command_context::CommandContext;
7+
use gitbutler_stack::VirtualBranchesHandle;
8+
9+
use crate::rub::undo::stack_id_by_commit_id;
10+
11+
pub fn commited_file_to_another_commit(
12+
ctx: &mut CommandContext,
13+
path: &str,
14+
source_id: gix::ObjectId,
15+
target_id: gix::ObjectId,
16+
) -> Result<()> {
17+
let source_stack = stack_id_by_commit_id(ctx, &source_id)?;
18+
let target_stack = stack_id_by_commit_id(ctx, &target_id)?;
19+
20+
let repo = ctx.gix_repo()?;
21+
let source_commit = repo.find_commit(source_id)?;
22+
let source_commit_parent_id = source_commit.parent_ids().next().context("First parent")?;
23+
24+
let (tree_changes, _) = tree_changes(&repo, Some(source_commit_parent_id.detach()), source_id)?;
25+
let relevant_changes = tree_changes
26+
.into_iter()
27+
.filter(|tc| tc.path.to_str_lossy() == path)
28+
.map(Into::into)
29+
.collect::<Vec<DiffSpec>>();
30+
31+
but_workspace::move_changes_between_commits(
32+
ctx,
33+
source_stack,
34+
source_id,
35+
target_stack,
36+
target_id,
37+
relevant_changes,
38+
ctx.app_settings().context_lines,
39+
)?;
40+
41+
let vb_state = VirtualBranchesHandle::new(ctx.project().gb_dir());
42+
update_workspace_commit(&vb_state, &ctx)?;
43+
44+
println!("Moved files between commits!");
45+
46+
Ok(())
47+
}

crates/but/src/rub/mod.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ use gitbutler_project::Project;
88
use gitbutler_oplog::{OplogExt, entry::{OperationKind, SnapshotDetails}};
99
mod amend;
1010
mod assign;
11+
mod commits;
1112
mod move_commit;
1213
mod squash;
13-
mod undo;
1414
mod uncommit;
15+
mod undo;
1516

1617
use crate::id::CliId;
1718

@@ -58,12 +59,20 @@ pub(crate) fn handle(
5859
uncommit::file_from_commit(ctx, path, commit_oid)?;
5960
}
6061
(CliId::CommittedFile { .. }, CliId::Branch { .. }) => {
61-
// Extract file from commit to branch - for now, not implemented
62-
bail!("Extracting files from commits is not yet supported. Use git commands to extract file changes.")
62+
// Extract file from commit to branch - for now, not implemented
63+
bail!(
64+
"Extracting files from commits is not yet supported. Use git commands to extract file changes."
65+
)
6366
}
64-
(CliId::CommittedFile { .. }, CliId::Commit { .. }) => {
65-
// Move file from one commit to another - for now, not implemented
66-
bail!("Moving files between commits is not yet supported. Use git commands to modify commits.")
67+
(
68+
CliId::CommittedFile {
69+
path,
70+
commit_oid: source_id,
71+
},
72+
CliId::Commit { oid: target_id },
73+
) => {
74+
create_snapshot(ctx, &project, OperationKind::FileChanges);
75+
commits::commited_file_to_another_commit(ctx, path, *source_id, *target_id)?;
6776
}
6877
(CliId::Unassigned, CliId::UncommittedFile { .. }) => {
6978
bail!(makes_no_sense_error(&source, &target))
@@ -74,11 +83,11 @@ pub(crate) fn handle(
7483
(CliId::Unassigned, CliId::Commit { oid }) => {
7584
create_snapshot(ctx, &project, OperationKind::AmendCommit);
7685
amend::assignments_to_commit(ctx, None, oid)?;
77-
},
86+
}
7887
(CliId::Unassigned, CliId::Branch { name: to }) => {
7988
create_snapshot(ctx, &project, OperationKind::MoveHunk);
8089
assign::assign_all(ctx, None, Some(to))?;
81-
},
90+
}
8291
(CliId::Unassigned, CliId::CommittedFile { .. }) => {
8392
bail!(makes_no_sense_error(&source, &target))
8493
}
@@ -91,15 +100,15 @@ pub(crate) fn handle(
91100
(CliId::Commit { oid }, CliId::Unassigned) => {
92101
create_snapshot(ctx, &project, OperationKind::UndoCommit);
93102
undo::commit(ctx, oid)?;
94-
},
103+
}
95104
(CliId::Commit { oid: source_oid }, CliId::Commit { oid: destination }) => {
96105
create_snapshot(ctx, &project, OperationKind::SquashCommit);
97106
squash::commits(ctx, source_oid, destination)?;
98107
}
99108
(CliId::Commit { oid }, CliId::Branch { name }) => {
100109
create_snapshot(ctx, &project, OperationKind::MoveCommit);
101110
move_commit::to_branch(ctx, oid, name)?;
102-
},
111+
}
103112
(CliId::Branch { .. }, CliId::UncommittedFile { .. }) => {
104113
bail!(makes_no_sense_error(&source, &target))
105114
}
@@ -140,17 +149,20 @@ fn ids(ctx: &mut CommandContext, source: &str, target: &str) -> anyhow::Result<(
140149
if target_result.len() != 1 {
141150
if target_result.is_empty() {
142151
return Err(anyhow::anyhow!(
143-
"Target '{}' not found. If you just performed a Git operation (squash, rebase, etc.), try running 'but status' to refresh the current state.",
152+
"Target '{}' not found. If you just performed a Git operation (squash, rebase, etc.), try running 'but status' to refresh the current state.",
144153
target
145154
));
146155
} else {
147-
let matches: Vec<String> = target_result.iter().map(|id| {
148-
match id {
149-
CliId::Commit { oid } => format!("{} (commit {})", id.to_string(), &oid.to_string()[..7]),
156+
let matches: Vec<String> = target_result
157+
.iter()
158+
.map(|id| match id {
159+
CliId::Commit { oid } => {
160+
format!("{} (commit {})", id.to_string(), &oid.to_string()[..7])
161+
}
150162
CliId::Branch { name } => format!("{} (branch '{}')", id.to_string(), name),
151-
_ => format!("{} ({})", id.to_string(), id.kind())
152-
}
153-
}).collect();
163+
_ => format!("{} ({})", id.to_string(), id.kind()),
164+
})
165+
.collect();
154166
return Err(anyhow::anyhow!(
155167
"Target '{}' is ambiguous. Matches: {}. Try using more characters, a longer SHA, or the full branch name to disambiguate.",
156168
target,

0 commit comments

Comments
 (0)