Introduction

While working on our projects and using a version control system we could create and make use of a wide variety of different types of files. We may not want to keep track of every single file in our repository. Under such circumstances, we could use the .gitignore file to prevent certain files or certain file patterns from being tracked by git. In this article, we will demonstrate a practical scenario where we would need to prevent certain files from being tracked and we will make use of the .gitignore file to fulfill this requirement.

Demonstration:
While working on a project you would probably have related files placed in some folders within your repository instead of having all the files jumbled up into a single folder. You might have an src folder for source code, a docs folder for documentation, an output folder to store program output etc. Within my repository, I currently have only one file and no folders.

[sahil@linuxnix test_repo]$ pwd
/home/sahil/test_repo
[sahil@linuxnix test_repo]$ git status
# On branch master
nothing to commit, working directory clean
[sahil@linuxnix test_repo]$ ls
help.txt
[sahil@linuxnix test_repo]$

So, let’s create some sub-directories within this directory.

[sahil@linuxnix test_repo]$ mkdir src docs output
[sahil@linuxnix test_repo]$

If we run the git status command again we notice something strange.

[sahil@linuxnix test_repo]$ git status
# On branch master
nothing to commit, working directory clean
[sahil@linuxnix test_repo]$

Observe that we created some new sub-directories but git did not detect their presence. This is one of the nuances with git wherein if it sees a folder that is empty then it won’t track it. One way to get around this is to create a README file in each folder describing the purpose of the folder. Another common practice is to keep a hidden file named .gitkeep within the folder. This way git will keep track of the folder and normal users won’t see the .gitkeep file since it will be hidden. Also if a user downloads the repository they would get the entire repository including the empty folders. So, let’s create a .gitkeep file in the three folders that we’ve created.

[sahil@linuxnix test_repo]$ touch docs/.gitkeep
[sahil@linuxnix test_repo]$ touch output/.gitkeep
[sahil@linuxnix test_repo]$ touch src/.gitkeep

Now if we run the git status command again we observe that the sub-directories we had created are now being tracked by git.

[sahil@linuxnix test_repo]$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# docs/
# output/
# src/
nothing added to commit but untracked files present (use "git add" to track)
[sahil@linuxnix test_repo]$

Now let’s add all these files to the staging area using git add.

[sahil@linuxnix test_repo]$ git add .

Now if we run git status we find that the .gitkeep files from the various directories has been moved to the staging area.

[sahil@linuxnix test_repo]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: docs/.gitkeep
# new file: output/.gitkeep
# new file: src/.gitkeep
#
[sahil@linuxnix test_repo]$

Since we intend to keep these modifications to the repository, let’s commit our changes.

[sahil@linuxnix test_repo]$ git commit -m "created docs, output and src folders"
[master 2ea4e1a] created docs, output and src folders
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 docs/.gitkeep
create mode 100644 output/.gitkeep
create mode 100644 src/.gitkeep

Now under the output directory, I’ve created a couple of files that would normally be generated by the execution of a script.

[sahil@linuxnix test_repo]$ cd output/
[sahil@linuxnix output]$ touch script.log
[sahil@linuxnix output]$ touch script.error
[sahil@linuxnix output]$ pwd
/home/sahil/test_repo/output

Now if we run git status we will observe that git has noticed these files and the updates are ready to be staged.

[sahil@linuxnix output]$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# script.error
# script.log
nothing added to commit but untracked files present (use "git add" to track)
[sahil@linuxnix output]$

So, these files would be generated by the execution of a program and we do not want git to track these files. To prevent these files from being tracked by git, we create a .gitignore file in the root directory of our repository and add the names of files that we do not want to track in the .gitignore file.

[sahil@linuxnix test_repo]$ pwd
/home/sahil/test_repo
[sahil@linuxnix test_repo]$ cat .gitignore
script.error
script.log

Now if we run git status again we will observe that these two files are no longer being tracked.

[sahil@linuxnix test_repo]$ git status
# On branch master
# 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)
[sahil@linuxnix test_repo]$

Notice that now git tells us that the .gitignore file itself is not being tracked. We’ll add the .gitignore file to the staging area and commit the change.

[sahil@linuxnix test_repo]$ git add .gitignore
[sahil@linuxnix test_repo]$ git commit -m "Created a .gitignore file"
[master 01248e5] Created a .gitignore file
1 file changed, 2 insertions(+)
create mode 100644 .gitignore
[sahil@linuxnix test_repo]$
[sahil@linuxnix test_repo]$ git status
# On branch master
nothing to commit, working directory clean

How to forcefully add an ignored file?
By default git will refuse to add files are to be ignored as part of .gitignore file.

[sahil@linuxnix test_repo]$ git add output/script.log
The following paths are ignored by one of your .gitignore files:
output/script.log
Use -f if you really want to add them.
fatal: no files added

But there is a way around it and that is by using the -f flag to force git to track the file.

[sahil@linuxnix test_repo]$ git add -f output/script.log
[sahil@linuxnix test_repo]$

As you may observe from the above output, we were able to move the file to the staging area using -f option with the git add command. Now if we execute the git status command we will see the file is in the staging area and our change is ready to be committed.

[sahil@linuxnix test_repo]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: output/script.log
#

Let’s commit this change now.

[sahil@linuxnix test_repo]$ git commit -m "Tracking script.log file now"
[master 3ab965d] Tracking script.log file now
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 output/script.log
[sahil@linuxnix test_repo]$

Conclusion

In this article, we explained in detail a practical scenario wherein you would consider using the .gitignore file.
We hope that this demonstration was helpful to you and we look forward towards your suggestions and feedback.

The following two tabs change content below.

Sahil Suri

He started his career in IT in 2011 as a system administrator. He has since worked with HP-UX, Solaris and Linux operating systems along with exposure to high availability and virtualization solutions. He has a keen interest in shell, Python and Perl scripting and is learning the ropes on AWS cloud, DevOps tools, and methodologies. He enjoys sharing the knowledge he's gained over the years with the rest of the community.