Introduction to .gitignore file
When you push files to your remote repository like Github, the files you've pushed can be viewed by anyone. This can be stressful as some of the files may be containing confidential data that should not be shared publicly. This should not stress you now, Git has a way of protecting your files in a very easy and simple way.
Git observes every file in your project folder in three main ways:
- Tracked files: these are files that have been previously committed or staged for commit.
- Untracked files: these are files that are have not been committed or staged for commit.
- Ignored files: these are files that Git is to ignore.
The .gitignore
is a file containing a list of files or folders that allows you to command Git to pass over/ignore in the local repository while pushing commits. The .gitignore
file is mainly found in the main folder of a project. Git can not ignore files and folders on your local branch unless you intentionally remove them from the branch to your .gitignore
file. This means that all files and folders in your local repository are added to commit in case you use the git add .
. This git add .
command stages every file into a commit.
Mostly, developers like to ignore output folders, compiled code, and concealed system files. For example, if youāve got a .env
file in your project folder, you may wish to hide it because the .env
file contains API keys that you may not be willing to commit. In Git, there is no .gitignore
command to be used to ignore files. For Git to ignore your files, you must intentionally create a list of all the files and folders you want to be ignored and add them to the .gitignore
file.
Lab Environment
To clearly master how .gitignore
file works,Ā it is important to have hand-on experience on how to go about it. I will clone git_examples repository from gitlab to my local workstation which we will use to demonstrate the examples from this article:
1. Create .gitignore file
Making a .gitignore
file in your local repository is simple.Ā On your terminal/command shell, cd
to your project repository/directory and use touch
command to create the hidden file.
~$ cd Projects/
~/Projects$ touch .gitignore
You can use ls -al
to list all the files including any hidden file. The file does not need any configuration setting for it to work.
Let's take a look at an example. In your project folder, we have untracked files and folders as seen below:
$ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) .DS_Store .env-dev .env-prod index.js node_modules/
It's a bit pointless to track theĀ .DS_Store
Ā andĀ node_modules/
files in our repo. The DS_Store
is a macOS invisible file that is automatically created when you open a folder with Finder. On the other hand, the node_module
folder contains downloaded npm libraries that anyone can download on their machine, so we'll have to ignore them.
To ignore these files we will add DS_Store
file and node_modules
folder in .gitignore
file which we created earlier.
.DS_Store node_modules/
Check the git status command, now the DS_Store
file and node_modules
folder are not in the untracked files and are stored in our .gitignore
file
$ git status
...
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env-dev
.env-prod
.gitignore
index.js
2. What type of files should be added in the .gitignore file
- Log files.
- Unwanted system files, for example, DS_Store on macOS.
- Generated files like the Dist folder.
- Dependencies that can be downloaded.
- Files that contain API keys, credentials, or any sensitive data.
- Compiled binary files such as
.pyc
scripts from python programs
3. How .gitignore works
- A
.gitignore
file is a plain file where every line contains patterns for files and directories to ignore. - The file is placed in the repository's root folder but can also be placed in any directory in the repository.
- You can also have multiple
.gitignore
files in one repository. - The location of the
.gitginore
file determines the pattern to be used. - The
.gitignore
uses globbing patterns to match filenames that have wildcard characters.
4. Create multiple .gitignore in different directories
Git allows you to have a .gitignore
file in any directory within your repository. Each file affects its directory and all subdirectories. To resolve a hierarchy with multiple .gitignore
directories and to allow command-line addenda to the list of ignored files, Git honors the following precedence, from highest to lowest:
- Patterns specified on the command line.
- Patterns read from
.gitignore
in the same directory. - Patterns in parent directories, proceeding upward. Hence, the current directoryās patterns overrule the parentsā patterns, and parents close to the current directory take precedence over higher parents.
- Patterns from the
.git/info/exclude
file. - Patterns from the file specified by the configuration variable
5. Examples of pattern matching in .gitignore
In this section we will cover some examples to ignore files and directories based on pattern match:
5.1 Adding comments using hash (#)
Blank lines are ignored, and lines starting with a hash mark (#) can be used for comments. However, the hash mark does not represent a comment if it follows other text on the line.
# Javascript node_modules node_modulesl/ # API keys .env
5.2 Ignoring folders or directories using forwards slash (/)
The forward slash symbol ( /
) is used as a folder separator. When used at the start of a pattern, it is relative to the folder where the .gitignore
file resides.
# ignore Project directory
/Project
If there is no slash at the start of a pattern, it matches files and folders in any folder or subfolder.
node_module
.env
If the pattern has a slash at the end, it matches only folders. If a folder/ directory is ignored, all the subdirectories and files in that folder are also ignored.
Javascript/
styles/
!
) pattern will also not be able to exclude files or directories from these excluded directory.
5.3 Ignore zero or more characters after match
There are three different regex pattern which can be used with .gitignore
:
- The asterisk symbol (
*
) matches zero or additional characters. - The double asterisk
**
symbols, it equals any file or zero or additional directories. When you have two * * then a slash, it matches only folders. - The question mark (
?
) symbol matches exactly one character
When you have two **
at the end of a pattern and a slash symbol, it equals anything inside the named folder.
logs/**
The question mark symbol (?) equals any solo character. For example, out?.log
may mean out0.log
, out1.log
, out3.log
5.4 Ignore a range of characters with square brackets []
The square brackets equal any of the characters that are inside the brackets. When two characters are separated by a -
(hyphen), it shows a range of characters, and the range comprises all characters between the two characters. The range can either be alphabet or numeric.
If the first character in the pattern following the [ is an exclamation mark (!
), the pattern matches some of the characters except the specified set.
For example,
- A pattern
*. [oa]
matchesfile.o
andfile.a
both. - A pattern
* . [!oa ]
it may mean that it matchesfile.s
,file.1
andfile.o
5.5 Exclude files from ignore list with negate (!) pattern
Any pattern that begins with an exclamation mark (!
) re-include any files that were previously ignored by the previous pattern. This rule aims to re-include files that the parent folder excluded.
*.log
!example.log
Based on this pattern, error.log
Ā orĀ logs/error.log
will be ignored but example.log
or logs/example.log
will not be ignored
You can not negate a file that is inside an ignored folder.
logs/
!logs/example.log
In this case, git will still ignore logs/example.log
because the whole logs folder is ignored.
5.6 gitignore pattern match examples
This table contains some more examples to demonstrate the behaviour of different pattern matching used in .gitignore
file:
Pattern | Match (Will be ignored) | No Match (Will not be ignored) | Comments |
---|---|---|---|
logs/ |
logs/debug.log |
log/debug.log |
Adding a forward slash at the end represents directory. All the files and directory in the provided directory will be ignored |
logs/ |
logs/debug.log |
dir/important_file |
Even though we have used Negate to exclude logs/important_file but when we add a directory for exclusion then git will never look inside that directory so we cannot individually exclude files inside excluded folder |
logs/* |
logs/debug.log |
logs/important_file |
Now we have specified an asterisk after logs/* so git will not ignore logs directory itself but all the files inside logs directory so now you can add Negate for individual files |
/dir1/*/file.log |
/dir1/dir2/file.log |
/dir1/dir2/dir4/file.log |
Single asterisk (* ) will match a single file or folder |
/dir1/**/file.log |
/dir1/dir2/file.log |
/dir1/dir2/dir4/file123.log |
Double asterisk (** ) matches any strings of folders |
/dir1/**/file*.log |
/dir1/dir2/dir4/file123.log |
We have combined double and single asterisk here from above examples to match the pattern | |
cron[0-9].log |
cron0.log |
cron11.log |
Provide a range of numbers or text between 0-9 or A-Z or a-z to match in the pattern. One block of square brackets will match single character only.To match multiple characters, provide multiple square brackets, such as [0-9][0-9] etc |
cron[09].log |
cron0.log |
cron2.log |
Since we have not specified a range here inside the square brackets, so only provided single digit will be matched |
cron[!09].log |
cron2.log |
cron0.log |
Using a negate pattern we have switched the pattern matching so now all integers except 0 and 9 will be matched |
!important_file |
logs/important_file |
important_file.log |
We use negate pattern (! ) to exclude a file or directory but the entire string should match unless a different regex pattern is used |
*.log?? |
file1.log10 |
file1.log1 |
? is used to match a single character. Since we have used two ?? so the regex expects exactly two character to have a match |
6. Personal .gitignore Rules
You can also express your personal ignore patterns for any repository in a unique file
.git/info/exclude
. These files remain unsorted and undistributed. This makes it a better place to add patterns that will only be of importance to you. They only work on that particular repository, and they do need to be committed.
Inside your Git
folder there is a /info/exclude
Ā that works the same way as .gitignore
file.
Add files that only you want to ignore in your project
debug.log
API.env
www/config.loc
Now, the files above are only ignored in our local clone but if we want them to be universally ignored they should be placed in .gitignore
file
7. Global .gitignore Rules
Additionally, you can create global Git ignore patterns by setting Git core.excludesFile property for all repositories on your local branch. The file can be kept in your home directory for easy spotting. They affect every directory/repository you use on your computer, and they do not require committing. Once the file is ready, you have to configure its location with git config.
The files added should be used in storing files that are specific to your production environment only. For example, if you are a Windows user, you may want to have a thumb.db
file and since other developers using the same repository may not be using Windows, the presence of a thumb.db
file repository gitginore
would not benefit them. Let us create a global Git ignore pattern.
First, create your .gitignore
file.
$ touch .gitignore
Add files to your .gitignore
file.
# inside .gitignore file # Windows Thumbs.db
Finally, let us configure git
to apply our new .gitignore
file.
git config --global core.excludesfile ~/.gitignore
8. List all Ignored Files
The git status
command is used to show the state of the local repository and the staging area. But by default it will not list any ignored files. You can use --ignored
argument with git status
command to list all the .gitignored
files in the repository:
9. Commit ignore files
One of the frequently asked questions is, can files that have been ignored be committed? It is possible to commitĀ ignored files by the use of the force option (-f
Ā or --force
) while you git addĀ
In this example we try and commit a fileĀ that has already been ignored (test/important_file
)
Next we use git add -f
to add this file forcefully to our repository:
deepak@ubuntu:~/git_examples$ git add -f test/important_file
Next check the status again, as you can see our file has been added successfully:
Now we can go ahead and commit this file:
$ git commit -m "Adding an ignored file" test/important_file
[new-feature 3e17cea] Adding an ignored file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test/important_file
10. Stashing an ignored file
The git stash command is a powerful feature that temporarily shelves changes that you have made on your working file so that you can focus on something else and then revisit and re-apply the changes later. Stashing is convenient if you urgently need to switch context and focus on something else, but you have not completed your task and can not be committed. By default, git stash ignore
all ignored files and only stashes files that are tracked by Git. But, you can initiate a git stash -u
( untracked file) or with the --all
option to stash changes ignored and untracked files.
# our .gitignore file consist:-
node_modules/
index.js
index.html
debug.log
API.env
www/config.lock
Now we are going to git stash -u
Ā to stash our untracked files.
$ git stash -u
Saved working directory and index state WIP on main: a4695ae Create Front-end
All our files have beenĀ stashed, now let us confirm by using git status
to see the state of our repository
$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
Now to re-apply our files back to our repository lets git stash pop
$ git stash pop On branch main Your branch is up to date with 'origin/main'. Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: API.env new file: debug.log new file: index.css new file: index.html new file: index.js Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore Dropped refs/stash@{0} (2a7eb1777c651416cb2c780d81b2e21a3ac57f08)
11. Debugging .gitignore File
In some cases there can be a challenge determining the reason why some files are being ignored, this happens mostly when you have multiple .gitignore
files or many complex patterns. This is where we use the git check-ignore
command with an option -v
to tell Git to showcase matching pattern's details.
Let's see our .gitignore
file
# inside the .gitignore file
node_modules/
index.js
index.html
debug.log
API.env
configuration/
For example, to check why is www/config.lock
ignored. We would run,
$git check-ignore -v www/config.lock .gitignore:6:/configuration/www/config.lock www/config.lock
The outputĀ will show the path to the .gitignore
file, the actual pattern, and the line number of the rule which matches the pattern.
12. Advantages of the .gitignore
Apart from ensuring that Git does not track particular files and directories, there are other advantages that come with using a .gitignore
file.
- It aids in organizing the code repository by ignoring unwanted directories and files.
- It aids in keeping the size of the repository under control, which is helpful when working on a big project.
- It ensures that you do a good commit, pull request, and push.
Summary
In this tutorial we covered following topics:
- Introduction to .gitignore file
- Creating a .gitignore file
- What type of git files should be ignored
- Different examples to match pattern with .gitignore
- How gitignore works
- Advantages of .gitignore