Much ado about .gitignore

Reference on gitignore

Ignore the files in a directory from tracking them


/aspire_jsdk23.jar

/META-INF/
/com/

.gitignore file itself is tracked and part of the commit

What is $git_dir

Search for: What is $git_dir

Here is some relevant info on SOF

Note on $GIT_DIR: This is a notation used all over the git manual simply to indicate the path to the git repository. If the environment variable is set, then it will override the location of whichever repo you're in, which probably isn't what you want.

.gitignore samples for java

Search for: .gitignore samples for java


# Ignore all files and sub directories
# in this sub directory
# except the .gitignore file

/**
!.gitignore

# Such a directory is useful for holding 
# local temporary processed files.

How to ignore all directories with a certain name in gitignore

Search for: How to ignore all directories with a certain name in gitignore

.gitignore patterns a simple guide

Search for: .gitignore patterns a simple guide

Some examples for atlassian


Name: .gitignore

usually: in the root folder (recommended)

Can be: placed in sub directories as well

This is a link from Plural insight: Seem better


#ignore any file or directory with this name
abc.txt 

#ignore any file or sub directory
#file can be anywhere in the subdirectory structure
xyz 

#Only if any sub directory matches this name
bin/

gitignore repo on github

A dot (.) has no special meaning


*xyz*

#a directory match in the hierarchy
/abc/dddxyzbbb/a.log #a match

#a file match in the hierarchy
/abc/xyz.log #a match

#Match only sub directories ending in xyz
#not files
*xyz/

** means a set of subdirectories: I think

A name by itself matches a directory or filename anywhere in the hierarchy

So few often useful patterns


#Directory anywhere
abc #any file or sub dir
abc\ #only any sub dir

#Sub directory
\abc #file or dir
\abc\ #only dir

bin/

*.jar

#Any sub directory named this way
__pycache__/ 

#Ignore these file extensions anywhere .pyc, .pyo, .pyd
#No special meaning to "." also "*" means any thing
*.py[cod]

#any file with this pattern. $ has no meaning
*$py.class

#File or dir anywhere
# "." has no meaning
.Python

#Any sub dir named build
build/
develop-eggs/
dist/

#Any sub directory that ends in ".egg-info"
*.egg-info/

#Any file or sub directory named like this
.installed.cfg

#Any file or sub dir ending in ".egg"
*.egg

#Any file or subdirectory anywhere
MANIFEST

#Any depth sub directory that has "docs" as its parent
docs/_build/

# any sub dir named target
target/

# Any file or sub dir: for Jupyter Notebook
# usually it is a sub dir
# i suspect placing a / at the end would work as well
.ipynb_checkpoints

# file or directory anywhere
.python-version

Read this as well

1. Behavior seem to be different if there is an "embedded" "/" in the path.

2. vs the "/" only at the end

The slash / is used as the directory separator. Separators may occur at the beginning, middle or end of the .gitignore search pattern.

If there is a separator at the beginning or middle (or both) of the pattern, then the pattern is relative to the directory level of the particular .gitignore file itself. Otherwise the pattern may also match at any level below the .gitignore level.

If there is a separator at the end of the pattern then the pattern will only match directories, otherwise the pattern can match both files and directories.

For example, a pattern doc/frotz/ matches doc/frotz directory, but not a/doc/frotz directory; however frotz/ matches frotz and a/frotz that is a directory (all paths are relative from the .gitignore file).

See this URL to understand it better


dir1/dir2/

will only match

/dir1/dir2

but not

/a/b/c/dir1/dir2

dir2/

will match

/dir2
/dir1/dir2
/a/b/c/dir2

foo/bar

will only match

/foo/bar

will not match

/a/b/foo/bar

For that to match you have to do 

**/foo/bar

at any depth will match

/a/b/foo/bar
/foo/bar
/x/foo/bar

etc..

Essentially that is one way to locate any "sub trees" to ignore

Some discussion on double *


What is obvious
Obvious patterns
What is not obvious
Not so obvious patterns
Role of /
Role of **
Role of *
What is unclear to me yet
References
  At Git
  Article 1
  Art 2
  SOF
  gitignore at github
Aggregated examples

#
# Hello this is a sample .gitignore file
#

# ******************************************
# Understand: * (ig: Any file or directory at any depth): 
# Result: Hide all
# ******************************************
# Lets try with */ (a directory approach)
# Only files under directories are hidden
# 
# Lets see what happens a * is in the root
# Seem to block all files and directories including .gitignore
#*

# ******************************************
# Understand: */ (ig: Any directory at any depth)
# Result: Only root files show
# ******************************************
# Lets try with */ (a directory approach)
# Only files under directories are hidden
# Because all directories are ignored, only root files show
# when a directory is ignored all its children are ignored
#*/

# ******************************************
# Understand: /** (Actual directive to ignore this directory and all below)
# Result: as expected
# ******************************************
# Meanning: Hide all sub directories including this one
# Hide this directory and everything underneath
# Similar behavior as *
#/**

# ******************************************
# Understand: /*
# ******************************************
# Lets see a relative path with a /*
# Any Directory or a file name in the root
#
# Children directory behavior (as expected)
# ******************************************
# 1. First level directories are hidden
# 2. First level files are hidden
# 3. Because of 1 all sub directories and their files are hidden as well
#
# Similar behavior as: *, /*, /**
#
# *******************************************
# /*

1. The filename for git ignore is: .gitignore

2. Look for or create this file at the root of the git repo

3. This file can also exist for each sub directory as well

1. Many many things can be done by having just one file at the root

2. So convention is to control most of the behavior from the one under the root

3. One does not need specialize at a sub directory level often

1. The rules of the .git ignore can get very confusing.

2. However the simple things are kept simple

3. I will provide the URL where these rules are documented in the References section below

4. There are also some rules that are short cuts and often used

5. It took me a few days to fully understand MOST rules

6. I will also point out what I am still not too clear, if they remain at the end

Lets get to the easiest rules to understand first


# This is a comment line

#ignore a file a.txt at the root
/a.txt

#ignore a deeper file
/dir1/dir2/a.obj

#you can obviously have empty lines

1. If this "/" is at the beginning the pattern can be interpreted differently. Later on this.

2. Same with "/" at the middle of a pattern

3. So the "/", as you will soon find has some special treatment

4. For now it is sufficient to know that for a relative path start with a "/"


# ignore this directory and all its sub directories
/dir1/

# deeper tree
/dir1/dir2/
/dir1/dir3/

etc...

1. In "/dir1/" if the trailing "/" is eliminated then "dir1" refers to either a directory or a filename, both

2. So by placing a trailing "/" one forces ignoring only directory with this name.


# consider this
/dir1/

# This would allow a filename
/dir1

# as long as there is such a filename

1. There is no special meaning in the context of gitignore

2. Like in a path, it represents multiple files that matches the pattern. it plays the same role here.


# ignore all root level files starting with name "test"
/test*

# or
/dir1/test*.txt

# ignore directories that match these patterns

# ignore all directories at the root that start
# with testdir-
/testdir-*/

# Notice the trailing "/"
# it tells that this applies only directories and not files

/a/b/dir*xys*/

#Ignore directories under /dir1 starting with test
/dir1/test*/

#However this will allow the following 

/dir1/test.txt
/dir1/test4.txt

# not allowed are
/dir1/testdir
/dir1/test4dir

1. Ignoring relative paths are pretty straight forward and few surprises.

2. They do have to start with "/" even though they are relative

3. You can use "*" for pattern matching

4. The "*" doesn't cross boundaries of directory separators "/"

Slightly less obvious rules

1. Placement of "/" in a path

2. Files vs Directories based on a path


# The following is not relative
# this pattern has a special meaning. will cover later
dir1

# This is NOT realative either
dir1/

#make this relative: / at the beginning
/dir1

#relative as well
/dir1/dir2

#the following is relative: / at the middle
dir1/dir2
dir1/a.txt

/dir1

#dir1 above can be a file or a directory

#force a directory with a trailing "/"

#So the following only applies to a directory
/dir1/

4. "/" at the end almost always says the preceding spec is a directory spec

1. For a path to be relative there must be a "/" at the beginning or in the middle of a path

2. The "/" at the end indicates that the spec applies only to directory and not files

3. Eliminating the trailing "/" means the entire namespace (file or directory) is not allowed in that relative path

I will now move on to the most seen rules in a gitignore file.

1. A spec with no interrupting (beginning or middle) "/" has a special meaning

2. Such a spec applies to anywhere in the hierarchy of directories

3. Spec does allow "*" to generalize the spec

4. The trailing "/" is allowed and retains its meaning of files vs directories or both


# No file or directory anywhere named "xys" is ignored
xyz

what does it mean in gitignore? It means, do not allow any where in the repo a directory or a file that is named "xyz"


#All of the following files and directories are ignored

/dir1/xyz #where xyz is a file is ignored

/dir2/dir3/xyz #where xyz is a directory

/xyz #where xyz is a directory


# The following ignores directories anywhere
# file are allowed with that name
xyz/

#Notice the LACK OF BEGINNING "/"

/dir1/xyz #where xyz is a file so it is allowed

/dir2/dir3/xyz #where xyz is a directory so it is ignored

/xyz #where xyz is a directory so it is ignored

# Ignore File or a directory anywhere whose name
# starts with "xyz"
xyz*

# Ignore all files anywhere with this extension
*.obj

# Ignore all directories (not files) 
# with this kind of name anywhere.
.profile/

1. So this is the most often used pattern

2. which is, ignoring files or directories anywhere in the hierarchy based on a name (and not relative path)


# Consider this line in gitignore
abc/testdir/

# it may look like an anywhere spec
# because it has no beginning "/"

#But it is not.

# Because it lacks the criteria that
# there cannot be a "/" interrupting the name
# as in this case in the middle.

1. A spec with no interrupting (beginning or middle) "/" has a special meaning

2. Such a spec applies to anywhere in the hierarchy of directories

3. Spec does allow "*" to generalize the spec

4. The trailing "/" is allowed and retains its meaning of files vs directories or both

5. This pattern is the most used in .gitignore files, you will find.

1. You can ignore files and directories (no trailing "/")

2. You can ignore directories only but allow files (trailing "/")

3. You cannot allow directories while ignoring files

4. so if you ignore files, directories are automatically ignored.

There are some rules involving "**" that are really not obvious and sometimes have overlapping effects with the previous rules. These are

1. "**" at the beginning of a line

2. "**" at the end

3. "**" in the middle


# if it is at the root you can say
/foo/bar/

# Or

/foo/bar

# Or

foo/bar

#But what if you want to avoid

/foo/bar
/dir1/dir2/foo/bar
/dir1/foo/bar

# but allow the directory "bar" when it appears by itself
# with out preceding by "foo"

/bar
/dir1/dir2/bar
/dir1/bar

# you can avoid the tree /foo/bar anywhere
# by indicating

**/foo/bar

# the "**" must be at the beginning
# No "/" is at the front to note

/dir1/**/foo/bar/

# This means
# Any number of sub directories under "dir1"

#So this avoids

/dir1/a/foo/bar
/dir1/b/foo/bar
/dir1/a/b/foo/bar
/dir1/a/b/c/foo/bar


/dir1/**

# This means
# ignore everything under the relative /dir1 to any depth

/**

# means ignore this directory and 
# everything underneath

1. "**" at the beginning of a line ignores the following directory hierarchy anywhere in the repo. So "**/foo/bar" ignores "/foo/bar" anywhere.

2. "**" at the end means ignore all sub directories. So "/foo/**" is same as "/foo/".

3. "**" in the middle like "/dir1/**/foo/bar" means any sub directory depth after "/dir1" but followed by "/foo/bar"


# ******************************************
# Understand: * (ig: Any file or directory at any depth): 
# Result: Hide all
# ******************************************
# Lets see what happens a * is in the root gitignore
# Seem to block all files and directories including .gitignore
# Because its instruction is 
#  "ignore anything with this pattern anywhere file or dir")

*

# ******************************************
# Understand: */ (ig: Any directory at any depth)
# Result: Only root files show
# ******************************************
# Because all directories are ignored, only root files show
# when a directory is ignored all its children are ignored

*/

# ******************************************
# Understand: /** (Actual directive to ignore this directory and all below)
# Result: Hides all as expected
# ******************************************
# Meanning: Hide all sub directories including this one
# Hide this directory and everything underneath
# Similar behavior as *

/**

# ******************************************
# Understand: /* (Ignore immediate files or directories under the root)
# Result: Hides all again
# ******************************************
# 1. First level directories are hidden
# 2. First level files are hidden
# 3. Because of 1 all sub directories and their files are hidden as well
#
# Similar behavior as: *, /*, /**
#
# *******************************************

/*

Key References

1. An article on Linked In:Curious experiment with \*, \*/, /\*, /\*/, and /\*\* in .gitignore

2.A running journal on .gitignore

3. Reference on gitignore at git

4. An Atlassian article

5. A Pluralinsight article

6. An SOF discussion

7. A repo for gitignore samples

8. A Git Repo to experiment with .gitignore with instructions