···33use jj_lib::commit::Commit;
44use jj_lib::config::ConfigSource;
55use jj_lib::merged_tree::MergedTree;
66-use jj_lib::object_id::{HexPrefix, PrefixResolution};
66+use jj_lib::object_id::{HexPrefix, ObjectId, PrefixResolution};
77+use jj_lib::op_walk;
78use jj_lib::repo::{Repo, StoreFactories};
89use jj_lib::repo_path::RepoPath;
910use jj_lib::settings::UserSettings;
1011use jj_lib::workspace::{Workspace, default_working_copy_factories};
1212+use std::collections::HashMap;
1113use std::path::Path;
1214use tokio::io::AsyncReadExt;
1315···234236 Ok(())
235237 }
236238239239+ pub fn abandon_revision(&mut self, change_id: &str) -> Result<()> {
240240+ let repo = self.workspace.repo_loader().load_at_head()?;
241241+ let mut tx = repo.start_transaction();
242242+243243+ // Resolve change ID to commit
244244+ let commit_id = self.resolve_change_id(repo.as_ref(), change_id)?;
245245+ let commit = repo.store().get_commit(&commit_id)
246246+ .map_err(|e| anyhow::anyhow!("Failed to get commit: {}", e))?;
247247+248248+ // Get the current working copy info before changes
249249+ let wc_commit_id = repo
250250+ .view()
251251+ .get_wc_commit_id(self.workspace.workspace_name())
252252+ .cloned();
253253+ let is_abandoning_wc = wc_commit_id.as_ref() == Some(commit.id());
254254+255255+ // Record the commit as abandoned
256256+ tx.repo_mut().record_abandoned_commit(&commit);
257257+258258+ // Rebase descendants (this handles moving children to the parent)
259259+ tx.repo_mut().rebase_descendants()?;
260260+261261+ // If we abandoned the working copy, check out the parent
262262+ if is_abandoning_wc {
263263+ let parent_id = commit.parent_ids().first().cloned()
264264+ .context("Abandoned commit has no parent")?;
265265+ let parent_commit = repo.store().get_commit(&parent_id)?;
266266+267267+ // Set the parent as the new working copy
268268+ let workspace_name = self.workspace.workspace_name().to_owned();
269269+ tx.repo_mut()
270270+ .set_wc_commit(workspace_name, parent_id.clone())
271271+ .context("Failed to set working copy commit")?;
272272+273273+ // Finalize transaction before checkout
274274+ let new_repo = tx.commit("abandon")?;
275275+ let operation_id = new_repo.operation().id().clone();
276276+277277+ // Check out the parent commit
278278+ let old_tree_id = commit.tree_id().clone();
279279+ self.workspace
280280+ .check_out(operation_id, Some(&old_tree_id), &parent_commit)
281281+ .context("Failed to check out parent commit")?;
282282+ } else {
283283+ // Finalize transaction
284284+ tx.commit("abandon")?;
285285+ }
286286+287287+ Ok(())
288288+ }
289289+237290 pub fn edit_revision(&mut self, change_id: String) -> Result<()> {
238291 let repo = self.workspace.repo_loader().load_at_head()?;
239292 let mut tx = repo.start_transaction();
···267320 .context("Failed to check out commit")?;
268321269322 Ok(())
323323+ }
324324+325325+ /// Walk the operation log to find when each commit was last the working copy.
326326+ /// Returns a map of commit_id (hex) -> timestamp_millis.
327327+ /// This is used to determine "recency" for branch ordering.
328328+ pub fn get_commit_recency(&self, limit: usize) -> Result<HashMap<String, i64>> {
329329+ let repo = self.workspace.repo_loader().load_at_head()?;
330330+ let current_op = repo.operation();
331331+ let workspace_name = self.workspace.workspace_name();
332332+333333+ let mut recency: HashMap<String, i64> = HashMap::new();
334334+335335+ // Walk operations from newest to oldest
336336+ let op_iter = op_walk::walk_ancestors(std::slice::from_ref(current_op));
337337+338338+ for (idx, op_result) in op_iter.enumerate() {
339339+ if idx >= limit {
340340+ break;
341341+ }
342342+343343+ let op = op_result.context("Failed to load operation")?;
344344+ let metadata = op.metadata();
345345+ let timestamp_millis = metadata.time.start.timestamp.0;
346346+347347+ // Get the view for this operation to see what was the WC
348348+ let view = op.view().context("Failed to load operation view")?;
349349+350350+ // Check what commit was the working copy at this operation
351351+ if let Some(wc_commit_id) = view.wc_commit_ids().get(workspace_name) {
352352+ let commit_hex = wc_commit_id.hex();
353353+ // Only record the first (most recent) occurrence
354354+ recency.entry(commit_hex).or_insert(timestamp_millis);
355355+ }
356356+ }
357357+358358+ Ok(recency)
270359 }
271360}