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

Re: "git rm" seems to do recursive removal even without "-r"

From
Kevin Daudt <me@ikke.info>
Date
Oct 8, 2017, 11:37 UTC
Message-ID
<20171008113732.GA8251@alpha.vpn.ikke.info>
In-Reply-To
<alpine.LFD.2.21.1710080502050.19600@localhost.localdomain>
On Sun, Oct 08, 2017 at 05:07:12AM -0400, Robert P. J. Day wrote:
Show 30 quoted lines
> On Sun, 8 Oct 2017, Junio C Hamano wrote:
> 
> > "Robert P. J. Day" <rpjday@crashcourse.ca> writes:
> >
> > > ... so if, in the kernel source
> > > tree, i ran:
> > >
> > >   $ git rm \*.c
> > >
> > > i would end up removing *all* 25,569 "*.c" files in the kernel source
> > > repository.
> >
> > Yes, as that is exactly what the command line asks Git to do.
> 
>   so if i wanted git to remove, say, all files named "Makefile*" from
> everywhere in the linux kernel source tree, the (dry run) command
> would be:
> 
>   $ git rm -n Makefile\*
> 
> is that it? let's try that:
> 
>   $ git rm -n Makefile\*
>   rm 'Makefile'
>   $
> 
> oops.
> 
> rday
> 

So your question is not su much about the recursive option (delete mentioned directories, including their contents), but globbing (expanding the * to any files matching the pattern).

The explanation of <files> mentions this:
   Files to remove. Fileglobs (e.g.  *.c) can be given to remove all
   matching files.

This indicates that git itself (not your shell alone) does file globbing.

I think the confusing part is that most people have no clear idea of the separation between what the shell sees and interprets, and what the program actually gets.

When you execute:
    $ git rm Makefile\*
What git actually sees is this:
    Makefile*

The shell intepreted the \* to mean just '*' and not interpret it itself, and provide that to the executed program. Git, in its turn, would start matching any file to that pattern to see which files matches.

If you would execute:
    $ git rm 'Makefile\*'
Git would see:
    Makefile\*

Which does the thing you intended. So you have to deal with 2 levels of programs interpreting the arguments, not just one.

Whether '*.c' should match just all .c files in the current dir, or all
files ending with .c depends on whether the path seperator is matched by
* or not and is a separate discussion.
GITGLOSSARY(7) under pathspec mentions this:
    glob    Git treats the pattern as a shell glob suitable for consumption
            by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the
            pattern will not match a / in the pathname.

So that seems to indicate '*.c' should only match .c files in the current dir. I'm not sure why that's not the case.

I hope this clears up what's happening a bit, and perhaps can lead to improvements to the documentation so that it's not so surprising.

Kind regards, Kevin.
Previous: Robert P. J. DayNext: Robert P. J. Day
Message 14 of 29 in “"git rm" seems to do recursive removal even without "-r"”
  1. Robert P. J. DayOct 7, 2017
  2. Todd ZullingerOct 7, 2017
  3. Robert P. J. DayOct 7, 2017
  4. Jeff KingOct 7, 2017
  5. Robert P. J. DayOct 7, 2017
  6. Jeff KingOct 7, 2017
  7. Robert P. J. DayOct 7, 2017
  8. Theodore Ts'oOct 7, 2017
  9. Robert P. J. DayOct 7, 2017
  10. Paul SmithOct 7, 2017
  11. Robert P. J. DayOct 7, 2017
  12. Junio C HamanoOct 8, 2017
  13. Robert P. J. DayOct 8, 2017
  14. Kevin DaudtOct 8, 2017
  15. Robert P. J. DayOct 8, 2017
  16. Martin ÅgrenOct 8, 2017
  17. René ScharfeOct 8, 2017
  18. Robert P. J. DayOct 8, 2017
  19. Heiko VoigtOct 10, 2017
  20. Robert P. J. DayOct 11, 2017
  21. Paul SmithOct 8, 2017
  22. Theodore Ts'oOct 8, 2017
  23. Robert P. J. DayOct 8, 2017
  24. Theodore Ts'oOct 8, 2017
  25. Jeff KingOct 9, 2017
  26. Robert P. J. DayOct 10, 2017
  27. Junio C HamanoOct 10, 2017
  28. Paul SmithOct 10, 2017
  29. Robert P. J. DayOct 10, 2017

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.