Ignore or Keep in Git
We can control what to be stored or not to be in Git remote repositories.
We can control what files or directories to be stored or not to be stored in Git remote repositories.
They are .gitignore
and .gitkeep
.
.gitignore
There are many unnecessary files that we don’t want to store in Git for example, .venv/
in Python projects, node_modules/
in Node.js projects, or .terraform
in Terraform projects. Or some data files or even a credential files in the project directory that we need to keep them in only our local machine and not in remote repositories.
.gitignore
is a file that Git uses to check and ignore them. It could be an exact file name or directory or a pattern.
Example
Let’s say we have a project structure like this:
1
2
3
4
5
6
7
8
9
10
11
.
├── normal-file2.txt
├── normal-file3.txt
├── normal-folder
│ └── normal-file1.txt
└── secret-folder
├── confidential.txt
├── public.txt
└── super-secret-file.txt
3 directories, 6 files
Ignore by a file name
We can directly put the name of files. It can be just file names to ignore them in any directories, or an absolute path in case we need to store the same name in other directories.
1 2 3 4 5 6 7 8 9 10 11
. ├── normal-file2.txt ├── normal-file3.txt ├── normal-folder │ └── normal-file1.txt └── secret-folder ├── confidential.txt ├── public.txt └── super-secret-file.txt 3 directories, 6 files
We ignore 2 secret files under
secret-folder/
so they won’t take place in the commit.1 2
secret-folder/super-secret-file.txt secret-folder/confidential.txt
1 2 3 4 5 6 7 8 9
$ git status -u Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore normal-file2.txt normal-file3.txt normal-folder/normal-file1.txt secret-folder/public.txt
Ignore by a directory name
We can also put the directory name to ignore every files inside. It could end with a slash (/
) or not, either way works.
1 2 3 4 5 6 7 8 9 10 11
. ├── normal-file2.txt ├── normal-file3.txt ├── normal-folder │ └── normal-file1.txt └── secret-folder ├── confidential.txt ├── public.txt └── super-secret-file.txt 3 directories, 6 files
1
secret-folder # or secret-folder/
1 2 3 4 5 6 7 8
$ git status -u Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore normal-file2.txt normal-file3.txt normal-folder/normal-file1.txt
Ignore by patterns
We can also ignore files with glob
patterns.
1 2 3 4 5 6 7 8 9 10 11
. ├── normal-file2.txt ├── normal-file3.txt ├── normal-folder │ └── normal-file1.txt └── secret-folder ├── confidential.txt ├── public.txt └── super-secret-file.txt 3 directories, 6 files
This will ignore every files in every directories where the file name starts with any characters (
*
), followed by-file
, followed by any characters (*
), and ends with.txt
.1
*-file*.txt # or **/*-file*.txt
1 2 3 4 5 6 7
$ git status -u Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore secret-folder/confidential.txt secret-folder/public.txt
Ignore but include a specific one
After we ignore some directories but just realize that we still need some files inside. We can use !
like this.
1 2 3 4 5 6 7 8 9 10 11
. ├── normal-file2.txt ├── normal-file3.txt ├── normal-folder │ └── normal-file1.txt └── secret-folder ├── confidential.txt ├── public.txt └── super-secret-file.txt 3 directories, 6 files
First we ignore every files inside the directory by
directory/*
to claim the file level, not directory level. Then add files we want to include by having!
in front. Now we can see that file is going to be committed.1 2
secret-folder/* !secret-folder/public.txt
1 2 3 4 5 6 7 8 9
$ git status -u Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore normal-file2.txt normal-file3.txt normal-folder/normal-file1.txt secret-folder/public.txt
Personal .gitignore
We can maintain the ignore file at .git/info/exclude
. This file works like .gitignore
but it won’t be recognized by Git so it won’t be store in the remote repository.
The benefit from this is that we can make new files in our local repository and will be ignored to Git without changing .gitignore
so that it won’t affect our teammates’ working environments.
1 2 3 4 5 6 7 8 9 10 11
. ├── normal-file2.txt ├── normal-file3.txt ├── normal-folder │ └── normal-file1.txt └── secret-folder ├── confidential.txt ├── public.txt └── super-secret-file.txt 3 directories, 6 files
Here we just ignore only the directory
secret-folder/
.1
secret-folder/
But in here we also want to ignore
normal-file2.txt
as well.1 2 3 4 5 6 7 8
# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ normal-file2.txt
1 2 3 4 5 6 7
$ git status -u Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore normal-file3.txt normal-folder/normal-file1.txt
Easy creation
There are so many ways to create .gitignore
file for instances:
- Create it manually and write the contents like above depends on our works.
- Copy contents from github/gitignore.
- Generate it from gitignore.io.
- Build automatically with package managers such as uv.
- Choose from templates when create a new repository in Git servers such as Github.
and more.
.gitkeep
Git basically doesn’t include empty directories. For example, if I have
1
2
3
4
.
├── published
│ └── sample.txt
└── drafts
Then I can’t commit the directory drafts/
because it is empty.
1
2
3
4
5
$ git status -u
Untracked files:
(use "git add <file>..." to include in what will be committed)
published/sample.txt
So I just create an empty file named .gitkeep
inside drafts/
to make Git recognize it.
1
2
3
4
5
.
├── published
│ └── sample.txt
└── drafts
└── .gitkeep # <-- newly created
Then the directory drafts/
can be committed there.
1
2
3
4
5
6
$ git status -u
Untracked files:
(use "git add <file>..." to include in what will be committed)
published/sample.txt
drafts/.gitkeep
However, .gitkeep
is not one of special files at all. In fact, we can create any name to the file because we just want the directory to be not empty and Git can recognize. And the name .gitkeep
is just a convention name to see that the file is keeping the directory in Git.