Skip to content

fix(git): remove read-only .git packfiles on Windows when falling back to fresh clone - #112

Open
spelech wants to merge 2 commits into
mainfrom
fix/git-clone-recovery-readonly-cleanup
Open

spelech wants to merge 2 commits into
mainfrom
fix/git-clone-recovery-readonly-cleanup

Conversation

@spelech

@spelech spelech commented Nov 11, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes an unrecoverable repository clone state on Windows when an incremental git fetch fails in a persistent clone directory (keep_shallow=True) and falls back to a fresh git clone:

  1. Read-Only .git/objects/pack/* Cleanup on Windows (cleanup_repo_dir):
    • Previously, cleanup_repo_dir called shutil.rmtree(repo_dir, ignore_errors=True). On Windows, Git marks packfiles (.pack / .idx) inside .git\objects\pack as read-only, causing shutil.rmtree to fail with PermissionError and silently leave the non-empty directory behind due to ignore_errors=True.
    • The subsequent git clone then failed permanently with fatal: destination path '...' already exists and is not an empty directory.
    • cleanup_repo_dir now uses an onerror=_handle_remove_readonly callback that clears read-only file attributes (os.chmod(path, stat.S_IWRITE | stat.S_IREAD)) and retries deletion, plus an atomic rename fallback (os.replace) if a handle is briefly held.
  2. Incremental Fetch & Fallback Clone Recovery (shallow_clone_repo):
    • Updates the origin remote URL (git remote set-url origin) before running git fetch so token/credential updates take effect on existing clones.
    • Checks git reset --hard return code (falling back to FETCH_HEAD or a fresh clone if reset fails).
    • Ensures repo_dir is cleaned up before the fallback git clone and if the initial --branch clone fails.

This branch has not been deployed

No deployments
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.

1 participant