code quality and tooling

Git Fundamentals for PHP Project Files

Git records changes to project files. In PHP work, that means source code, tests, Composer metadata, configuration examples, migrations, and documentation should be tracked, while generated files, dependencies, caches, logs, and secrets should usually be ignored.

The key skill is knowing which files belong in the repository and which files are local or generated. That affects reviews, deployments, onboarding, and debugging.

Track source, not generated output

A PHP project usually tracks files like these:

track:
- src/OrderTotal.php
- tests/OrderTotalTest.php
- composer.json
- composer.lock
- phpstan.neon
- phpcs.xml
- README.md

ignore:
- vendor/
- .phpunit.cache/
- storage/logs/app.log
- .env

The tracked files let another developer install, run, test, and review the project. The ignored files are recreated locally or contain machine-specific state.

Composer files

composer.json describes dependencies and scripts. composer.lock records the exact installed package versions for an application.

For most PHP applications, commit both:

composer.json
composer.lock

Do not commit vendor/. The dependency code should be installed from Composer.

vendor/

If you are working on a reusable library rather than an application, the lock-file convention can vary. Follow the project's existing practice.

Environment files

Real credentials and local environment values should not be committed.

.env
.env.local

Projects often commit an example file:

.env.example

The example file documents required keys without exposing secrets.

Caches and logs

Test caches, framework caches, log files, uploaded temporary files, and generated reports should normally stay out of Git.

.phpunit.cache/
var/cache/
var/log/
storage/logs/
storage/framework/cache/
coverage/

Some frameworks need empty directories to exist. In that case, projects sometimes commit a placeholder file such as .gitkeep inside the directory while ignoring generated contents.

Check the current state

Use git status before and after changes.

git status --short

Short status helps you see what files are modified, added, deleted, or untracked.

Before committing, inspect the actual diff.

git diff

This is where you catch accidental debug output, unrelated formatting, secrets, or generated files.

Stage intentionally

Do not blindly stage every file. Stage the files that belong to the change.

git add src/OrderTotal.php tests/OrderTotalTest.php

If a generated file appears in git status, update .gitignore or leave the file untracked. Do not commit it just because it appeared.

A useful PHP .gitignore shape

This is not universal, but it shows the common categories.

vendor/
.env
.env.local
.phpunit.cache/
coverage/
var/cache/
var/log/
storage/logs/

Always adjust for the framework and project.

What to remember

Git should capture the source of truth for the project, not every file produced while running it. Track code, tests, configuration, lock files for applications, and documentation. Ignore dependencies, caches, logs, local secrets, and generated output.

Before moving on, make sure you can explain why composer.lock is usually committed for applications, why vendor/ is ignored, and why .env.example is safer than committing .env.

Practice

Task: Sort Tracked And Ignored Files

Sort these files into track and ignore groups for a typical PHP application.

src/OrderTotal.php
tests/OrderTotalTest.php
composer.json
composer.lock
vendor/autoload.php
.env
.env.example
.phpunit.cache/test-results
storage/logs/app.log
phpstan.neon

Requirements

  • Put each file in exactly one group.
  • Explain why vendor/ should not be committed.
  • Explain why .env.example is different from .env.
  • Keep the answer focused on PHP project work.
Show solution
src/OrderTotal.php
tests/OrderTotalTest.php
composer.json
composer.lock
.env.example
phpstan.neon

Ignore:

vendor/autoload.php
.env
.phpunit.cache/test-results
storage/logs/app.log

vendor/ should not be committed because Composer can install dependencies from composer.json and composer.lock.

.env can contain real local secrets and machine-specific values. .env.example is safe to commit because it documents required keys without storing real credentials.