{"thread":{"id":"46932","subject":"\"git rm\" seems to do recursive removal even without \"-r\"","startedAt":"2017-10-07T18:39:57Z","lastAt":"2017-10-11T08:32:03Z","messageCount":29,"participants":["Robert P. J. Day","Todd Zullinger","Jeff King","Theodore Ts'o","Paul Smith","Junio C Hamano","Kevin Daudt","Martin Ågren","René Scharfe","Heiko Voigt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"329963","messageId":"alpine.LFD.2.21.1710071436140.14843@localhost.localdomain","threadId":"46932","inReplyTo":null,"subject":"\"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-07T18:39:50Z","receivedAt":"2017-10-07T18:39:57Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"\n  was just testing variations of \"git rm\", and man page claims:\n\n  -r\n     Allow recursive removal when a leading directory name is given.\n\ni tested this on the \"pro git\" book repo, which contains a top-level\n\"book/\" directory, and quite a number of \"*.asc\" files in various\nsubdirectories one or more levels down. i ran:\n\n  $ git rm book/\\*.asc\n\nand it certainly seemed to delete *all* \"*.asc\" files no matter where\nthey were under book/, even without the \"-r\" option.\n\n  am i misunderstanding something?\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"329964","messageId":"20171007190402.GH3382@zaya.teonanacatl.net","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710071436140.14843@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Todd Zullinger","fromEmail":"tmz@pobox.com","sentAt":"2017-10-07T19:04:02Z","receivedAt":"2017-10-07T19:04:12Z","isPatch":false,"sender":{"key":"tmz@pobox.com","avatar":"https://avatars.githubusercontent.com/u/806319?v=4"},"body":"Robert P. J. Day wrote:\n>\n>  was just testing variations of \"git rm\", and man page claims:\n>\n>  -r \n>     Allow recursive removal when a leading directory name is given.\n>\n> i tested this on the \"pro git\" book repo, which contains a top-level \n> \"book/\" directory, and quite a number of \"*.asc\" files in various \n> subdirectories one or more levels down. i ran:\n>\n>  $ git rm book/\\*.asc\n>\n> and it certainly seemed to delete *all* \"*.asc\" files no matter where \n> they were under book/, even without the \"-r\" option.\n>\n>  am i misunderstanding something?\n\nBy shell-escaping the *, you're letting git perform the file glob.  \nThe DISCUSSION section of git-rm(1) says \"File globbing matches across \ndirectory boundaries.\"\n\n# With bash performing file globbing\n$ git rm -n Documentation/*.txt | wc -l\n199\n\n# With git performing file globbing\n$ git rm -n Documentation/\\*.txt | wc -l\n578\n\n-- \nTodd\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhenever you find yourself on the side of the majority, it is time to\npause and reflect.\n    -- Mark Twain\n\n"},{"id":"329965","messageId":"alpine.LFD.2.21.1710071506210.15271@localhost.localdomain","threadId":"46932","inReplyTo":"20171007190402.GH3382@zaya.teonanacatl.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-07T19:12:01Z","receivedAt":"2017-10-07T19:12:17Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sat, 7 Oct 2017, Todd Zullinger wrote:\n\n> Robert P. J. Day wrote:\n> >\n> >  was just testing variations of \"git rm\", and man page claims:\n> >\n> >  -r     Allow recursive removal when a leading directory name is given.\n> >\n> > i tested this on the \"pro git\" book repo, which contains a top-level \"book/\"\n> > directory, and quite a number of \"*.asc\" files in various subdirectories one\n> > or more levels down. i ran:\n> >\n> >  $ git rm book/\\*.asc\n> >\n> > and it certainly seemed to delete *all* \"*.asc\" files no matter where they\n> > were under book/, even without the \"-r\" option.\n> >\n> >  am i misunderstanding something?\n>\n> By shell-escaping the *, you're letting git perform the file glob.  The\n> DISCUSSION section of git-rm(1) says \"File globbing matches across directory\n> boundaries.\"\n>\n> # With bash performing file globbing\n> $ git rm -n Documentation/*.txt | wc -l\n> 199\n>\n> # With git performing file globbing\n> $ git rm -n Documentation/\\*.txt | wc -l\n> 578\n\n  ok, in that case, can you give me an example where \"-r\" makes a\ndifference, given that the man page refers to \"a leading directory\nname being given\"? let's use as an example the linux kernel source,\nwhere there are a *ton* of files named \"Makefile\" under the drivers/\ndirectory.\n\n  should there be a difference between:\n\n  $ git rm drivers/Makefile\n  $ git rm -r drivers/Makefile\n\nclearly, i have a \"leading directory name\" in both examples above ...\nwhat should happen differently?\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"329967","messageId":"20171007192902.ma4s47hn6edwldx5@sigill.intra.peff.net","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710071506210.15271@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-10-07T19:29:02Z","receivedAt":"2017-10-07T19:30:41Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Oct 07, 2017 at 03:12:01PM -0400, Robert P. J. Day wrote:\n\n>   ok, in that case, can you give me an example where \"-r\" makes a\n> difference, given that the man page refers to \"a leading directory\n> name being given\"? let's use as an example the linux kernel source,\n> where there are a *ton* of files named \"Makefile\" under the drivers/\n> directory.\n> \n>   should there be a difference between:\n> \n>   $ git rm drivers/Makefile\n>   $ git rm -r drivers/Makefile\n> \n> clearly, i have a \"leading directory name\" in both examples above ...\n> what should happen differently?\n\nNothing, because there is nothing to recurse in the pathspecs you've\ngiven.\n\nTry:\n\n  $ git rm drivers\n  fatal: not removing 'drivers' recursively without -r\n\nversus\n\n  $ git rm -r drivers\n  [...removes everything under drivers/...]\n\n-Peff\n"},{"id":"329968","messageId":"alpine.LFD.2.21.1710071531090.15738@localhost.localdomain","threadId":"46932","inReplyTo":"20171007192902.ma4s47hn6edwldx5@sigill.intra.peff.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-07T19:32:24Z","receivedAt":"2017-10-07T19:32:31Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sat, 7 Oct 2017, Jeff King wrote:\n\n> On Sat, Oct 07, 2017 at 03:12:01PM -0400, Robert P. J. Day wrote:\n>\n> >   ok, in that case, can you give me an example where \"-r\" makes a\n> > difference, given that the man page refers to \"a leading directory\n> > name being given\"? let's use as an example the linux kernel source,\n> > where there are a *ton* of files named \"Makefile\" under the drivers/\n> > directory.\n> >\n> >   should there be a difference between:\n> >\n> >   $ git rm drivers/Makefile\n> >   $ git rm -r drivers/Makefile\n> >\n> > clearly, i have a \"leading directory name\" in both examples above ...\n> > what should happen differently?\n>\n> Nothing, because there is nothing to recurse in the pathspecs you've\n> given.\n>\n> Try:\n>\n>   $ git rm drivers\n>   fatal: not removing 'drivers' recursively without -r\n>\n> versus\n>\n>   $ git rm -r drivers\n>   [...removes everything under drivers/...]\n\n  that is not what the man page is saying ... it refers to a \"leading\"\ndirectory name, not simply a directory name. if it should say simply\n\"when a directory name is given\", then it should be changed to say\nthat.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"329970","messageId":"20171007193805.a2mwzkweonb6ymdk@sigill.intra.peff.net","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710071531090.15738@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-10-07T19:38:05Z","receivedAt":"2017-10-07T19:38:11Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Oct 07, 2017 at 03:32:24PM -0400, Robert P. J. Day wrote:\n\n> > Nothing, because there is nothing to recurse in the pathspecs you've\n> > given.\n> >\n> > Try:\n> >\n> >   $ git rm drivers\n> >   fatal: not removing 'drivers' recursively without -r\n> >\n> > versus\n> >\n> >   $ git rm -r drivers\n> >   [...removes everything under drivers/...]\n> \n>   that is not what the man page is saying ... it refers to a \"leading\"\n> directory name, not simply a directory name. if it should say simply\n> \"when a directory name is given\", then it should be changed to say\n> that.\n\nIt's the leading directory of the files that will be removed.\n\nAn earlier part of the manpage (under <file>) also says:\n\n  A leading directory name (e.g. dir to remove dir/file1 and dir/file2)\n  can be given to remove all files in the directory, and recursively all\n  sub-directories, but this requires the -r option to be explicitly\n  given.\n\nwhich perhaps makes it more clear. Later in \"-r\", we say:\n\n   -r\n           Allow recursive removal when a leading directory name is given.\n\nwhich I guess is the part you're reading.  I think it would be equally\ncorrect to say \"leading directory\" or just \"directory\" there.\n\nThough really, you could give many such directory names, or even match\nthem with a glob. So a more accurate description might be something\nlike:\n\n  -r\n\tRecursively remove the contents of any directories that match\n\t`<file>`.\n\nor something.\n\n-Peff\n"},{"id":"329971","messageId":"alpine.LFD.2.21.1710071541430.15964@localhost.localdomain","threadId":"46932","inReplyTo":"20171007193805.a2mwzkweonb6ymdk@sigill.intra.peff.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-07T19:43:43Z","receivedAt":"2017-10-07T19:43:51Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sat, 7 Oct 2017, Jeff King wrote:\n\n> On Sat, Oct 07, 2017 at 03:32:24PM -0400, Robert P. J. Day wrote:\n>\n> > > Nothing, because there is nothing to recurse in the pathspecs you've\n> > > given.\n> > >\n> > > Try:\n> > >\n> > >   $ git rm drivers\n> > >   fatal: not removing 'drivers' recursively without -r\n> > >\n> > > versus\n> > >\n> > >   $ git rm -r drivers\n> > >   [...removes everything under drivers/...]\n> >\n> >   that is not what the man page is saying ... it refers to a \"leading\"\n> > directory name, not simply a directory name. if it should say simply\n> > \"when a directory name is given\", then it should be changed to say\n> > that.\n>\n> It's the leading directory of the files that will be removed.\n>\n> An earlier part of the manpage (under <file>) also says:\n>\n>   A leading directory name (e.g. dir to remove dir/file1 and dir/file2)\n>   can be given to remove all files in the directory, and recursively all\n>   sub-directories, but this requires the -r option to be explicitly\n>   given.\n>\n> which perhaps makes it more clear. Later in \"-r\", we say:\n>\n>    -r\n>            Allow recursive removal when a leading directory name is given.\n>\n> which I guess is the part you're reading.  I think it would be equally\n> correct to say \"leading directory\" or just \"directory\" there.\n>\n> Though really, you could give many such directory names, or even match\n> them with a glob. So a more accurate description might be something\n> like:\n>\n>   -r\n> \tRecursively remove the contents of any directories that match\n> \t`<file>`.\n>\n> or something.\n\n  it's been a long week, so take this in the spirit in which it is\nintended ... i think the \"git rm\" command and its man page should be\nprinted out, run through a paper shredder, then set on fire. i can't\nremember the last time i saw such a thoroughly badly-designed,\nbadly-documented and non-intuitive utility.\n\n  i'm going to go watch football now and try to forget this horror.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"329972","messageId":"20171007210500.s3s5q53qihtf2s32@thunk.org","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710071541430.15964@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Theodore Ts'o","fromEmail":"tytso@mit.edu","sentAt":"2017-10-07T21:05:00Z","receivedAt":"2017-10-07T21:05:10Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sat, Oct 07, 2017 at 03:43:43PM -0400, Robert P. J. Day wrote:\n> >   -r\n> > \tRecursively remove the contents of any directories that match\n> > \t`<file>`.\n> >\n> > or something.\n> \n>   it's been a long week, so take this in the spirit in which it is\n> intended ... i think the \"git rm\" command and its man page should be\n> printed out, run through a paper shredder, then set on fire. i can't\n> remember the last time i saw such a thoroughly badly-designed,\n> badly-documented and non-intuitive utility.\n> \n>   i'm going to go watch football now and try to forget this horror.\n\nIt sounds like the real issue here is that you are interpreting\n\"recursively\" to mean \"globbing\".  Your original complaint seemed to\nbe a surprise that \"git rm book/\\*.asc\" would delete all of the files\nin the directory \"book\" that ended in .asc, even without the -r flag.\n\nThat's because the operation of matching *.asc is considered\n\"globbing\".  Now if there were directories whose name ended in .asc,\nthen they would only be deleted if the -r flag is given.  Deleting\ndirectories and their contents is what is considered \"recursive\nremoval\".\n\nThat's not particularly surprising to me as a long-time Unix/Linux\nuser/developer, since that's how things work in Unix/Linux:\n\n% touch 1.d 2.d ; mkdir 3.d 4.d\n% /bin/ls\n1.d  2.d  3.d  4.d\n% rm -r *.d\n% touch 1.d 2.d ; mkdir 3.d 4.d\n% rm *.d\nrm: cannot remove '3.d': Is a directory\nrm: cannot remove '4.d': Is a directory\n\nI'm going to guess that you don't come from a Unix background?\n\n        \t     \t   \t    - Ted\n"},{"id":"329974","messageId":"alpine.LFD.2.21.1710071740260.16732@localhost.localdomain","threadId":"46932","inReplyTo":"20171007210500.s3s5q53qihtf2s32@thunk.org","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-07T21:40:56Z","receivedAt":"2017-10-07T21:41:04Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sat, 7 Oct 2017, Theodore Ts'o wrote:\n\n> On Sat, Oct 07, 2017 at 03:43:43PM -0400, Robert P. J. Day wrote:\n> > >   -r\n> > > \tRecursively remove the contents of any directories that match\n> > > \t`<file>`.\n> > >\n> > > or something.\n> >\n> >   it's been a long week, so take this in the spirit in which it is\n> > intended ... i think the \"git rm\" command and its man page should be\n> > printed out, run through a paper shredder, then set on fire. i can't\n> > remember the last time i saw such a thoroughly badly-designed,\n> > badly-documented and non-intuitive utility.\n> >\n> >   i'm going to go watch football now and try to forget this horror.\n>\n> It sounds like the real issue here is that you are interpreting\n> \"recursively\" to mean \"globbing\".  Your original complaint seemed to\n> be a surprise that \"git rm book/\\*.asc\" would delete all of the files\n> in the directory \"book\" that ended in .asc, even without the -r flag.\n>\n> That's because the operation of matching *.asc is considered\n> \"globbing\".  Now if there were directories whose name ended in .asc,\n> then they would only be deleted if the -r flag is given.  Deleting\n> directories and their contents is what is considered \"recursive\n> removal\".\n>\n> That's not particularly surprising to me as a long-time Unix/Linux\n> user/developer, since that's how things work in Unix/Linux:\n>\n> % touch 1.d 2.d ; mkdir 3.d 4.d\n> % /bin/ls\n> 1.d  2.d  3.d  4.d\n> % rm -r *.d\n> % touch 1.d 2.d ; mkdir 3.d 4.d\n> % rm *.d\n> rm: cannot remove '3.d': Is a directory\n> rm: cannot remove '4.d': Is a directory\n>\n> I'm going to guess that you don't come from a Unix background?\n\n  yeah, that must be it, i'm a newbie at linux. let's go with that.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"329975","messageId":"alpine.LFD.2.21.1710071749240.16818@localhost.localdomain","threadId":"46932","inReplyTo":"1507412674.8322.4.camel@mad-scientist.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-07T21:55:48Z","receivedAt":"2017-10-07T21:55:55Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sat, 7 Oct 2017, Paul Smith wrote:\n\n> On Sat, 2017-10-07 at 15:43 -0400, Robert P. J. Day wrote:\n> >   it's been a long week, so take this in the spirit in which it is\n> > intended ... i think the \"git rm\" command and its man page should be\n> > printed out, run through a paper shredder, then set on fire. i can't\n> > remember the last time i saw such a thoroughly badly-designed,\n> > badly-documented and non-intuitive utility.\n>\n> \"git rm\" works the same way that the UNIX rm command has worked, for\n> 40+ years now.  Very simple, very well designed, and very intuitive\n> (IMO).\n>\n> The major difference is the ability to handle globbing patterns,\n> which UNIX rm doesn't do.  Maybe the way this is implemented is a\n> little confusing, although I just read the man page and it seemed\n> pretty clear to me.\n\n  um, wrong.\n\n> If you don't use glob patterns (or more specifically if you let the\n> shell handle glob patterns, which is how I always do it) then there\n> is really nothing bizarre about \"git rm\".  Maybe you could be more\n> precise in your criticism.\n\n  ok, fine, let me explain why this command is a nightmarish\nmonstrosity. as i now understand, if i use an escaped wildcard\npattern, \"git rm\" will *automatically* (with no further guidance from\nme, and no warning), operate recursively. so if, in the kernel source\ntree, i ran:\n\n  $ git rm \\*.c\n\ni would end up removing *all* 25,569 \"*.c\" files in the kernel source\nrepository.\n\n  however, let's say i wanted to remove, recursively, all files with a\n*precise* (non-globbed) name, such as \"Makefile\". so i, naively, run:\n\n  $ git rm Makefile\n\nguess what ... the lack of globbing means i remove only the single\nMakefile at the top of the working directory.\n\n  if that isn't an example of ridiculous, non-intuitive behaviour, i\ndon't know what is.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"329976","messageId":"1507412674.8322.4.camel@mad-scientist.net","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710071541430.15964@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Paul Smith","fromEmail":"paul@mad-scientist.net","sentAt":"2017-10-07T21:44:34Z","receivedAt":"2017-10-07T22:07:31Z","isPatch":false,"sender":{"key":"paul@mad-scientist.net","avatar":"https://avatars.githubusercontent.com/u/109636?v=4"},"body":"On Sat, 2017-10-07 at 15:43 -0400, Robert P. J. Day wrote:\n>   it's been a long week, so take this in the spirit in which it is\n> intended ... i think the \"git rm\" command and its man page should be\n> printed out, run through a paper shredder, then set on fire. i can't\n> remember the last time i saw such a thoroughly badly-designed,\n> badly-documented and non-intuitive utility.\n\n\"git rm\" works the same way that the UNIX rm command has worked, for 40+\nyears now.  Very simple, very well designed, and very intuitive (IMO).\n\nThe major difference is the ability to handle globbing patterns, which\nUNIX rm doesn't do.  Maybe the way this is implemented is a little\nconfusing, although I just read the man page and it seemed pretty clear\nto me.\n\nIf you don't use glob patterns (or more specifically if you let the\nshell handle glob patterns, which is how I always do it) then there is\nreally nothing bizarre about \"git rm\".  Maybe you could be more precise\nin your criticism.\n"},{"id":"329978","messageId":"xmqqy3oms22q.fsf@gitster.mtv.corp.google.com","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710071749240.16818@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-08T04:20:13Z","receivedAt":"2017-10-08T04:20:37Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Robert P. J. Day\" <rpjday@crashcourse.ca> writes:\n\n> ... so if, in the kernel source\n> tree, i ran:\n>\n>   $ git rm \\*.c\n>\n> i would end up removing *all* 25,569 \"*.c\" files in the kernel source\n> repository.\n\nYes, as that is exactly what the command line asks Git to do.\n\nIf you said\n\n    $ git rm *.c\n\nthen the shell expands the glob and all Git sees is that you want to\nremove a.c b.c d.c ...; if you said \"git rm -r *.c\", unless b.c is\nnot a directory, these and only these files are removed.\n\n>   however, let's say i wanted to remove, recursively, all files with a\n> *precise* (non-globbed) name, such as \"Makefile\". so i, naively, run:\n>\n>   $ git rm Makefile\n>\n> guess what ... the lack of globbing means i remove only the single\n> Makefile at the top of the working directory.\n\nAgain, that is exactly what you asked Git to do.\n\n    $ git rm $(find . -name Makefile -print)\n\nwould of course one way to remove all Makefiles.  If you let POSIX\nshell glob, i.e.\n\n    $ git rm */Makefile\n\nthe asterisk would not expand nothing but a single level, so it may\nremove fs/Makefile, but not fs/ext4/Makefile (some shells allow\n\"wildmatch\" expansion so \"git rm **/Makefile\" may catch the latter\nwith such a shell).\n\nBy letting Git see the glob, i.e.\n\n    $ git rm Makefile \\*/Makefile\n\nyou would let Git to go over the paths it knows/cares about to find\nones that match the pathspec pattern and remove them (but not\nrecursively, even if you had a directory whose name is Makefile; for\nthat, you would use \"-r\").\n\nEarlier some people mentioned \"Unix newbie\" in the thread, but I do\nnot think this is about Unix.  In general, Unix tools do not perform\ngrobbing themselves but expect the user to tell the shell to do so\nbefore the tools see the arguments.  In that sense, I do think the\ncombination of \"-r\" and globbing pathspec may produce a result that\nlooks confusing at first glance.  \n\n\"git rm [-r] <pathspec>...\"\n\n (1) walks the paths it knows/cares about, rejecting ones that do\n     not match the <pathspec>;\n\n (2) decides to remove the ones that match; and\n\n (3) when it is asked to recursively remove, the ones that are\n     directories are removed together with its contents.  If it was\n     not asked to go recursive, it refuses to act on directories.\n\nwhere (1) and (2) are not something the tool needs to worry\nabout---what is given from the command line is the only set of paths\nthat the tool is asked to operate on.  These two steps are quite\nunlike regular Unix tools.\n\nOnce you decide to give the tool the flexibility that come from\ntaking pathspec, however, steps (1) and (2) do have to happen inside\nthe tool.  And great power takes some understanding of the tool on\nthe part of the user to exercise.  I suspect that the occasion you\nwould need to use \"-r\" with \"git rm\" is a lot less frequent than a\nplain \"rm\".\n\nOf course, there is no confusion if you do not quote wildcards.  By\nquoting wildcards and not letting the shell to expand them, the user\ntells Git that the fact _it_ sees the asterisk is because the user\nis doing so on purpose---so that Git would find paths that match the\npattern.\n\nHope this clarifies and helps.\n"},{"id":"329982","messageId":"alpine.LFD.2.21.1710080502050.19600@localhost.localdomain","threadId":"46932","inReplyTo":"xmqqy3oms22q.fsf@gitster.mtv.corp.google.com","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-08T09:07:12Z","receivedAt":"2017-10-08T09:07:21Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sun, 8 Oct 2017, Junio C Hamano wrote:\n\n> \"Robert P. J. Day\" <rpjday@crashcourse.ca> writes:\n>\n> > ... so if, in the kernel source\n> > tree, i ran:\n> >\n> >   $ git rm \\*.c\n> >\n> > i would end up removing *all* 25,569 \"*.c\" files in the kernel source\n> > repository.\n>\n> Yes, as that is exactly what the command line asks Git to do.\n\n  so if i wanted git to remove, say, all files named \"Makefile*\" from\neverywhere in the linux kernel source tree, the (dry run) command\nwould be:\n\n  $ git rm -n Makefile\\*\n\nis that it? let's try that:\n\n  $ git rm -n Makefile\\*\n  rm 'Makefile'\n  $\n\noops.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n\n\n"},{"id":"329985","messageId":"20171008113732.GA8251@alpha.vpn.ikke.info","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710080502050.19600@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Kevin Daudt","fromEmail":"me@ikke.info","sentAt":"2017-10-08T11:37:32Z","receivedAt":"2017-10-08T11:37:39Z","isPatch":false,"sender":{"key":"me@ikke.info","avatar":"https://avatars.githubusercontent.com/u/135698?v=4"},"body":"On Sun, Oct 08, 2017 at 05:07:12AM -0400, Robert P. J. Day wrote:\n> On Sun, 8 Oct 2017, Junio C Hamano wrote:\n> \n> > \"Robert P. J. Day\" <rpjday@crashcourse.ca> writes:\n> >\n> > > ... so if, in the kernel source\n> > > tree, i ran:\n> > >\n> > >   $ git rm \\*.c\n> > >\n> > > i would end up removing *all* 25,569 \"*.c\" files in the kernel source\n> > > repository.\n> >\n> > Yes, as that is exactly what the command line asks Git to do.\n> \n>   so if i wanted git to remove, say, all files named \"Makefile*\" from\n> everywhere in the linux kernel source tree, the (dry run) command\n> would be:\n> \n>   $ git rm -n Makefile\\*\n> \n> is that it? let's try that:\n> \n>   $ git rm -n Makefile\\*\n>   rm 'Makefile'\n>   $\n> \n> oops.\n> \n> rday\n> \n\nSo your question is not su much  about the recursive option (delete\nmentioned directories, including their contents), but globbing\n(expanding the * to any files matching the pattern).\n\nThe explanation of <files> mentions this:\n\n   Files to remove. Fileglobs (e.g.  *.c) can be given to remove all\n   matching files.\n\nThis indicates that git itself (not your shell alone) does file\nglobbing.\n\nI think the confusing part is that most people have no clear idea of the\nseparation between what the shell sees and interprets, and what the\nprogram actually gets.\n\nWhen you execute:\n\n    $ git rm Makefile\\*\n\nWhat git actually sees is this:\n\n    Makefile*\n\nThe shell intepreted the \\* to mean just '*' and not interpret it\nitself, and provide that to the executed program. Git, in its turn,\nwould start matching any file to that pattern to see which files\nmatches.\n\n\nIf you would execute:\n\n    $ git rm 'Makefile\\*'\n\nGit would see:\n\n    Makefile\\*\n\nWhich does the thing you intended. So you have to deal with 2 levels of\nprograms interpreting the arguments, not just one.\n\nWhether '*.c' should match just all .c files in the current dir, or all\nfiles ending with .c depends on whether the path seperator is matched by\n* or not and is a separate discussion.\n\nGITGLOSSARY(7) under pathspec mentions this:\n\n    glob    Git treats the pattern as a shell glob suitable for consumption\n            by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the\n            pattern will not match a / in the pathname.\n\nSo that seems to indicate '*.c' should only match .c files in the\ncurrent dir. I'm not sure why that's not the case.\n\nI hope this clears up what's happening a bit, and perhaps can lead to\nimprovements to the documentation so that it's not so surprising.\n\nKind regards, Kevin.\n"},{"id":"329986","messageId":"alpine.LFD.2.21.1710080736530.21897@localhost.localdomain","threadId":"46932","inReplyTo":"xmqqy3oms22q.fsf@gitster.mtv.corp.google.com","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-08T11:56:20Z","receivedAt":"2017-10-08T11:56:27Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sun, 8 Oct 2017, Junio C Hamano wrote:\n\n> \"Robert P. J. Day\" <rpjday@crashcourse.ca> writes:\n>\n> > ... so if, in the kernel source\n> > tree, i ran:\n> >\n> >   $ git rm \\*.c\n> >\n> > i would end up removing *all* 25,569 \"*.c\" files in the kernel\n> > source repository.\n>\n> Yes, as that is exactly what the command line asks Git to do.\n\n  ok, i truly want to understand this, so let me dig through this\ncarefully. i can now see (from the man page and the recent\nexplanations) that \"git rm\" will accept *escaped* fileglobs to remove\nand that, further, \"File globbing matches across directory\nboundaries.\" which is why, in the linux kernel source tree, if i run\none of:\n\n  $ git rm \\*.c\n  $ git rm '*.c'\n\nthe \"git rm\" command will internally process the fileglob and apply it\nacross directory boundaries. and that's why, when i try a dry run, i\ncan see the effect it would have on the kernel source:\n\n  $ git rm -n '*.c' | wc -l\n  25569\n  $\n\n> If you said\n>\n>     $ git rm *.c\n>\n> then the shell expands the glob and all Git sees is that you want to\n> remove a.c b.c d.c ...; if you said \"git rm -r *.c\", unless b.c is\n> not a directory, these and only these files are removed.\n\n  right, that's just regular shell fileglob processing, no surprise\nthere. (let's stick to just file removal for now.)\n\n> >   however, let's say i wanted to remove, recursively, all files with a\n> > *precise* (non-globbed) name, such as \"Makefile\". so i, naively, run:\n> >\n> >   $ git rm Makefile\n> >\n> > guess what ... the lack of globbing means i remove only the single\n> > Makefile at the top of the working directory.\n>\n> Again, that is exactly what you asked Git to do.\n\n  yes, now i get it -- a lack of fileglob arguments disallows\ntraversing directory boundaries, so one gets the \"normal\" behaviour.\n\n>     $ git rm $(find . -name Makefile -print)\n>\n> would of course one way to remove all Makefiles.  If you let POSIX\n> shell glob, i.e.\n>\n>     $ git rm */Makefile\n>\n> the asterisk would not expand nothing but a single level, so it may\n> remove fs/Makefile, but not fs/ext4/Makefile (some shells allow\n> \"wildmatch\" expansion so \"git rm **/Makefile\" may catch the latter\n> with such a shell).\n\n  sure, all regular shell fileglob processing.\n\n> By letting Git see the glob, i.e.\n>\n>     $ git rm Makefile \\*/Makefile\n>\n> you would let Git to go over the paths it knows/cares about to find\n> ones that match the pathspec pattern and remove them (but not\n> recursively, even if you had a directory whose name is Makefile; for\n> that, you would use \"-r\").\n\n  right ... i can now see that '*/Makefile' would pick up all\nMakefiles *below* the current directory, so you need that initial\nreference to 'Makefile' to catch the top one. this just seems ...\nawkward.\n\n  but as i asked in my earlier post, if i wanted to remove *all* files\nwith names of \"Makefile*\", why can't i use:\n\n  $ git rm 'Makefile*'\n\njust as i used:\n\n  $ git rm '*.c'\n\nare those not both acceptable fileglobs? why does the former clearly\nonly match the top-level Makefile, and refuse to cross directory\nboundaries?\n\n  $ git rm -n 'Makefile*'\n  rm 'Makefile'\n  $\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"329988","messageId":"CAN0heSqvz1ak8BvM=i9FGPm=_4Fi7WLhZhPMN37GN-VngewkuA@mail.gmail.com","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710080736530.21897@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2017-10-08T12:23:24Z","receivedAt":"2017-10-08T12:23:30Z","isPatch":false,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On 8 October 2017 at 13:56, Robert P. J. Day <rpjday@crashcourse.ca> wrote:\n>   but as i asked in my earlier post, if i wanted to remove *all* files\n> with names of \"Makefile*\", why can't i use:\n>\n>   $ git rm 'Makefile*'\n>\n> just as i used:\n>\n>   $ git rm '*.c'\n>\n> are those not both acceptable fileglobs? why does the former clearly\n> only match the top-level Makefile, and refuse to cross directory\n> boundaries?\n>\n>   $ git rm -n 'Makefile*'\n>   rm 'Makefile'\n>   $\n\nHmmm. The manpage says the following:\n\n       git rm -f git-*.sh\n           Because this example lets the shell expand the asterisk (i.e.\n           you are listing the files explicitly), it does not remove\n           subdir/git-foo.sh.\n\nThis implies that `git rm \"git-*.sh\"` should remove subdir/git-foo.sh.\nBut it doesn't, at least not in my testing. It seems that the globbing\nonly kicks in when the \"*\" comes first, as you've noted.\n"},{"id":"329989","messageId":"05775b3d-2e88-9ceb-e8d2-8ff2373cfdb5@web.de","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710080736530.21897@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2017-10-08T12:39:05Z","receivedAt":"2017-10-08T12:39:18Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"[My SMTP server still refuses to accept emails to rpjday@crashcourse.ca\n and reports \"mailbox unavailable\" and \"invalid DNS MX or A/AAAA resource\n record.\"  So just replying to the list.]\n\nAm 08.10.2017 um 13:56 schrieb Robert P. J. Day:\n>    but as i asked in my earlier post, if i wanted to remove *all* files\n> with names of \"Makefile*\", why can't i use:\n> \n>    $ git rm 'Makefile*'\n> \n> just as i used:\n> \n>    $ git rm '*.c'\n> \n> are those not both acceptable fileglobs? why does the former clearly\n> only match the top-level Makefile, and refuse to cross directory\n> boundaries?\n> \n>    $ git rm -n 'Makefile*'\n>    rm 'Makefile'\n>    $\n\nTry:\n\n\t$ git rm -n '*Makefile'\n\nThe whole path is considered.  The asterisk there matches any\ndirectory part -- but also any file name prefix.  Check the entry for\n\"pathspec\" in gitglossary(7) for more details.\n\nRené\n"},{"id":"329990","messageId":"alpine.LFD.2.21.1710080843320.22844@localhost.localdomain","threadId":"46932","inReplyTo":"05775b3d-2e88-9ceb-e8d2-8ff2373cfdb5@web.de","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-08T12:45:15Z","receivedAt":"2017-10-08T12:45:24Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sun, 8 Oct 2017, René Scharfe wrote:\n\n> [My SMTP server still refuses to accept emails to rpjday@crashcourse.ca\n>  and reports \"mailbox unavailable\" and \"invalid DNS MX or A/AAAA resource\n>  record.\"  So just replying to the list.]\n>\n> Am 08.10.2017 um 13:56 schrieb Robert P. J. Day:\n> >    but as i asked in my earlier post, if i wanted to remove *all* files\n> > with names of \"Makefile*\", why can't i use:\n> >\n> >    $ git rm 'Makefile*'\n> >\n> > just as i used:\n> >\n> >    $ git rm '*.c'\n> >\n> > are those not both acceptable fileglobs? why does the former clearly\n> > only match the top-level Makefile, and refuse to cross directory\n> > boundaries?\n> >\n> >    $ git rm -n 'Makefile*'\n> >    rm 'Makefile'\n> >    $\n>\n> Try:\n>\n> \t$ git rm -n '*Makefile'\n>\n> The whole path is considered.  The asterisk there matches any\n> directory part -- but also any file name prefix.  Check the entry\n> for \"pathspec\" in gitglossary(7) for more details.\n\n  but \"*Makefile\" is not the wildcard pattern i'm interested in.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================"},{"id":"329992","messageId":"1507473160.8322.12.camel@mad-scientist.net","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710071749240.16818@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Paul Smith","fromEmail":"paul@mad-scientist.net","sentAt":"2017-10-08T14:32:40Z","receivedAt":"2017-10-08T14:32:49Z","isPatch":false,"sender":{"key":"paul@mad-scientist.net","avatar":"https://avatars.githubusercontent.com/u/109636?v=4"},"body":"On Sat, 2017-10-07 at 17:55 -0400, Robert P. J. Day wrote:\n> On Sat, 7 Oct 2017, Paul Smith wrote:\n> > On Sat, 2017-10-07 at 15:43 -0400, Robert P. J. Day wrote:\n> > > it's been a long week, so take this in the spirit in which it is\n> > > intended ... i think the \"git rm\" command and its man page should be\n> > > printed out, run through a paper shredder, then set on fire. i can't\n> > > remember the last time i saw such a thoroughly badly-designed,\n> > > badly-documented and non-intuitive utility.\n> >\n> > \"git rm\" works the same way that the UNIX rm command has worked, for\n> > 40+ years now.  Very simple, very well designed, and very intuitive\n> > (IMO).\n> >\n> > The major difference is the ability to handle globbing patterns,\n> > which UNIX rm doesn't do.  Maybe the way this is implemented is a\n> > little confusing, although I just read the man page and it seemed\n> > pretty clear to me.\n> \n>   um, wrong.\n\nI don't know what part of my comment here you consider \"wrong\".  I've\nre-read it and I believe everything I said is correct.\n\n> > If you don't use glob patterns (or more specifically if you let the\n> > shell handle glob patterns, which is how I always do it) then there\n> > is really nothing bizarre about \"git rm\".  Maybe you could be more\n> > precise in your criticism.\n> \n> ok, fine, let me explain why this command is a nightmarish\n> monstrosity. as i now understand, if i use an escaped wildcard\n> pattern, \"git rm\" will *automatically* (with no further guidance from\n> me, and no warning), operate recursively. so if, in the kernel source\n> tree, i ran:\n> \n>   $ git rm \\*.c\n\nYes, this is what I said: \"IF YOU DON'T USE GLOB PATTERNS (or more\nspecifically if you let the shell handle glob patterns ...) then there\nis nothing bizarre about \"git rm\"\" (emphasis added).\n\nIn this example you ARE sending glob patterns to Git, because you're\nescaping them from the shell.  Hence, you might consider the behavior\nbizarre, at least until you grok it fully.\n\nIf you want to avoid this, simply use normal shell globbing and don't\nask Git to do the globbing for you.  Then it behaves exactly as normal\nUNIX rm, including with the '-r' option, and is very simple.\n\n> so if i wanted git to remove, say, all files named \"Makefile*\" from\n> everywhere in the linux kernel source tree, the (dry run) command\n> would be:\n> \n>   $ git rm -n Makefile\\*\n> \n> is that it? let's try that:\n> \n>   $ git rm -n Makefile\\*\n>   rm 'Makefile'\n>   $\n> \n> oops.\n\nGlobbing in \"git rm\" matches on the FULL PATH, not just the file name. \nSo, if you have a list of Makefiles in your repository like:\n\n  Makefile\n  foo/Makefile\n  bar/Makefile\n\nThen 'Makefile*' only matches the first one, since 'Makefile*' doesn't\nmatch 'foo/Makefile' or 'bar/Makefile'.\n\nIf you you worry that '*Makefile' will match things you don't want to\nmatch, you'll have to use:\n\n  git rm -n Makefile '*/Makefile'\n\nPersonally I don't use Git's magical globbing capabilities, and use \"git\nrm\" as if it were UNIX rm.  So in your request above I'd use:\n\n   git rm $(find . -name Makefile)\n\nwhich I find simpler.\n"},{"id":"329995","messageId":"20171008184046.uj7gcutddli54ic3@thunk.org","threadId":"46932","inReplyTo":"1507473160.8322.12.camel@mad-scientist.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Theodore Ts'o","fromEmail":"tytso@mit.edu","sentAt":"2017-10-08T18:40:46Z","receivedAt":"2017-10-08T18:41:06Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sun, Oct 08, 2017 at 10:32:40AM -0400, Paul Smith wrote:\n> Personally I don't use Git's magical globbing capabilities, and use \"git\n> rm\" as if it were UNIX rm.  So in your request above I'd use:\n> \n>    git rm $(find . -name Makefile)\n> \n> which I find simpler.\n\nI have to agree that git's magical globbing capabilities\nare... strange.  (And apologies to Robert for my earlier post; I\ndidn't understand what he was complaining about.)  I don't use it\neither, although I tend to use:\n\n    find <find args> | xargs git rm\n\nmyself.\n\nOne thing which is interesting is that not only is the git's magical\nglobbing capabilities have somewhat unusual semantics, the how\nglobbing is done in .gitignore entries are completely different.\n\nShrug.  I put this in the same category as \"tabs are significant in\nMakefile's\", \"whitespace is significant in python\", and \"the many\nvaried different behaviours and uses of 'git reset'\".\n\nThey are all idiosyncrancies of semantics of various highly popular\ntools (which being highly popular, would make changing the details\nquite difficult due to backwards compatibility concerns, even if we\nwanted to change them).\n\n\t\t\t\t\t\t- Ted\n\n\n"},{"id":"330001","messageId":"alpine.LFD.2.21.1710081536180.28646@localhost.localdomain","threadId":"46932","inReplyTo":"20171008184046.uj7gcutddli54ic3@thunk.org","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-08T19:44:14Z","receivedAt":"2017-10-08T19:45:48Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Sun, 8 Oct 2017, Theodore Ts'o wrote:\n\n> On Sun, Oct 08, 2017 at 10:32:40AM -0400, Paul Smith wrote:\n> > Personally I don't use Git's magical globbing capabilities, and\n> > use \"git rm\" as if it were UNIX rm.  So in your request above I'd\n> > use:\n> >\n> >    git rm $(find . -name Makefile)\n> >\n> > which I find simpler.\n>\n> I have to agree that git's magical globbing capabilities are...\n> strange.  (And apologies to Robert for my earlier post; I didn't\n> understand what he was complaining about.)  I don't use it either,\n> although I tend to use:\n>\n>     find <find args> | xargs git rm\n>\n> myself.\n\n  that's what i would have normally used until i learned about git's\nmagical globbing capabilities, and i'm going to go back to using it,\nbecause git's magical globbing capabilities now scare me.\n\n> One thing which is interesting is that not only is the git's magical\n> globbing capabilities have somewhat unusual semantics, the how\n> globbing is done in .gitignore entries are completely different.\n\n  i know ... it would have made way more sense to try to be\nconsistent. oh, well, live and learn. at least now i'm aware of the\nweirdness.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"330002","messageId":"20171008204227.f6wgaobosa6yn62g@thunk.org","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710081536180.28646@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Theodore Ts'o","fromEmail":"tytso@mit.edu","sentAt":"2017-10-08T20:42:27Z","receivedAt":"2017-10-08T20:43:08Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sun, Oct 08, 2017 at 03:44:14PM -0400, Robert P. J. Day wrote:\n> >\n> >     find <find args> | xargs git rm\n> >\n> > myself.\n> \n>   that's what i would have normally used until i learned about git's\n> magical globbing capabilities, and i'm going to go back to using it,\n> because git's magical globbing capabilities now scare me.\n\nHmm, I wonder if the reason why git's magically globbing capabilities\neven exist at all is for those poor benighted souls on Windows, for\nwhich their shell (and associated utilities) doesn't have advanced\ntools like \"find\" and \"xargs\"....\n\n\t\t\t\t- Ted\n"},{"id":"330045","messageId":"20171009175225.qn6a3j2th3dxjjn2@sigill.intra.peff.net","threadId":"46932","inReplyTo":"20171008204227.f6wgaobosa6yn62g@thunk.org","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-10-09T17:52:26Z","receivedAt":"2017-10-09T17:52:35Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Oct 08, 2017 at 04:42:27PM -0400, Theodore Ts'o wrote:\n\n> On Sun, Oct 08, 2017 at 03:44:14PM -0400, Robert P. J. Day wrote:\n> > >\n> > >     find <find args> | xargs git rm\n> > >\n> > > myself.\n> > \n> >   that's what i would have normally used until i learned about git's\n> > magical globbing capabilities, and i'm going to go back to using it,\n> > because git's magical globbing capabilities now scare me.\n> \n> Hmm, I wonder if the reason why git's magically globbing capabilities\n> even exist at all is for those poor benighted souls on Windows, for\n> which their shell (and associated utilities) doesn't have advanced\n> tools like \"find\" and \"xargs\"....\n\nOne benefit of globbing with Git is that it restricts the matches only\nto tracked files. That matters a lot when you have a very broad glob\n(e.g., like you might use with \"git grep\") because it avoids looking at\ncruft like generated files (or even inside .git).\n\n-Peff\n"},{"id":"330096","messageId":"alpine.LFD.2.21.1710100432220.16182@localhost.localdomain","threadId":"46932","inReplyTo":"20171009175225.qn6a3j2th3dxjjn2@sigill.intra.peff.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-10T08:36:53Z","receivedAt":"2017-10-10T08:37:04Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Mon, 9 Oct 2017, Jeff King wrote:\n\n> On Sun, Oct 08, 2017 at 04:42:27PM -0400, Theodore Ts'o wrote:\n>\n> > On Sun, Oct 08, 2017 at 03:44:14PM -0400, Robert P. J. Day wrote:\n> > > >\n> > > >     find <find args> | xargs git rm\n> > > >\n> > > > myself.\n> > >\n> > >   that's what i would have normally used until i learned about\n> > > git's magical globbing capabilities, and i'm going to go back to\n> > > using it, because git's magical globbing capabilities now scare\n> > > me.\n> >\n> > Hmm, I wonder if the reason why git's magically globbing\n> > capabilities even exist at all is for those poor benighted souls\n> > on Windows, for which their shell (and associated utilities)\n> > doesn't have advanced tools like \"find\" and \"xargs\"....\n>\n> One benefit of globbing with Git is that it restricts the matches\n> only to tracked files. That matters a lot when you have a very broad\n> glob (e.g., like you might use with \"git grep\") because it avoids\n> looking at cruft like generated files (or even inside .git).\n\n  ah, now *that* is a compelling rationale that justifies the\nunderlying weirdness. but it still doesn't explain the different\nbehaviour between:\n\n  $ git rm -n 'Makefile*'\n  $ git rm -n '*Makefile'\n\nin the linux kernel source tree, the first form matches only the\nsingle, top-level Makefile, while the second form gets *all* of them\nrecursively, even though those globs should be equivalent in terms of\nmatching all files named \"Makefile\".\n\n  am i misunderstanding something?\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"},{"id":"330098","messageId":"xmqqpo9vpeg3.fsf@gitster.mtv.corp.google.com","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710100432220.16182@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-10T08:58:04Z","receivedAt":"2017-10-10T08:58:11Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Robert P. J. Day\" <rpjday@crashcourse.ca> writes:\n\n> underlying weirdness. but it still doesn't explain the different\n> behaviour between:\n>\n>   $ git rm -n 'Makefile*'\n>   $ git rm -n '*Makefile'\n>\n> in the linux kernel source tree, the first form matches only the\n> single, top-level Makefile, while the second form gets *all* of them\n> recursively, even though those globs should be equivalent in terms of\n> matching all files named \"Makefile\".\n>\n>   am i misunderstanding something?\n\nWe are matching what Git cares/knows about aka \"the paths in the\nindex\" to pathspec patterns.\n\nWhat are these paths in the index?  In Linux kernel sources, there\nare quite a many but here are examples that are enough to explain\nthe above:\n\n\tMakefile\n        COPYING\n\tfs/Makefile\n\tfs/ext4/Makefile\n\nWhich one of these four match patterh \"Makefile*\", which is \"the\nfirst letter is 'M', the second letter is 'a', ....,, the eighth\nletter is 'e', and anything else can follow to the end\"?  Yes, only\nthe first one.\n\nWhich one of these four match pattern \"*Makefile\", then?  \"Anything\ncan appear as leading substring, but then 'M', 'a', 'k', ..., and\nfinally 'e' must appear at the end\"?\n\nNote that these \"start from the paths in the index that match the\npathspec patterns\" have nothing to do with \"recursive\".  It happens\nway before we decide to go recursive (or not).\n\nWe are not going down recursively from the paths in the index that\nare matched by pathspec patterns with the above two \"git rm\"\nrequests (because there is no \"-r\" there), but even if we were,\nbecause these three Makefile files are not directories, there is\nnothing to remove recursively underneath them.\n"},{"id":"330105","messageId":"20171010115250.GA75189@book.hvoigt.net","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710080736530.21897@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2017-10-10T11:52:50Z","receivedAt":"2017-10-10T11:53:03Z","isPatch":false,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"On Sun, Oct 08, 2017 at 07:56:20AM -0400, Robert P. J. Day wrote:\n>   but as i asked in my earlier post, if i wanted to remove *all* files\n> with names of \"Makefile*\", why can't i use:\n> \n>   $ git rm 'Makefile*'\n> \n> just as i used:\n> \n>   $ git rm '*.c'\n> \n> are those not both acceptable fileglobs? why does the former clearly\n> only match the top-level Makefile, and refuse to cross directory\n> boundaries?\n\nMaybe think about it this way: The only difference between git's\nglobbing and the default shell globbing is that the '/' in a path has a\nspecial meaning. The shells expansion stops at a '/' but git does not.\n\nSo with *.c the shell matches: blabla.c, blub.c, ...  but not\nsubdir/bla.c, subdir/blub.c, ... since it only considers files in the\ncurrent directory. A little different for Makefile* that will also match\nMakefile.bla, Makefile/bla or Makefile_bla/blub in shell but not\nsubdir/Makefile or bla.Makefile. Basically anything directly in *this*\ndirectory that *starts* with 'Makefile'.\n\nGit on the other hand does not consider '/' to be special. So *.c\nmatches all of the path above: bla.c, blub.c, subdir/bla.c,\nsubdir/blub.c. Basically any file below the current directory with a\npath that ends in '.c'. With Makefile* it is the opposite: Every file\nbelow the current directory that *starts* with 'Makefile'. So\nMakefile.bla, Makefile/bla, ... but also not subdir/Makefile or\nbla.Makefile.\n\nMaybe that helps...\n\nCheers Heiko\n\n"},{"id":"330108","messageId":"1507637979.8322.33.camel@mad-scientist.net","threadId":"46932","inReplyTo":"alpine.LFD.2.21.1710100432220.16182@localhost.localdomain","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Paul Smith","fromEmail":"paul@mad-scientist.net","sentAt":"2017-10-10T12:19:39Z","receivedAt":"2017-10-10T12:41:07Z","isPatch":false,"sender":{"key":"paul@mad-scientist.net","avatar":"https://avatars.githubusercontent.com/u/109636?v=4"},"body":"On Tue, 2017-10-10 at 04:36 -0400, Robert P. J. Day wrote:\n>   ah, now *that* is a compelling rationale that justifies the\n> underlying weirdness. but it still doesn't explain the different\n> behaviour between:\n> \n>   $ git rm -n 'Makefile*'\n>   $ git rm -n '*Makefile'\n\nI explained that behavior in the email up-thread from this reply:\n\n> Globbing in \"git rm\" matches on the FULL PATH, not just the file name. \n> So, if you have a list of Makefiles in your repository like:\n> \n>   Makefile\n>   foo/Makefile\n>   bar/Makefile\n> \n> Then 'Makefile*' only matches the first one, since 'Makefile*' doesn't\n> match 'foo/Makefile' or 'bar/Makefile'.\n>\n> If you you worry that '*Makefile' will match things you don't want to\n> match, you'll have to use:\n> \n>   git rm -n Makefile '*/Makefile'\n\n"},{"id":"330135","messageId":"alpine.LFD.2.21.1710101543290.4437@localhost.localdomain","threadId":"46932","inReplyTo":"1507637979.8322.33.camel@mad-scientist.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-10T19:44:02Z","receivedAt":"2017-10-10T19:44:12Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Tue, 10 Oct 2017, Paul Smith wrote:\n\n> On Tue, 2017-10-10 at 04:36 -0400, Robert P. J. Day wrote:\n> >   ah, now *that* is a compelling rationale that justifies the\n> > underlying weirdness. but it still doesn't explain the different\n> > behaviour between:\n> >\n> >   $ git rm -n 'Makefile*'\n> >   $ git rm -n '*Makefile'\n>\n> I explained that behavior in the email up-thread from this reply:\n\n  yup, sorry i missed it. man, it's been an educational thread.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================"},{"id":"330163","messageId":"alpine.LFD.2.21.1710110430020.10556@localhost.localdomain","threadId":"46932","inReplyTo":"20171010115250.GA75189@book.hvoigt.net","subject":"Re: \"git rm\" seems to do recursive removal even without \"-r\"","fromName":"Robert P. J. Day","fromEmail":"rpjday@crashcourse.ca","sentAt":"2017-10-11T08:31:51Z","receivedAt":"2017-10-11T08:32:03Z","isPatch":false,"sender":{"key":"rpjday@crashcourse.ca","avatar":"https://avatars.githubusercontent.com/u/226084077?v=4"},"body":"On Tue, 10 Oct 2017, Heiko Voigt wrote:\n\n> On Sun, Oct 08, 2017 at 07:56:20AM -0400, Robert P. J. Day wrote:\n> >   but as i asked in my earlier post, if i wanted to remove *all* files\n> > with names of \"Makefile*\", why can't i use:\n> >\n> >   $ git rm 'Makefile*'\n> >\n> > just as i used:\n> >\n> >   $ git rm '*.c'\n> >\n> > are those not both acceptable fileglobs? why does the former\n> > clearly only match the top-level Makefile, and refuse to cross\n> > directory boundaries?\n>\n> Maybe think about it this way: The only difference between git's\n> globbing and the default shell globbing is that the '/' in a path\n> has a special meaning. The shells expansion stops at a '/' but git\n> does not.\n>\n> So with *.c the shell matches: blabla.c, blub.c, ...  but not\n> subdir/bla.c, subdir/blub.c, ... since it only considers files in\n> the current directory. A little different for Makefile* that will\n> also match Makefile.bla, Makefile/bla or Makefile_bla/blub in shell\n> but not subdir/Makefile or bla.Makefile. Basically anything directly\n> in *this* directory that *starts* with 'Makefile'.\n>\n> Git on the other hand does not consider '/' to be special. So *.c\n> matches all of the path above: bla.c, blub.c, subdir/bla.c,\n> subdir/blub.c. Basically any file below the current directory with a\n> path that ends in '.c'. With Makefile* it is the opposite: Every\n> file below the current directory that *starts* with 'Makefile'. So\n> Makefile.bla, Makefile/bla, ... but also not subdir/Makefile or\n> bla.Makefile.\n\n   ok, i believe i finally appreciate what is happening here, and\nperhaps my first contribution will be a minor addition to the \"git-rm\"\nman page to introduce a couple examples explaining these intricacies,\nsince they're not immediately obvious. i'll put something together and\nsubmit it to the list. thank you all for your patience in explaining\nthis.\n\nrday\n\n-- \n\n========================================================================\nRobert P. J. Day                                 Ottawa, Ontario, CANADA\n                        http://crashcourse.ca\n\nTwitter:                                       http://twitter.com/rpjday\nLinkedIn:                               http://ca.linkedin.com/in/rpjday\n========================================================================\n"}]}