Skip to content

Ignoring Files with .gitignore

Some files are required on a developer’s computer but should not become part of the repository. Examples include:

  • Dependency directories that can be recreated.
  • Local environment configuration.
  • Files containing passwords, API keys, or tokens.
  • Generated build output.
  • Logs and temporary files.

Tracking these files can expose secrets, increase repository size, create conflicts between developers, and add unnecessary changes to project history.

Git uses a special file named:

.gitignore

This file contains patterns describing paths that Git should normally ignore while they are untracked.

Create .gitignore in the repository root:

laravel-shop/
├── .git/
├── .gitignore
├── app/
└── composer.json

Example:

.env
/vendor/
/node_modules/
/public/build/
*.log
Pattern Meaning
.env Ignore .env
/vendor/ Ignore the root Composer dependency directory
/node_modules/ Ignore the root JavaScript dependency directory
/public/build/ Ignore generated frontend build output
*.log Ignore files ending in .log

.gitignore itself should normally be tracked and committed, so the team receives the same ignore rules:

Terminal window
git add .gitignore
git commit -m "build: add Git ignore rules"

Conventional Commit formatting is optional and is not required by Git.

Dependencies versus dependency definitions

Section titled “Dependencies versus dependency definitions”

These generated or installed directories are normally ignored:

vendor/
node_modules/

These dependency definition and lock files are normally committed:

composer.json
composer.lock
package.json
package-lock.json

The directories can be recreated from the tracked dependency files.

A Laravel .env may contain sensitive values:

APP_ENV=local
DB_DATABASE=laravel_shop
DB_USERNAME=root
DB_PASSWORD=secret-password
STRIPE_SECRET=sk_test_example

The real .env should normally not be committed. A safe template may be tracked instead:

.env.example

Example:

APP_ENV=local
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
STRIPE_SECRET=

.env.example lists the required configuration keys without storing real secrets.

.gitignore tells Git which matching untracked paths it should normally avoid showing and adding.

It does not:

  • Delete files from the computer.
  • Encrypt files.
  • Protect already exposed secrets.
  • Remove files from old commits.
  • Automatically stop tracking an already tracked file.

A tracked file is known to Git and belongs to the tracked project state. It may be unmodified, modified, or staged.

An untracked file exists in the Working Tree but Git is not currently tracking it. It normally appears when running:

Terminal window
git status

An ignored path normally means an untracked path matches an ignore rule. Git usually hides it from the normal untracked-files list.

Every ignored path is normally untracked, but not every untracked path is ignored.

A tracked file does not become ignored merely because its name is added to .gitignore.

Suppose .gitignore contains:

.env

If .env has never been tracked, running:

Terminal window
git status

should normally not show it under Untracked files.

Check the matching rule with:

Terminal window
git check-ignore -v .env
git check-ignore
Tests whether a path matches an ignore rule.
-v
Shows the matching rule and where that rule was defined.
.env
The path to test.

Illustrative output:

.gitignore:1:.env .env

This identifies the ignore file, the matching line, the pattern, and the checked path.

To include ignored paths in Git’s status summary, use:

Terminal window
git status --ignored

--ignored asks git status to show ignored paths as well as its normal tracked and untracked state summary. This is an inspection option; it does not change the files, the Staging Area, or a commit.

Suppose .env was already committed:

Terminal window
git add .env
git commit -m "add environment configuration"

Adding this later:

.env

does not make Git forget the file. Git continues reporting changes to .env because it is already tracked.

Ignore rules normally affect untracked paths. They do not retroactively remove files from the Index or previous snapshots.

First add the rule:

.env

Then run:

Terminal window
git rm --cached .env
git rm
Prepares removal of a tracked path from the next snapshot.
--cached
Removes the path from Git's Index while keeping the Working Tree copy.
.env
The path Git should stop tracking.

git rm --cached .env removes .env from the Index and stages its removal from the next commit snapshot, while keeping the local Working Tree file on disk.

The file does not physically move between Git areas — the Working Tree, Staging Area, and HEAD each track a different state or version of the same content.

Before git rm –cached

Working Tree
.env exists
Staging Area
.env exists
HEAD
.env exists

After git rm –cached

Working Tree
.env still exists
Staging Area
.env is absent
HEAD
.env still exists (until the next commit)

Assume .env is tracked and the repository is clean:

Working Tree: .env exists
Staging Area: .env exists
HEAD: .env exists

All three states agree.

After:

Terminal window
git rm --cached .env

the conceptual state becomes:

Working Tree: .env still exists
Staging Area: .env is absent
HEAD: .env still exists

There is now a staged difference between:

Staging Area ↔ HEAD

The next snapshot is prepared without .env, but HEAD still contains it until a new commit is created.

Run:

Terminal window
git status

Expected idea:

Changes to be committed:
deleted: .env

deleted: .env means the next commit snapshot is prepared without .env. It does not mean the Working Tree copy was deleted from the computer.

If .env matches .gitignore, the retained local copy is ignored and normally does not appear as Untracked.

Run:

Terminal window
git diff --staged
git status
Shows a summary of file states.
git diff --staged
Shows the actual staged difference between the Staging Area and HEAD.

git status does not display line-by-line differences.

If the learner runs:

Terminal window
git rm --cached .env

without adding .env to .gitignore, the file remains on disk but is removed from the Index. git status may show:

  • A staged deletion for the previously tracked version.
  • The remaining local .env as an untracked file.

Use this order instead:

  1. Add the ignore rule.
  2. Remove the path from the Index.
  3. Inspect the state.
  4. Commit the change.

Add these rules:

.env
.env.*
!.env.example

Stage .gitignore:

Terminal window
git add .gitignore

Stop tracking .env:

Terminal window
git rm --cached .env

Inspect the summary:

Terminal window
git status

Inspect the exact staged changes:

Terminal window
git diff --staged

Commit:

Terminal window
git commit -m "build: stop tracking local environment file"

Verify:

Terminal window
git status
git check-ignore -v .env
Previous commit:
.env exists in its snapshot
New commit:
.env is absent from its snapshot
Working Tree:
.env still exists locally

The Staging Area normally matches the new commit, and the local .env is ignored. The repository can report a clean Working Tree even though .env remains on disk.

No. Older snapshots may still contain it:

Old commit:
.env exists
New commit:
.env does not exist

Adding .env to .gitignore and committing its removal does not rewrite history.

If the file contained a real password, API key, or token:

  1. Treat the secret as exposed.
  2. Revoke or rotate it.
  3. Create a replacement secret.
  4. Keep the replacement outside tracked files.
  5. Use a separate history-cleaning process if required.
Command Working Tree Staged result
rm .env Deletes the local file The shell command itself does not stage the deletion
git rm .env Deletes the local file Stages its deletion
git rm --cached .env Keeps the local file Stages its removal from the next snapshot

rm is a shell command; git rm is a Git command. For this lesson’s goal, use:

Terminal window
git rm --cached .env

To stop tracking a directory while keeping it locally:

Terminal window
git rm -r --cached node_modules/

The corresponding rule should exist:

/node_modules/
-r
Process the directory recursively.
--cached
Change the Index while preserving Working Tree files.
# Ignore one file
.env
# Ignore files by extension
*.log
# Ignore a directory
node_modules/
# Ignore only the root-level directory
/node_modules/
# Ignore build output
/public/build/
# Ignore environment variants
.env.*
# Allow the safe template
!.env.example
  • # starts a comment.
  • * matches text.
  • A trailing / represents a directory pattern.
  • A leading / anchors the pattern to the location of this .gitignore.
  • ! creates an exception to a previous ignore rule.
  • Assuming .gitignore automatically untracks files.
  • Using git rm when the local file should remain.
  • Forgetting to commit the staged removal.
  • Running git rm --cached before adding an ignore rule.
  • Thinking old commits were cleaned.
  • Treating .gitignore as secret protection.
  • Ignoring dependency lock files along with dependency directories.
Goal Command
Inspect file states git status
Display ignored paths git status --ignored
Check the matching rule git check-ignore -v .env
Stop tracking a file but keep it locally git rm --cached .env
Stop tracking a directory but keep it locally git rm -r --cached node_modules/
Inspect staged differences git diff --staged
Commit the removal git commit -m "build: stop tracking local environment file"

.gitignore normally prevents matching untracked paths from being shown and added. It does not retroactively untrack files. git rm --cached stages a tracked path’s removal from the next snapshot while keeping the Working Tree copy. After the commit, Git stops tracking the path in new snapshots, but older commits remain unchanged.