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 <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
1701872fc2
commit
bdecd9d41b
@ -14,7 +14,8 @@ DESCRIPTION
|
||||
Remove files from the working tree and from the index. The
|
||||
files have to be identical to the tip of the branch, and no
|
||||
updates to its contents must have been placed in the staging
|
||||
area (aka index).
|
||||
area (aka index). When --cached is given, the staged content has to
|
||||
match either the tip of the branch *or* the file on disk.
|
||||
|
||||
|
||||
OPTIONS
|
||||
|
32
builtin-rm.c
32
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);
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,40 @@ test_expect_success \
|
||||
'Test that git rm foo succeeds' \
|
||||
'git rm --cached foo'
|
||||
|
||||
test_expect_success \
|
||||
'Test that git rm --cached foo succeeds if the index matches the file' \
|
||||
'echo content > foo
|
||||
git add foo
|
||||
git rm --cached foo'
|
||||
|
||||
test_expect_success \
|
||||
'Test that git rm --cached foo succeeds if the index matches the file' \
|
||||
'echo content > foo
|
||||
git add foo
|
||||
git commit -m foo
|
||||
echo "other content" > foo
|
||||
git rm --cached foo'
|
||||
|
||||
test_expect_failure \
|
||||
'Test that git rm --cached foo fails if the index matches neither the file nor HEAD' \
|
||||
'echo content > foo
|
||||
git add foo
|
||||
git commit -m foo
|
||||
echo "other content" > foo
|
||||
git add foo
|
||||
echo "yet another content" > foo
|
||||
git rm --cached foo'
|
||||
|
||||
test_expect_success \
|
||||
'Test that git rm --cached -f foo works in case where --cached only did not' \
|
||||
'echo content > foo
|
||||
git add foo
|
||||
git commit -m foo
|
||||
echo "other content" > foo
|
||||
git add foo
|
||||
echo "yet another content" > foo
|
||||
git rm --cached -f foo'
|
||||
|
||||
test_expect_success \
|
||||
'Post-check that foo exists but is not in index after git rm foo' \
|
||||
'[ -f foo ] && ! git ls-files --error-unmatch foo'
|
||||
|
Loading…
Reference in New Issue
Block a user