Table of Contents
Learning Git for PHP developers is one of the most valuable skills you can add to your workflow. Most PHP tutorials skip Git entirely or mention it in one line – “initialize a repository and commit your code.” That’s not enough. Git is the tool you’ll use every single day, and getting the workflow right from the start saves significant pain later.
This guide covers Git setup specifically for PHP projects – configuration, the daily commit workflow, what belongs in your .gitignore, how to write commit messages that actually help you later, and the commands you’ll run dozens of times per week. No theory, just the practical workflow.
Installing Git
Windows
Download Git from git-scm.com and run the installer. Accept the defaults – they’re sensible. During installation, select “Git from the command line and also from 3rd-party software” when asked about PATH adjustment.
Verify the installation:
git --version
Output:
git version 2.44.0.windows.1
Linux (Ubuntu/Debian)
sudo apt update
sudo apt install git
git --version
macOS
# Install via Homebrew
brew install git
git --version
First-Time Configuration
Do this once after installation. Every commit you make will be stamped with this name and email:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Set VS Code as your default editor – useful when Git opens an editor for commit messages or merge conflicts:
git config --global core.editor "code --wait"
Enable colored output so diffs and status messages are readable:
git config --global color.ui true
Set the default branch name to main – modern convention and matches GitHub’s default:
git config --global init.defaultBranch main
Verify everything looks correct:
git config --list
Output:
user.name=Kapil Verma
user.email=kapil@example.com
core.editor=code --wait
color.ui=true
init.defaultbranch=main
Initializing a PHP Project
Navigate to your project directory and initialize Git:
mkdir my-php-project
cd my-php-project
git init
Output:
Initialized empty Git repository in /var/www/html/my-php-project/.git/
For an existing PHP project:
cd /var/www/html/my-existing-project
git init
git add .
git commit -m "Initial commit"
The PHP .gitignore File
This is the most important file you create in any PHP project. It tells Git which files to ignore – vendor directories, environment files, logs, and editor-specific files that have no business in version control.
Create .gitignore in your project root before your first commit:
# PHP Dependencies
/vendor/
composer.phar
# Environment and configuration
.env
.env.local
.env.*.local
config/local.php
config/database.local.php
# Laravel specific
/bootstrap/cache/
/storage/*.key
/public/hot
/public/storage
Homestead.json
Homestead.yaml
# WordPress specific
wp-config.php
/wp-content/uploads/
/wp-content/cache/
/wp-content/upgrade/
*.log
# Logs and temporary files
/logs/
*.log
/tmp/
/cache/
# IDE and editor files
.idea/
.vscode/
*.swp
*.swo
.DS_Store
Thumbs.db
# Testing
/coverage/
.phpunit.result.cache
# Build files
/node_modules/
/public/build/
/public/mix-manifest.json
The two most critical entries are /vendor/ and .env. Committing vendor means pushing thousands of dependency files that Composer regenerates in seconds. Committing .env means putting database passwords and API keys into version control – a security problem that’s difficult to fully undo once it’s in the history.
Understanding the Three States
Git has three places your code lives – understanding this makes every command make sense:
Working Directory → Staging Area → Repository
(modified) (staged) (committed)
Working directory is where you edit files. Staging area is where you prepare your next commit. Repository is the permanent history.
Check which state your files are in at any time:
git status
Output on a fresh PHP project:
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
index.php
src/
nothing added to commit but untracked files present
The Daily Git for PHP Developers Workflow
This is the sequence you’ll repeat dozens of times every week. Internalize this and Git becomes automatic:
Step 1: Check What Changed
git status
Always start here. It tells you exactly what’s modified, what’s staged, and what’s untracked.
Step 2: See the Actual Changes
# See unstaged changes
git diff
# See changes in a specific file
git diff src/UserController.php
Output:
diff --git a/src/UserController.php b/src/UserController.php
index a3b2c1d..f4e5d6e 100644
--- a/src/UserController.php
+++ b/src/UserController.php
@@ -15,6 +15,12 @@ class UserController
public function store(Request $request)
{
+ $validated = $request->validate([
+ 'name' => 'required|string|max:255',
+ 'email' => 'required|email|unique:users',
+ ]);
+
+ User::create($validated);
Lines starting with + are additions. Lines starting with - are removals. Review this before staging anything – it’s your last easy chance to catch mistakes.
Step 3: Stage Your Changes
# Stage a specific file
git add src/UserController.php
# Stage a directory
git add src/
# Stage everything in the project
git add .
# Stage parts of a file interactively
git add -p src/UserController.php
git add -p is worth knowing. It shows each changed chunk individually and asks whether to stage it. Useful when one file contains two unrelated changes and you want to commit them separately.
Step 4: Verify What You’re About to Commit
git diff --staged
This shows staged changes – exactly what will be in your next commit. Always check this before committing on important changes.
Step 5: Commit
git commit -m "Add validation to UserController store method"
Output:
[main 3f7a9b2] Add validation to UserController store method
1 file changed, 6 insertions(+)
Writing Good Commit Messages
A commit message is a note to your future self and anyone else who works on the code. “fixed stuff” and “WIP” are useless when you’re debugging a production issue at 11pm six months later.
The format that works:
# Good commit messages - specific and clear
git commit -m "Add email validation to registration form"
git commit -m "Fix cURL timeout on product scraper - increase to 30s"
git commit -m "Remove deprecated mysql_connect - replace with PDO"
git commit -m "Add CSRF token to login form"
git commit -m "Fix SQL injection vulnerability in search query"
# Bad commit messages - useless for debugging
git commit -m "fix"
git commit -m "WIP"
git commit -m "changes"
git commit -m "update"
git commit -m "asdfgh"
The rule: if you can’t complete the sentence “This commit will…” with your message, rewrite it. “This commit will add email validation to registration form” – clear. “This commit will fix” – meaningless.
Viewing History
# Full commit history
git log
# Condensed one-line format - most useful day to day
git log --oneline
# Last 5 commits
git log --oneline -5
# Commits by a specific author
git log --oneline --author="Kapil"
# Commits that changed a specific file
git log --oneline -- src/UserController.php
# Visual graph showing branches
git log --oneline --graph --all
Output of git log –oneline -5:
3f7a9b2 Add validation to UserController store method
8c4d1e5 Add PDO connection with error handling
2a9f3b1 Create users table migration
7e2c8d4 Add .gitignore for PHP project
1b5a6f9 Initial commit
This is your project’s timeline. Each line is a save point you can return to.
Connecting to GitHub
Create a repository on GitHub then connect your local project:
# Add the remote repository
git remote add origin https://github.com/yourusername/my-php-project.git
# Verify the remote was added
git remote -v
# Push your code for the first time
git push -u origin main
Output:
origin https://github.com/yourusername/my-php-project.git (fetch)
origin https://github.com/yourusername/my-php-project.git (push)
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Writing objects: 100% (12/12), 3.42 KiB | 3.42 MiB/s, done.
To https://github.com/yourusername/my-php-project.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
After the first push with -u flag, future pushes are just:
git push
Cloning an Existing PHP Project
When joining a project or setting up on a new machine:
# Clone the repository
git clone https://github.com/username/php-project.git
# Clone into a specific directory name
git clone https://github.com/username/php-project.git my-local-name
cd php-project
# Install PHP dependencies
composer install
# Copy environment file
cp .env.example .env
# Set up your local configuration
nano .env
Always run composer install after cloning a PHP project. The vendor directory is in .gitignore so it won’t be in the repository – Composer recreates it from composer.lock.
Useful Git Aliases for PHP Developers
Set up shortcuts for the commands you run most often:
# Short status
git config --global alias.st status
# Short log - one line per commit
git config --global alias.lg "log --oneline --graph --all -20"
# Undo last commit but keep changes staged
git config --global alias.undo "reset --soft HEAD~1"
# Show what changed in the last commit
git config --global alias.last "show --stat HEAD"
Now instead of typing git status you type git st. Small thing, adds up over thousands of uses:
git st # git status
git lg # visual log last 20 commits
git undo # undo last commit safely
git last # what did I just commit?
Quick Reference: Daily Commands
| Command | What It Does |
|---|---|
| git status | Show modified, staged, and untracked files |
| git diff | Show unstaged changes |
| git diff –staged | Show staged changes about to be committed |
| git add . | Stage all changed files |
| git add -p | Stage changes interactively chunk by chunk |
| git commit -m “message” | Commit staged changes with a message |
| git push | Push commits to remote repository |
| git pull | Fetch and merge remote changes |
| git log –oneline | View condensed commit history |
| git log –oneline — file | History of a specific file |
Frequently Asked Questions
Should I commit composer.lock to Git?
Yes – always commit composer.lock but never commit the /vendor/ directory. The lock file records the exact versions of every dependency installed. When another developer runs composer install, they get identical versions to yours. Without the lock file, composer install might install newer patch versions that behave differently. The vendor directory itself is regenerated from the lock file and has no place in version control.
I accidentally committed my .env file. What do I do?
Three steps. First, add .env to your .gitignore immediately. Second, remove it from Git’s tracking without deleting the file:
git rm --cached .env
git commit -m "Remove .env from version control"
git push
Third – and this is critical – rotate every credential that was in that file. Change your database password, regenerate API keys, update your application key. The file is in the repository history even after removal. If the repository was ever public or pushed to a remote, assume those credentials are compromised.
What is the difference between git fetch and git pull?
git fetch downloads changes from the remote repository but doesn’t merge them into your working branch. git pull fetches and merges in one step. Use git fetch when you want to see what changed on the remote before deciding whether to merge. Use git pull when you’re ready to update your local branch immediately.
How often should I commit in a PHP project?
Commit when you complete a logical unit of work – not necessarily a full feature, but something that stands on its own. Adding a method, fixing a bug, adding validation to a form, writing a database migration. Small focused commits are easier to understand in the log, easier to revert if something goes wrong, and easier to review in pull requests. Committing once a day with everything bundled together makes Git history nearly useless.
What should I do if I committed to the wrong branch?
If you haven’t pushed yet, undo the last commit while keeping your changes:
# Undo last commit, keep changes staged
git reset --soft HEAD~1
# Switch to the correct branch
git checkout correct-branch
# Commit on the right branch
git commit -m "Your message"
If you’ve already pushed, the situation is more complex – that’s covered in Post 3 of this series on undoing mistakes in Git.
Summary
The Git workflow for PHP developers comes down to a repeating cycle:
- Check status before touching anything –
git status - Review changes before staging –
git diff - Stage intentionally –
git add -pfor precision,git add .for everything - Commit with meaning – messages that explain what and why, not just “update”
- Push regularly – your remote is your backup
The .gitignore file is not optional for PHP projects. Set it up before the first commit and include /vendor/, .env, logs, and editor files as a minimum.
The next post in this series covers Git branching for PHP projects – how to use feature branches for new work, hotfix branches for production bugs, and how to merge cleanly without losing history. If you’re using Git for a PHP project alongside a framework, the PHP project setup guide covers the full project structure including Git initialization from scratch.
