Skip to content

Commit 884c587

Browse files
committed
Implement but undo
1 parent 4aeb8fb commit 884c587

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
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: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,54 @@ pub(crate) fn restore_to_oplog(
196196

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

0 commit comments

Comments
 (0)