git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Behavior of git rm

From
Jeff King <peff@peff.net>
Date
Apr 3, 2013, 20:36 UTC
Message-ID
<20130403203612.GB3982@sigill.intra.peff.net>
In-Reply-To
<7vli8z5xfr.fsf@alter.siamese.dyndns.org>
On Wed, Apr 03, 2013 at 10:35:52AM -0700, Junio C Hamano wrote:
Show 21 quoted lines
> > 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)
> 
> OK.  We may be running lstat() on D/F but there may be D that is not
> a directory.  If it is a file, we get ENOTDIR.
> 
> By the way, if D is a dangling symlink, we get ENOENT; in such a
> case, we report "rm 'D/F'" on the output and remove the index entry.
>
> 	$ rm -f .git/index && rm -fr D E
> 	$ mkdir D && >D/F && git add D && rm -fr D
>         $ ln -s erewhon D && git rm D/F && git ls-files
>         rm 'D/F'

That seems sane to me, and makes me feel like handling ENOTDIR here is the right direction. What that conditional is trying to say is "if it is because the file is not there...", and so far we know of three conditions where it is not there:

  1. There is no entry at that path.
  2. There is a non-directory in the prefix of that path.
  3. There is a dangling symlink in the prefix of that path.

(1) and (3) we already handle via ENOENT. I think it is sane to handle (2) the same as (3), but we do not do so currently.

Show 8 quoted lines
> Also if D is a symlink that point at a directory E, "git rm" does
> something interesting.
> 
> (1) Perhaps we want a complaint in this case.
> 
> 	$ rm -f .git/index && rm -fr D E
> 	$ mkdir D && >D/F && git add D && rm -fr D
> 	$ mkdir E && ln -s E D && git rm D/F

I think that is OK without complaint; the user asked to get rid of D/F, and it is indeed gone (as well as its index entry) after the call finishes. And we did not even need to delete anything, so we cannot be losing data. I am much more concerned about this case:

Show 6 quoted lines
> (2) Perhaps we want to make sure D/F is not beyond a symlink in this
>     case.
> 
> 	$ rm -f .git/index && rm -fr D E
> 	$ mkdir D && >D/F && git add D && rm -fr D
> 	$ mkdir E && ln -s E D && date >E/F && git rm D/F

where the user is deleting something that may or may not be related to the original D/F. On the other hand, I don't have that much sympathy; "rm" would make the same deletion. But hmm...shouldn't we be doing an up-to-date check? Indeed:

  $ git rm D/F
  error: 'D/F' has staged content different from both the file and the HEAD
  (use -f to force removal)
  $ git commit -m foo && git rm D/F
  $ git rm D/F
  error: 'D/F' has local modifications
  (use --cached to keep the file, or -f to force removal)

So I do not think we need any extra safety; the content-level checks should be enough to make sure we are not losing anything.

-Peff
Previous: Junio C HamanoNext: Jeff King
Message 4 of 18 in “Behavior of git rm”
  1. jpinheiroApr 3, 2013
  2. Jeff KingApr 3, 2013
  3. Junio C HamanoApr 3, 2013
  4. Jeff KingApr 3, 2013
  5. Jeff KingApr 4, 2013
  6. 1/3 rm: do not complain about d/f conflicts during deletionJeff King, Apr 4, 2013
  7. 2/3 t3600: test behavior of reverse-d/f conflictJeff King, Apr 4, 2013
  8. 3/3 t3600: test rm of path with changed leading symlinksJeff King, Apr 4, 2013
  9. Junio C HamanoApr 4, 2013
  10. Jeff KingApr 4, 2013
  11. Junio C HamanoApr 4, 2013
  12. Jeff KingApr 4, 2013
  13. Junio C HamanoApr 4, 2013
  14. Jeff KingApr 4, 2013
  15. Junio C HamanoApr 4, 2013
  16. Jeff KingApr 5, 2013
  17. Junio C HamanoApr 5, 2013
  18. Jeff KingApr 5, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.