Skip to content

Refuse a checkout that would delete a file where the target has a directory - #1153

Open
CleanCut wants to merge 1 commit into
mainfrom
cleancut/checkout-keep-untracked-file
Open

CleanCut wants to merge 1 commit into
mainfrom
cleancut/checkout-keep-untracked-file

Conversation

@CleanCut

Copy link
Copy Markdown
Collaborator

oxen checkout <branch> deleted any file sitting where the target branch has a directory, unless it was a tracked file with local edits. An untracked file there, or a file put in place of a tracked directory, was lost with no error, while the same untracked file stopped the checkout when the target had a file at that path instead.

Checkout now replaces such a file only when it is the current commit's file at that path, unchanged, and otherwise fails with the "your local changes would be overwritten" error and leaves the working tree as it was. oxen merge --abort still replaces it. This affects local working trees only (the CLI and Python bindings), not oxen-server.

Fixes #1136

…ectory

`oxen checkout <branch>` deleted any file sitting where the target branch has a directory, unless
it was a tracked file with local edits. An untracked file there, or a file put in place of a
tracked directory, was lost with no error, while the same untracked file stopped the checkout when
the target had a file at that path instead.

Checkout now replaces such a file only when it is the current commit's file at that path,
unchanged, and otherwise fails with the "your local changes would be overwritten" error and leaves
the working tree as it was. `oxen merge --abort` still replaces it. This affects local working
trees only (the CLI and Python bindings), not oxen-server.

Fixes #1136
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 0f0f397 and 73e2928.

Files selected for processing: 2
  • crates/liboxen/src/core/v_latest/branches.rs
  • crates/liboxen/src/repositories/checkout.rs

Included review availability: This review used your included allowance. Your plan provides up to 5 included reviews per hour; 0 remain after this review.

📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Checkout now preserves untracked files and locally modified files when they conflict with a directory in the target branch, and reports an overwrite conflict instead of replacing them.
    • Unmodified tracked files can still be replaced by the target directory, and choosing overwrite restores the directory and its contents.
  • Tests
    • Added coverage for file-versus-directory conflicts across branches, including preserved file contents and unchanged checkout state after a conflict.

Checkout now refuses directory replacement when the working-tree file is untracked or fails the unchanged-file checks. Regression tests cover conflict refusal, file preservation, replacement of an unchanged tracked file, and OnConflict::Overwrite.

Changes: Checkout directory replacement conflicts

Layer / File(s) Summary
Directory replacement conflict handling
crates/liboxen/src/core/v_latest/branches.rs, crates/liboxen/src/repositories/checkout.rs
Under OnConflict::Abort, checkout records a conflict if no corresponding from-tree file exists or if the tracked file fails the size and mtime-or-hash checks. Tests verify refusal and content preservation, permitted replacement of an unchanged tracked file, and replacement under OnConflict::Overwrite.

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

Merge Risk: Minimal · up to 73e29

Checkout appears to preserve conflicting local files while still allowing an unchanged tracked file to be replaced. No actionable merge risk remains after normal checks.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main checkout change: refusing to delete a file when the target has a directory at that path.
Description check Passed The description directly explains the checkout behavior, the conditions for replacement, the preserved working tree, and the affected interfaces. It matches the changeset.
Linked Issues check Passed Issue [#1136] requires checkout to refuse a non-directory entry where the target tree requires a directory, report the local-changes-overwritten error, and preserve the entry. walk_target_tree now p…
Out of Scope Changes check Passed The changes are limited to checkout conflict handling in crates/liboxen/src/core/v_latest/branches.rs and related checkout regression tests. The OnConflict::Overwrite assertion verifies the docume…
Full details: Linked Issues check

Explanation

Issue [#1136] requires checkout to refuse a non-directory entry where the target tree requires a directory, report the local-changes-overwritten error, and preserve the entry. walk_target_tree now permits replacement under OnConflict::Abort only for an unchanged file from the current tree. Untracked entries and changed tracked entries become conflicts before any replacement. The regression test covers an untracked file, error text, unchanged contents, and unchanged HEAD. The test also covers replacement of an unchanged tracked file and the existing overwrite path.

Full details: Out of Scope Changes check

Explanation

The changes are limited to checkout conflict handling in crates/liboxen/src/core/v_latest/branches.rs and related checkout regression tests. The OnConflict::Overwrite assertion verifies the documented oxen merge --abort behavior. The changes support the linked checkout objective and do not add unrelated product behavior.

Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

oxen checkout deletes an untracked file where the target branch has a directory

1 participant