diff --git a/builtin-rm.c b/builtin-rm.c index e06640cf8d..b7126e3e25 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -79,7 +79,8 @@ static int check_local_mod(unsigned char *head, int index_only) || hashcmp(ce->sha1, sha1)) staged_changes = 1; - if (local_changes && staged_changes) + if (local_changes && staged_changes && + !(index_only && is_empty_blob_sha1(ce->sha1))) errs = error("'%s' has staged content different " "from both the file and the HEAD\n" "(use -f to force removal)", name); diff --git a/cache.h b/cache.h index cdbeb48c65..b0edbf9b9f 100644 --- a/cache.h +++ b/cache.h @@ -519,6 +519,7 @@ static inline void hashclr(unsigned char *hash) { memset(hash, 0, 20); } +extern int is_empty_blob_sha1(const unsigned char *sha1); int git_mkstemp(char *path, size_t n, const char *template); diff --git a/read-cache.c b/read-cache.c index fdb41b872e..2c450866ce 100644 --- a/read-cache.c +++ b/read-cache.c @@ -160,7 +160,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) return 0; } -static int is_empty_blob_sha1(const unsigned char *sha1) +int is_empty_blob_sha1(const unsigned char *sha1) { static const unsigned char empty_blob_sha1[20] = { 0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b, diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 66aca99fd3..5b4d6f7138 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -187,6 +187,19 @@ test_expect_success 'but with -f it should work.' ' test_must_fail git ls-files --error-unmatch baz ' +test_expect_failure 'refuse to remove cached empty file with modifications' ' + touch empty && + git add empty && + echo content >empty && + test_must_fail git rm --cached empty +' + +test_expect_success 'remove intent-to-add file without --force' ' + echo content >intent-to-add && + git add -N intent-to-add + git rm --cached intent-to-add +' + test_expect_success 'Recursive test setup' ' mkdir -p frotz && echo qfwfq >frotz/nitfol &&