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

git-rm fu

From
Jon Loeliger <jdl@jdl.com>
Date
Apr 13, 2008, 20:44 UTC
Message-ID
<E1Jl949-0000yh-M1@jdl.com>
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
Message 1 of 1 in “git-rm fu”
  1. Jon LoeligerApr 13, 2008

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.