Skip to content

Commit f2e5695

Browse files
authored
Merge pull request #10462 from gitbutlerapp/kv-branch-55
Implement but undo
2 parents 4aeb8fb + b07cd77 commit f2e5695

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

crates/but/src/args.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ For examples see `but rub --help`."
9595
/// Oplog SHA to restore to
9696
oplog_sha: String,
9797
},
98+
/// Undo the last operation by reverting to the previous snapshot.
99+
Undo,
98100
/// Starts up the MCP server.
99101
Mcp {
100102
/// Starts the internal MCP server which has more granular tools.
@@ -138,6 +140,8 @@ pub enum CommandName {
138140
Oplog,
139141
#[clap(alias = "restore")]
140142
Restore,
143+
#[clap(alias = "undo")]
144+
Undo,
141145
BaseCheck,
142146
BaseUpdate,
143147
BranchNew,

crates/but/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ async fn main() -> Result<()> {
183183
metrics_if_configured(app_settings, CommandName::Restore, props(start, &result)).ok();
184184
result
185185
}
186+
Subcommands::Undo => {
187+
let result = oplog::undo_last_operation(&args.current_dir, args.json);
188+
metrics_if_configured(app_settings, CommandName::Undo, props(start, &result)).ok();
189+
result
190+
}
186191
Subcommands::Init { repo } => init::repo(&args.current_dir, args.json, *repo)
187192
.context("Failed to initialize GitButler project."),
188193
}

crates/but/src/oplog/mod.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ pub(crate) fn restore_to_oplog(
122122
oplog_sha: &str,
123123
) -> anyhow::Result<()> {
124124
let project = Project::find_by_path(repo_path)?;
125+
let snapshots = but_api::undo::list_snapshots(project.id, 100, None, None)?;
125126

126127
// Parse the oplog SHA (support partial SHAs)
127128
let commit_sha_string = if oplog_sha.len() >= 7 {
128129
// Try to find a snapshot that starts with this SHA
129-
let snapshots = but_api::undo::list_snapshots(project.id, 100, None, None)?;
130130

131131
let matching_snapshot = snapshots
132132
.iter()
@@ -139,7 +139,6 @@ pub(crate) fn restore_to_oplog(
139139
};
140140

141141
// Get information about the target snapshot
142-
let snapshots = but_api::undo::list_snapshots(project.id, 100, None, None)?;
143142
let target_snapshot = snapshots
144143
.iter()
145144
.find(|snapshot| snapshot.commit_id.to_string() == commit_sha_string)
@@ -196,3 +195,54 @@ pub(crate) fn restore_to_oplog(
196195

197196
Ok(())
198197
}
198+
199+
pub(crate) fn undo_last_operation(repo_path: &Path, _json: bool) -> anyhow::Result<()> {
200+
let project = Project::find_by_path(repo_path)?;
201+
202+
// Get the last two snapshots - restore to the second one back
203+
let snapshots = but_api::undo::list_snapshots(project.id, 2, None, None)?;
204+
205+
if snapshots.len() < 2 {
206+
println!("{}", "No previous operations to undo.".yellow());
207+
return Ok(());
208+
}
209+
210+
let target_snapshot = &snapshots[1];
211+
212+
let target_operation = target_snapshot
213+
.details
214+
.as_ref()
215+
.map(|d| d.title.as_str())
216+
.unwrap_or("Unknown operation");
217+
218+
let target_time = chrono::DateTime::from_timestamp(target_snapshot.created_at.seconds(), 0)
219+
.ok_or(anyhow::anyhow!("Could not parse timestamp"))?
220+
.format("%Y-%m-%d %H:%M:%S")
221+
.to_string();
222+
223+
println!("{}", "Undoing operation...".blue().bold());
224+
println!(
225+
" Reverting to: {} ({})",
226+
target_operation.green(),
227+
target_time.dimmed()
228+
);
229+
230+
// Restore to the previous snapshot using the but_api
231+
but_api::undo::restore_snapshot(project.id, target_snapshot.commit_id.to_string())?;
232+
233+
let restore_commit_short = format!(
234+
"{}{}",
235+
&target_snapshot.commit_id.to_string()[..7]
236+
.blue()
237+
.underline(),
238+
&target_snapshot.commit_id.to_string()[7..12].blue().dimmed()
239+
);
240+
241+
println!(
242+
"{} Undo completed successfully! Restored to snapshot: {}",
243+
"✓".green().bold(),
244+
restore_commit_short
245+
);
246+
247+
Ok(())
248+
}

0 commit comments

Comments
 (0)