---
title: 'Ignore Rules'
source: 'https://academia.sh/en/courses/introduction-to-version-control/ignore-rules'
course: 'Introduction to Version Control'
language: en
updated: '2026-08-17T18:10:47+00:00'
license: 'CC BY-SA 4.0'
---

# Ignore Rules

Files that should not enter the repository; `.gitignore` pattern syntax; finding a rule's source, and why ignore rules do not apply to tracked files.

So far, the repository holds only files written by hand. But files also get
produced while working: the script's output, backups left by the editor, build
results. These get listed at every `git status` call, lowering the visibility of
the real changes, and can end up in a commit by mistake.

This lesson takes up which files are kept out of the repository, and how this
decision gets recorded.

## What Should Not Enter the Repository

Four classes are distinguished:

- **Derived files.** Everything that can be produced from the sources already in
  the repository: build outputs, data produced by scripts, temporary reports.
  Keeping them in history is unnecessary, because they can be regenerated from
  the source; what is more, they show up as a constant diff since they change on
  every regeneration.
- **Local environment files.** Editor settings, metadata files the operating
  system leaves in directories, personal notes. These belong to the person, not
  the project.
- **Secrets.** Passwords, access keys, private certificates. Keeping these out
  of the repository is not a matter of tidiness, it is a security requirement.
- **Large binary files.** Every version is stored as a separate object and
  cannot be compressed, since no diff can be taken. They take up space in every
  copy of the repository.

The third item calls for a separate warning. As noted in the previous topic, in a
distributed repository, history spreads to every copy. Even if a password is
deleted after being committed, the deletion only adds a new commit; the old
commit containing the password stays in place and is present in every copy of
the repository. In this case, the only correct action is to invalidate the
secret.

## The `.gitignore` File

In the example repository, running the script produces a log file and an output
directory; the editor also leaves a backup:

```bash
git status --short
```

```
?? README.md~
?? ara.log
?? cikti/
```

The rules are written into a text file named `.gitignore`:

```
# Betiğin ürettiği çıktılar
ara.log
cikti/

# Düzenleyici yedekleri
*~
```

```bash
git status --short
```

```
?? .gitignore
```

Three entries dropped off the list; what is left is the file carrying the rules
itself. `.gitignore` is committed to the repository: the rules belong to the
project and should be the same in every copy of the repository.

```bash
git add .gitignore
git commit -m "Üretilen dosyaları yoksayma listesine al"
```

```
[main 9b23cc3] Üretilen dosyaları yoksayma listesine al
 1 file changed, 6 insertions(+)
 create mode 100644 .gitignore
```

## Pattern Syntax

Every line is a **pattern**: a string matched against path names that can
contain wildcard characters.

| Pattern | Meaning |
|---|---|
| `*.log` | Files with the `.log` extension, at any depth |
| `cikti/` | Only directories named `cikti`, and their contents |
| `/gecici.tmp` | Only `gecici.tmp` at the repository root |
| `not?.txt` | Single-character wildcard: `not1.txt`, `not2.txt` |
| `a/**/veri.bin` | `veri.bin` at any depth under `a` |
| `!ara.log` | Excludes a file covered by a previous rule from the rule |
| `# text` | A comment line |

Two details are often confused. The first is **the position of the slash**: if
there is a slash inside or at the start of the pattern, the pattern is resolved
relative to the directory the `.gitignore` file is in; otherwise it matches at
any depth. `/gecici.tmp` catches only the file at the root, not
`alt/gecici.tmp`. The second is **the trailing slash**: `cikti/` matches only
directories, not a file named `cikti`.

Rules are evaluated in order, and **the last matching rule** takes effect. This
is why a rule starting with `!` has to be written after the pattern it covers;
if written first, it has no effect.

## Why a File Is Ignored

In long rule lists, which line is in effect can be asked directly:

```bash
git check-ignore -v ara.log cikti/son-arama.txt "README.md~"
```

```
.gitignore:2:ara.log	ara.log
.gitignore:3:cikti/	cikti/son-arama.txt
.gitignore:6:*~	README.md~
```

Every line gives the file the rule is in, the line number, the pattern, and the
matching path. If a rule starting with `!` matches, it is listed too; in that
case, the file is not ignored, because the last matching rule excluded it from
the rule.

All ignored files can also be listed:

```bash
git status --short --ignored
```

```
?? .gitignore
!! README.md~
!! ara.log
!! cikti/
```

The `!!` mark denotes ignored entries.

## Ignoring Does Not Apply to Tracked Files

A file holding local notes gets committed by mistake:

```bash
git commit -m "Yerel notları ekle"
```

```
[main 7783378] Yerel notları ekle
 1 file changed, 3 insertions(+)
 create mode 100644 notlar-yerel.md
```

The mistake is noticed, and the file name is added to `.gitignore`. But nothing
changes:

```bash
git ls-files
```

```
.gitignore
README.md
ara.sh
notlar-yerel.md
terimler.txt
```

The file is still tracked. The rule not applying is not a flaw, it is a
consequence of the definition: ignore rules determine whether **untracked**
files get listed or not. If a file has a record in the staging area, it is
already tracked, and the rules have nothing to do with it. Otherwise, adding a
rule could make tracked files silently drop out of history.

For the same reason, `git check-ignore` stays silent too: by default, the
command does not evaluate tracked paths.

The fix is to remove the file from the staging area:

```bash
git rm --cached notlar-yerel.md
```

```
rm 'notlar-yerel.md'
```

The `--cached` option deletes only the record in the staging area; the file in
the working directory stays in place. Without the option, the file is deleted
from disk too.

```bash
git commit -a -m "Yerel notları izlemeden çıkar"
```

```
[main cb8f7ee] Yerel notları izlemeden çıkar
 2 files changed, 1 insertion(+), 3 deletions(-)
 delete mode 100644 notlar-yerel.md
```

After this commit, the file is no longer tracked, and the `.gitignore` rule
takes effect. The file's old content, however, still sits in history: commit
`7783378` is still reachable. Ignoring does not clean up the past; it only puts
the future in order.

## Three Ignore Layers

| Location | Scope | Shared? |
|---|---|---|
| `.gitignore` | The directory it is in, and below | Yes, committed to the repository |
| `.git/info/exclude` | This repository only | No, stays local |
| The file pointed to by `core.excludesFile` | All of the user's repositories | No |

The distinction is made by this criterion: does the rule belong to the
**project**, or to a **work habit**? The build output's name belongs to the
project and is written to `.gitignore`. The temporary files left by the editor
in use belong to the person; rather than adding these to every project's
`.gitignore`, the right place to write them is the user-level file.

Rules specific to this repository but not meant to be shared are written to the
`.git/info/exclude` file, and it uses the same syntax:

```bash
git check-ignore -v deneme-1.txt
```

```
.git/info/exclude:7:deneme-*.txt	deneme-1.txt
```

Since the output's first field shows which file the rule came from, confusion
between the three layers is resolved with the same command.

## Summary

- Derived files, local environment files, secrets, and large binary files
  should not enter the repository.
- Rules are written to the `.gitignore` file; the file is committed to the
  repository and applies in every copy.
- In patterns, the slash's position determines the scope; a trailing slash
  limits the pattern to directories; the last matching rule takes effect.
- Ignore rules affect only untracked files; a tracked file has to be removed
  from tracking with `git rm --cached`.
- Rules can be kept in three layers: the file committed to the repository, the
  repository-specific local file, and the user-level file.

## Next Step

The basic cycle is complete: a change is made, staged, committed, history is
read. But this cycle has been told in one direction only. What happens when the
wrong file gets staged, an edit needs to be taken back, or a commit is written
wrong? The next topic takes up the tools for undoing, and its first lesson
starts with the narrowest-scoped ones — unstaging and restoring a file.
