First off thanks for reporting the bug :) So I cannot test this bug as my files system is case sensitive but to just read the code and give a thought in a direction (Assuming that the bug is recreatable) int refs_delete_refs(struct ref_store *refs, const char *logmsg, struct string_list *refnames, unsigned int flags) { ... struct ref_transaction *transaction; ... for_each_string_list_item(item, refnames) { transaction = ref_store_transaction_begin(refs, 0, &err); if (!transaction) { warning(_("could not begin transaction to delete %s: %s"), item->string, err.buf); strbuf_reset(&err); failures = 1; continue; } ret = ref_transaction_delete(transaction, item->string, NULL, NULL, flags, msg, &err); if (ret) { warning(_("could not delete reference %s: %s"), item->string, err.buf); strbuf_reset(&err); ref_transaction_free(transaction); failures = 1; continue; } ret = ref_transaction_commit(transaction, &err); if (ret) { warning(_("could not commit deletion of %s: %s"), item->string, err.buf); strbuf_reset(&err); failures = 1; } ref_transaction_free(transaction); } if (failures) ret = -1; strbuf_release(&err); free(msg); return ret; } The original implementation: Starts a single transaction using ref_store_transaction_begin(). Adds all deletions to that transaction. Commits the transaction. If any deletion fails, the entire transaction is aborted. On case-insensitive file systems, two refs like: may conflict at the file system level (e.g. both mapped to the same file or directory). If Git tries to delete both in one go, the transaction fails due to a lock file or unlink error. (Above are my assumptions till now). What has changed is: Deletes each reference in its own transaction struct ref_transaction *transaction = ref_store_transaction_begin(...); ref_transaction_delete(transaction, ...); ref_transaction_commit(transaction, ...); ref_transaction_free(transaction); If one deletion fails due to a case conflict, the others still proceed. It avoids rolling back the entire prune operation just because of a single failure. Keeps failure count and returns appropriately Signals that something went wrong, but Git can now give partial success feedback. The question I have is If this approach seems viable or perhaps any solution, would it be possible to write a test case for this scenario? Thank you - Jayatheerth