Cover workspace and index mutation attribution - #2139
Conversation
54de872 to
8560683
Compare
48c825c to
4f4aa0a
Compare
f6e5004 to
ff01c3a
Compare
64478fc to
d691996
Compare
| let head = restore_head | ||
| .filter(|head| !head.is_empty()) | ||
| .map(ToOwned::to_owned) | ||
| .unwrap_or(repo.head()?.target()?); |
There was a problem hiding this comment.
🟡 Cleanup of discarded AI edits after a file restore still aborts when the repository's current position cannot be read
The repository's current position is looked up unconditionally (repo.head()?.target()? at src/daemon.rs:1599) even when the position captured at command time is already known, so a restore whose position is known is still abandoned with an error whenever the current position cannot be resolved.
Impact: Discarded AI edits can stay attached to restored files (and the operation reports an error) even though all the information needed to clean them up was already available.
Eager evaluation of the `unwrap_or` fallback defeats the new event-derived head
The PR threads the head captured by the RestorePaths semantic event (src/daemon.rs:8019-8023, produced in src/daemon/analyzers/workspace.rs:30-32) into apply_checkout_switch_working_log_side_effect so the async side effect no longer depends on live repository state. However Option::unwrap_or evaluates its argument eagerly, so repo.head()?.target()? runs on every restore with pathspecs, even when restore_head is Some:
- Any error from
repo.head()/Reference::target()(src/git/repository.rs:832-854, which falls back to spawninggit rev-parse) propagates out of the function with?, so the pruning is skipped and a side-effect error is recorded even though the known head made the lookup unnecessary. This is reachable in the intended async scenario: HEAD may have become unborn (e.g. a latercheckout --orphan) by the time the restore side effect runs. - It also performs an avoidable ref read /
git rev-parsespawn per restore command.
The pre-existing analogue at src/daemon.rs:7422-7425 has the same shape, but there the value is genuinely needed as a fallback.
| let head = restore_head | |
| .filter(|head| !head.is_empty()) | |
| .map(ToOwned::to_owned) | |
| .unwrap_or(repo.head()?.target()?); | |
| let head = match restore_head.filter(|head| !head.is_empty()) { | |
| Some(head) => head.to_string(), | |
| None => repo.head()?.target()?, | |
| }; |
Was this helpful? React with 👍 or 👎 to provide feedback.
d691996 to
33bbf33
Compare
Uh oh!
There was an error while loading. Please reload this page.