From: Jeff King <peff@peff.net>
To: jpinheiro <7jpinheiro@gmail.com>
Cc: git@vger.kernel.org
Subject: Re: Behavior of git rm
Date: Wed, 3 Apr 2013 11:58:41 -0400 [thread overview]
Message-ID: <20130403155841.GA16885@sigill.intra.peff.net> (raw)
In-Reply-To: <1365000624535-7581485.post@n2.nabble.com>
On Wed, Apr 03, 2013 at 07:50:24AM -0700, jpinheiro wrote:
> While experimenting with git we found an unexpected behavior with git rm.
> Here is a trace of the unexpected behavior:
>
> $ git init
> $ mkdir D
> $ echo "Hi" > D/F
> $ git add D/F
> $ rm -r D
> $ echo "Hey" > D
> $ git rm D/F
> warning: 'D/F': Not a directory
> rm 'D/F'
> fatal: git rm: 'D/F': Not a directory
We drop the D/F entry from the index, but then fail to actually remove
it from the filesystem, because it has already been replaced. It is
impossible to tell from this toy example what the true intent was, but
in such a situation, there is a reasonable chance that the user should
have invoked "rm --cached" in the first place.
That being said, we do try to handle files which have already gone
missing; when unlink() fails, we do not consider it an error if we got
ENOENT. We could perhaps add ENOTDIR to that list, as it also indicates
that the file is gone (it just happens that one of its prefix
directories was replaced with something else).
The opposite case is also interesting:
$ git init
$ echo 1 >D
$ git add D
$ rm D
$ mkdir D
$ echo 2 >D/F
$ git rm D
rm 'D'
fatal: git rm: 'D': Is a directory
We expect to see 'D' as a file, but it is now a directory. We _could_
recursively remove the directory, but that has the potential to delete
files that the user does not expect.
So in both cases, "git rm" could certainly detect the situation and
proceed with the destructive operation. But when there is such a
conflict between what's in the working tree and what's in the index, I
think we may be better off erring on the conservative side and bailing,
and letting the user reconcile the differences themselves (using either
"git add" or "git rm --cached" to update the index, or deciding how to
handle the working tree contents themselves with regular "rm").
Of the two situations, I think the first one is less likely to be
destructive (noticing that a file is already gone via ENOTDIR), as we
are only proceeding with the index deletion, and we end up not touching
the filesystem at all. That patch would look something like:
diff --git a/builtin/rm.c b/builtin/rm.c
index dabfcf6..7b91d52 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -110,7 +110,7 @@ static int check_local_mod(unsigned char *head, int index_only)
ce = active_cache[pos];
if (lstat(ce->name, &st) < 0) {
- if (errno != ENOENT)
+ if (errno != ENOENT && errno != ENOTDIR)
warning("'%s': %s", ce->name, strerror(errno));
/* It already vanished from the working tree */
continue;
diff --git a/dir.c b/dir.c
index 57394e4..f9e7355 100644
--- a/dir.c
+++ b/dir.c
@@ -1603,7 +1603,7 @@ int remove_path(const char *name)
{
char *slash;
- if (unlink(name) && errno != ENOENT)
+ if (unlink(name) && errno != ENOENT && errno != ENOTDIR)
return -1;
slash = strrchr(name, '/');
next prev parent reply other threads:[~2013-04-03 15:59 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-03 14:50 Behavior of git rm jpinheiro
2013-04-03 15:58 ` Jeff King [this message]
2013-04-03 17:35 ` Junio C Hamano
2013-04-03 20:36 ` Jeff King
2013-04-04 19:02 ` Jeff King
2013-04-04 19:03 ` [PATCH 1/3] rm: do not complain about d/f conflicts during deletion Jeff King
2013-04-04 19:03 ` [PATCH 2/3] t3600: test behavior of reverse-d/f conflict Jeff King
2013-04-04 19:06 ` [PATCH 3/3] t3600: test rm of path with changed leading symlinks Jeff King
2013-04-04 19:42 ` Junio C Hamano
2013-04-04 19:55 ` Jeff King
2013-04-04 20:31 ` Junio C Hamano
2013-04-04 21:03 ` Jeff King
2013-04-04 23:12 ` Junio C Hamano
2013-04-04 23:29 ` Jeff King
2013-04-04 23:33 ` Junio C Hamano
2013-04-05 0:00 ` Jeff King
2013-04-05 4:59 ` Junio C Hamano
2013-04-05 5:04 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130403155841.GA16885@sigill.intra.peff.net \
--to=peff@peff.net \
--cc=7jpinheiro@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).