Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What pattern does .gitignore follow?

Tags:

git

shell

glob

Here is the content of my current directory.

$ ls
foo.foo
$ ls -a
.  ..  .bar.foo  .foo  foo.foo  .gitignore

Then I turn this directory into a git repository.

$ git init
Initialized empty Git repository in /home/lone/foo/.git/
$ ls -a
.  ..  .bar.foo  .foo  foo.foo  .git  .gitignore

Here is the content of .gitignore.

$ cat .gitignore 
*.foo

I see that the pattern in .gitignore behaves differently from the same pattern in shell. In the shell *.foo matches only non-hidden files, i.e. filenames that do not begin with a period.

$ echo *.foo
foo.foo

But *.foo in .gitignore seems to match any files, hidden or non-hidden, that ends with .foo.

$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        .gitignore

nothing added to commit but untracked files present (use "git add" to track)

Where can I learn more about the precise definition of the patterns that .gitignore follows, so that I can understand where and why its behaviour differs from that of the shell glob patterns?

like image 381
Lone Learner Avatar asked Jan 20 '16 13:01

Lone Learner


2 Answers

gitignore use of '*' follows the glob convention:

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.

For example, "Documentation/*.html" matches "Documentation/git.html" but not "Documentation/ppc/ppc.html" or "tools/perf/Documentation/perf.html".

The OP Lone Learner asks in the comments:

Does the shell also use fnmatch(3) to process glob patterns?
In that case why does * not match zero characters before. (i.e. hidden files) but gitignore does?

Because that is a shell configuration choice.

Type (using shopt, which is specific to bash):

shopt -s dotglob
echo *.foo
.foo foo.foo

That is using dotglob

If set, Bash includes filenames beginning with a '.' in the results of filename expansion. (for pattern matching)

like image 140
VonC Avatar answered Sep 25 '22 03:09

VonC


.gitignore simply contains entries for the pattern you wish to tell git not to track (wildcards support).

This configuration is stored at a folder level.
In there you can specify which file to ignore.
This file will apply to all the subfolders inside in a recursive way.

.gitignore is collecting information in a commutative way:

  • System level - (Global) for example if you are a unix user and you wish to ignore all the *.so files for all your projects you will place it in the global file

  • Local - Usually will be at a project level applying for all the content of the given project.

  • Per folder - specific definitions for the given folder (for example - ignore password file, log file etc or any other resource you wish to ignore)

There is also a configuration property core.excludesfile which allow you to set an ignored file to use as well.

git config --global core.excludesfile ~/.gitignore

You can also specify which files not to ignore by adding the ! before the file so it will not be ignored (read more below about the wildcards whic can be used).

To learn about the syntax you can read about it here.
You can use 3rd part tools to generate this file for you gitignore.io.


I couldn't find what in the page explains that * matches zero or more characters and matches hidden files too

Each line in the file can contain any pattern with the following wildcards:

? = Matches zero or one occurrence of the given patterns.
* = Matches zero or more occurrences of the given patterns.
+ = Matches one or more occurrences of the given patterns.
@ = Matches one of the given patterns.
! = Matches anything except one of the given patterns.


In your comment you asked for information about the * pattern.

Here you can see that the * ignore all files. Git doesn't care if its a hidden file or not. its simply looking for the matched pattern.

enter image description here

As explained above git try to match the pattern you supply in the .gitignore file so if you wish to ignore files in an inner folder you will have to specify the inner folder. Here is a demo of the folder content and how to ignore inner files. You can see that the inner folder aa contain file inside but since the ignore file contains the **/ pattern it will ignore all the inner folders and files.

enter image description here

like image 22
CodeWizard Avatar answered Sep 22 '22 03:09

CodeWizard