When to use leading slash in gitignore

swahnee picture swahnee · Jun 10, 2014 · Viewed 14.1k times · Source

I'm trying to understand more clearly the .gitignore syntax, and in particular as far as https://github.com/github/gitignore gitignores are concerned.

I see that the leading slash is used to match only pathnames relative to the location of the .gitignore file (from http://git-scm.com/docs/gitignore):

A leading slash matches the beginning of the pathname. For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".

But what happens when i remove the leading slash? As far as what i understood, there are two cases:

  1. If the pattern does not contain a slash (or it contains only a trailing slash, which means that it should match a directory), the search is performed inside the entire directory tree. For example, the pattern dir/ will match <root>/dir, <root>/a/dir, <root>/a/b/c/.../dir, etc., where <root> is the location of the .gitignore file.
  2. If the pattern contains a slash, which is not in the trailing position (it's not the last character), then it is matched only with pathnames relative to the .gitignore file location.

These are the examples i made to check this behaviour:

# Directory structure:
<root>
├─ dir/
│   └─ test
├─ src/
│   ├─ dir/
│   │   └─ test
test file is there only because Git does not track empty directories.

First test:

# .gitignore
dir/

# git status
nothing to commit

So Git is ignoring both dir directories. This is consistent with case number 1: the pattern has no slashes (except for the trailing one), so Git is watching the entire directory tree, ignoring everything that matches the pattern.

Second test:

# .gitignore
/dir/

# git status
Untracked files:
    src/

Here, Git is ignoring only the dir directory directly beneath the root directory, thanks to the leading slash in the pattern.

Third test:

# .gitignore
dir/*

# git status
Untracked files:
    src/

This is consistent with the case number 2: the pattern has some slash inside it, so it is considered as a pathname starting from the root directory.

Now it's time for the real question. Let's consider this gitignore file: when they ignore the directory downloader/, for example, aren't they actually ignoring every single downloader directory found in the entire directory tree? This is what i'm driven to think since what i saw about Git's workings before.

So if i happen to have a custom module with a downloader directory inside of it, will it be unexpectedly ignored as well as the regular one in the root of Magento? This is a bit of a rethorical question because it actually already happened to me, producing a really hard to find bug.

So, in the Magento .gitignore file (which i'm referring to only as an example, btw) a lot of the patterns contain slashes, so they are correctly matched against pathnames starting from the root, but there are a few cases, like downloader/ or errors/ that, if i'm not mistaken, are potentially dangerous, and which should probably be changed to /downloader/ and /errors/.

As a more general question, should i always use the leading slash for patterns not containing slashes (except for the trailing one) when i want to select a pathname explicitly starting from root, and not to use it for patterns containing slashes, or should i always use the leading slash for clarity? What do you think about it?

Thank you for reading and sorry for the long post.

Answer

solstice333 picture solstice333 · Jul 18, 2016

Just wanted to summarize for possible quick future reference -- the leading slash anchors the match to the root. Thus, in the example below, without the slash, the wildcard would also exclude everything within foo because it would take * and move recursively down the tree. However, with /*, it excludes everything except folder foo and its contents:

$ cat .gitignore
/*
!/foo