Programming and IT

The .gitignore file

Every project has files that do not belong in the repository — caches, build folders, editor settings, local passwords. You keep the list of such files in .gitignore, and Git stops offering to add them.

Updated
In this article

Why you need it#

Without a list of exclusions, git status turns into a junk pile: hundreds of cache files hang next to your edits, and it is easy to miss what matters among them. Worse, a file with passwords or a key added by accident gets into history and goes to the server along with the commit.

.gitignore is an ordinary text file that lives in the repository and is committed itself: the rules should be the same for everyone who works on the project. It only affects files Git is not tracking yet. That is the main source of confusion, covered below.

Pattern syntax#

One line, one rule. Blank lines are skipped, and a line starting with a hash is a comment.

Pattern What it matches
secrets.txt a file with that name in any folder of the repository
*.log any file with the log extension
build/ the build folder and everything inside it, at any level
/build only build in the same folder as this .gitignore
docs/*.pdf pdf files directly in docs, but not in its subfolders
docs/**/*.pdf pdf files in docs and all of its subfolders
*.py[cod] .pyc, .pyo and .pyd files
!example.log an exception to the previous rule: do not ignore this file

The rules are simple, but two points are worth remembering. A slash inside a pattern anchors it to the folder of the .gitignore file; without a slash the pattern matches at any depth. And the exclamation mark does not work if the whole folder is ignored: Git does not look inside an excluded folder and cannot see that something there is allowed — in that case you ignore the contents (logs/*) and then add the exception.

A ready-made example#

A file in the root of a Python project:

__pycache__/
*.py[cod]

.venv/
venv/

.idea/
.vscode/
.DS_Store

/dist/
/build/
*.egg-info/

.env
*.local.yml

*.log
!example.log

The first two blocks are what the language itself creates. Then editor settings and operating-system clutter. Then build output — with a leading slash so you do not accidentally hide a build folder inside your sources. And at the end, local settings with secrets, plus logs, with one sample file deliberately kept.

Templates for dozens of languages and tools are collected in the open github/gitignore repository — taking one from there and adding your own lines is faster than remembering everything from scratch.

The file is already in the repository and the rule does nothing#

The most common complaint. .gitignore works only for untracked files; once a file has been committed, Git keeps tracking it no matter how many rules you add. You need to stop tracking it while keeping it on disk:

git rm --cached .env
rm '.env'

For a folder it is the same with -r: git rm --cached -r .idea. Then you record the change with a commit, and from that moment the rule applies.

An important note about secrets: untracking a file removes it from future commits, not from past ones. A password or token that was in a pushed commit counts as compromised — you change it, you do not scrub it from history.

Where else rules live#

There can be more than one .gitignore. A file in a subfolder applies to that folder and everything below it, and its rules are added to the root ones — handy when part of the project has its own clutter.

Personal habits do not belong in the shared file: the list for your editor or operating system is better kept in a global file so it works in every project at once.

git config --global core.excludesFile ~/.gitignore_global

Rules needed only in this copy of the repository and by nobody else go into .git/info/exclude — it is not committed and never reaches the server.

How to test a rule#

When you cannot tell why a file is ignored (or is not), ask directly:

git check-ignore -v .venv/bin/python
.gitignore:4:.venv/	.venv/bin/python

Read the answer as: the source of the rule, the line number, the pattern itself and the path. An empty answer means no rule matches the file. git status --ignored shows the whole list of ignored files.

If the rule is written correctly but the file still shows up in git status, it is almost certainly already tracked — go back to git rm --cached and a git commit. The other everyday commands are listed in the cheat sheet.

Step-by-step plan

  1. Create the file in the rootA plain-text .gitignore next to the .git folder.
  2. Add the obviousLanguage caches, build folders, virtual environments, editor settings, local secrets.
  3. Check the outputgit status: no more clutter in the untracked list.
  4. Untrack old filesgit rm --cached for files that got into the repository before the rule.
  5. Commit the file itself.gitignore is part of the project and everyone on it needs it.

Start learning this in your own space

The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.

Start the plan

Check yourself

1.The .env file got into the repository earlier, and you have now added a rule to .gitignore. What else do you need to do?

2.What does the line build/ in .gitignore ignore?

3.Which command shows exactly which rule ignores a file?

Sources

Was this helpful?

More articles

Programming and IT git checkout Historically `git checkout` does several unrelated things at once: it moves your working copy to another branch, creates a branch and pulls a single file out of a commit. Because it was so overloaded, Git 2.23 added two separate commands — `switch` and `restore`. Here are both sides: the old way and its modern replacement. Programming and IT git reset git reset moves the current branch pointer to another commit. How much your work suffers depends on one flag — `--soft` touches nothing but history, `--mixed` clears the index, `--hard` rewrites the files on disk. The third mode is the one Git command that destroys unsaved work for good. Programming and IT Python: reading a file Working with a file takes three steps: open it, read or write, close it. You are better off not closing it by hand — that is what the `with` statement is for. And the parameter people forget most is the encoding: without it, the same code reads a file differently on different machines. Programming and IT What is Docker Docker packages a program together with everything it needs to run into a single image — and that image starts the same way on a developer's laptop and on a server. Below — what an image is, how it differs from a container, how to write your first Dockerfile and where the technology is overkill. Programming and IT git commit A commit is a saved state of your project with an author, a timestamp and a message. git commit takes what you selected beforehand with git add and writes it into history as one indivisible piece. Programming and IT git merge Merging brings work from one branch into another. git merge takes the branch you name and joins its history with the current one — sometimes by just moving a pointer, sometimes by creating a separate commit, and sometimes by stopping and asking for help.

More solutions