22

In Ryan Bates' Railscast about git, his .gitignore file contains the following line:

tmp/**/*

What is the purpose of using the double asterisks followed by an asterisk as such: **/*? Would using simply tmp/* instead of tmp/**/* not achieve the exact same result?

Googling the issue, I found an unclear IBM article about it, and I was wondering if someone could clarify the issue.

P̲̳x͓L̳
  • 3,615
  • 3
  • 29
  • 37
Yuval Karmi
  • 26,277
  • 39
  • 124
  • 175
  • Note: While some shells support this syntax, Git does not. In a `.gitignore` file this is equivalent to `tmp/*/*`. – hammar Oct 02 '12 at 07:09

3 Answers3

26

It says to go into all the subdirectories below tmp, as well as just the content of tmp.

e.g. I have the following:

$ find tmp
tmp
tmp/a
tmp/a/b
tmp/a/b/file1
tmp/b
tmp/b/c
tmp/b/c/file2

matched output:

$ echo tmp/*
tmp/a tmp/b

matched output:

$ echo tmp/**/*
tmp/a tmp/a/b tmp/a/b/file1 tmp/b tmp/b/c tmp/b/c/file2

It is a default feature of zsh, to get it to work in bash 4, you perform:

shopt -s globstar
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • Is there nomenclature for this kind of pattern matching in Unix? I'm trying to find more information and I don't know how to Google it. – Jondlm Nov 29 '13 at 16:00
  • Pattern matching for files is called globbing. The basic variants are `*` for 0 or more characters, `?` for any character and `[CharacterRange]` for characters matching a particular range e.g. `[0-9]` to match a digit. Some shells extend it in their own ways, which includes the `**` syntax. – Anya Shenanigans Nov 29 '13 at 17:43
  • I tried it in my bash shell but echo tmp/**/* and tmp/*/* give the same result, so I don't see ** doing anything more than * – Storm Sep 20 '15 at 10:05
  • Make more than two level of subdirectories and you'll see the difference. – Anya Shenanigans Sep 20 '15 at 10:06
6

From http://blog.privateergroup.com/2010/03/gitignore-file-for-android-development/:

(kwoods)

"The double asterisk (**) is not a git thing per say, it’s really a linux / Mac shell thing.

It would match on everything including any sub folders that had been created.

You can see the effect in the shell like so:

# ls ./tmp/* = should show you the contents of ./tmp (files and folders)
# ls ./tmp/** = same as above, but it would also go into each sub-folder and show the contents there as well."
Hans
  • 3,403
  • 3
  • 28
  • 33
2

According to the documentation of gitignore, this syntax is supported since git version 1.8.2.

Here is the relevant section:

Two consecutive asterisks (**) in patterns matched against full pathname may have special meaning:

  • A leading ** followed by a slash means match in all directories. For example, **/foo matches file or directory foo anywhere, the same as pattern foo. **/foo/bar matches file or directory bar anywhere that is directly under directory foo.

  • A trailing /** matches everything inside. For example, abc/** matches all files inside directory abc, relative to the location of the .gitignore file, with infinite depth.

  • A slash followed by two consecutive asterisks then a slash matches zero or more directories. For example, a/**/b matches a/b, a/x/b, a/x/y/b and so on.

  • Other consecutive asterisks are considered invalid.

ValarDohaeris
  • 6,064
  • 5
  • 31
  • 43