git-rm fu
From: Jon Loeliger <hidden>
Date: 2016-06-15 22:44:28
Given:
$ git init
Initialized empty Git repository in .git/
$ echo one >> git-foo.sh
$ mkdir subdir
$ echo two >> subdir/git-foo.sh
$ mkdir subdir/snizzle
$ echo three >> subdir/snizzle/git-foo.sh
$ git add .
$ git commit -m"All quiet on the western front."
Created initial commit 15fe70d: All quiet on the western front.
3 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 git-foo.sh
create mode 100644 subdir/git-foo.sh
create mode 100644 subdir/snizzle/git-foo.sh
The "git rm" manual's second example says:
git-rm -f git-*.sh
Remove all git-*.sh scripts that are in the index. Because this
example lets the shell expand the asterisk (i.e. you are listing
the files explicitly), it does not remove subdir/git-foo.sh.
It is not true that this command will remove all git-*.sh scripts
that are in the index. Here are three:
$ git ls-files
git-foo.sh
subdir/git-foo.sh
subdir/snizzle/git-foo.sh
Using -f on this command is a red herring. Using -f or -n
doesn't matter, and since we want to do more than one command
here, I'm just going to show it all using -n:
The effect of the command is to match just one file at the top level:
$ git rm -n git-*.sh
rm 'git-foo.sh'
Furthermore, there is an implication in the wording of the
second example that suggests that if you had let git expand the
file glob, the subdir/git-foo.sh file would have been removed.
Also not true:
$ git rm -n git-\*.sh
rm 'git-foo.sh'
To actually get the behavior of "removing all git-*.sh scripts
from the index", you have to prefix a file glob at the front
of the paths to match directories too:
$ git rm -n \*git-\*.sh
rm 'git-foo.sh'
rm 'subdir/git-foo.sh'
rm 'subdir/snizzle/git-foo.sh'
But then, using any of:
\*git-\*.sh
\*git-*.sh
*git-\*.sh
all effectively *will* match subdir/git-foo.sh:
$ git rm -n \*git-*.sh
rm 'git-foo.sh'
rm 'subdir/git-foo.sh'
rm 'subdir/snizzle/git-foo.sh'
$ git rm -n *git-\*.sh
rm 'git-foo.sh'
rm 'subdir/git-foo.sh'
rm 'subdir/snizzle/git-foo.sh'
So it seems that the two parts discussed in the second example
are really unrelated.
It seems like "git rm d2/*" should remove all of d2's files
without trying to recursively remove any subdirectories,
but it won't:
$ git rm -n d2/*
fatal: not removing 'd2/two' recursively without -r
But then using -r force d2/two/ to be removed as well:
$ git rm -n d2/\*
rm 'd2/two/xyzzy'
rm 'd2/x'
rm 'd2/y'
rm 'd2/z'
There's no real way to say "just the files in d2/".
(Yeah, sure, I could have said "git rm d2/\?", but that wouldn't
work if d2/xyzzy existed too. :-))
jdl