From bdecd9d41b3528e17aea2290344c584412e2424e Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Fri, 13 Jul 2007 19:41:38 +0200 Subject: More permissive "git-rm --cached" behavior without -f. In the previous behavior, "git-rm --cached" (without -f) had the same restriction as "git-rm". This forced the user to use the -f flag in situations which weren't actually dangerous, like: $ git add foo # oops, I didn't want this $ git rm --cached foo # back to initial situation Previously, the index had to match the file *and* the HEAD. With --cached, the index must now match the file *or* the HEAD. The behavior without --cached is unchanged, but provides better error messages. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- builtin-rm.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'builtin-rm.c') diff --git a/builtin-rm.c b/builtin-rm.c index 4a0bd93c8..9a808c1bf 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -46,7 +46,7 @@ static int remove_file(const char *name) return ret; } -static int check_local_mod(unsigned char *head) +static int check_local_mod(unsigned char *head, int index_only) { /* items in list are already sorted in the cache order, * so we could do this a lot more efficiently by using @@ -65,6 +65,8 @@ static int check_local_mod(unsigned char *head) const char *name = list.name[i]; unsigned char sha1[20]; unsigned mode; + int local_changes = 0; + int staged_changes = 0; pos = cache_name_pos(name, strlen(name)); if (pos < 0) @@ -87,14 +89,32 @@ static int check_local_mod(unsigned char *head) continue; } if (ce_match_stat(ce, &st, 0)) - errs = error("'%s' has local modifications " - "(hint: try -f)", ce->name); + local_changes = 1; if (no_head || get_tree_entry(head, name, sha1, &mode) || ce->ce_mode != create_ce_mode(mode) || hashcmp(ce->sha1, sha1)) - errs = error("'%s' has changes staged in the index " - "(hint: try -f)", name); + staged_changes = 1; + + if (local_changes && staged_changes) + errs = error("'%s' has staged content different " + "from both the file and the HEAD\n" + "(use -f to force removal)", name); + else if (!index_only) { + /* It's not dangerous to git-rm --cached a + * file if the index matches the file or the + * HEAD, since it means the deleted content is + * still available somewhere. + */ + if (staged_changes) + errs = error("'%s' has changes staged in the index\n" + "(use --cached to keep the file, " + "or -f to force removal)", name); + if (local_changes) + errs = error("'%s' has local modifications\n" + "(use --cached to keep the file, " + "or -f to force removal)", name); + } } return errs; } @@ -192,7 +212,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); - if (check_local_mod(sha1)) + if (check_local_mod(sha1, index_only)) exit(1); } -- cgit v1.2.1