Git Best Practices
In this lesson, we'll explore essential Git best practices that will help you maintain clean, secure, and efficient repositories. Following these practices will make collaboration easier and prevent common mistakes.
Commit Often, Push Regularly
Frequent commits and regular pushes protect your work and improve collaboration:
Commit Often:
✓ Commit after completing a logical unit of work
✓ Don't wait until end of day to commit
✓ Creates more granular history
✓ Easier to identify when bugs were introduced
✓ Simpler to revert specific changes
Push Regularly:
✓ Push at least once per day
✓ Backup your work to remote
✓ Share progress with team
✓ Enable early conflict detection
✓ Prevent large merge conflicts
Golden Rule: Commit locally when a feature or fix works. Push to remote when it's ready for others to see. Think: "Commit for you, push for them."
Keep Commits Atomic and Focused
Atomic commits contain one logical change and make history easier to understand:
Good - Atomic Commits:
✓ "Add user authentication endpoint"
✓ "Fix login button alignment"
✓ "Update API documentation"
Bad - Non-Atomic Commits:
✗ "Fix bugs and add features"
✗ "Friday afternoon changes"
✗ "Various updates"
How to stage partial changes:
# Stage specific files
git add file1.js file2.css
# Interactive staging (patch mode)
git add -p
# Stage only modified files (not new files)
git add -u
# Stage everything in a directory
git add src/components/
Tip: Use git add -p to review each change before staging. This helps you split unrelated changes into separate commits.
Write Meaningful Commit Messages
Good commit messages explain why changes were made, not just what changed:
Commit Message Structure:
<type>(<scope>): <subject>
<body>
<footer>
Example:
feat(auth): implement JWT token refresh
Add automatic token refresh mechanism to prevent
session expiration during active use. Tokens are
refreshed 5 minutes before expiration.
Closes #123
Conventional Commits Types:
feat: New feature
fix: Bug fix
docs: Documentation changes
style: Code formatting (no logic change)
refactor: Code restructuring (no behavior change)
test: Adding or updating tests
chore: Maintenance tasks (dependencies, build)
perf: Performance improvements
ci: CI/CD configuration changes
revert: Reverting a previous commit
Good Commit Messages:
✓ "fix(api): handle null values in user response"
✓ "refactor(auth): extract validation logic to service"
✓ "docs(readme): add installation instructions"
Bad Commit Messages:
✗ "fix stuff"
✗ "update"
✗ "asdfasdf"
✗ "fix fix fix"
Best Practice: Write commit messages in imperative mood: "Add feature" not "Added feature" or "Adds feature". Think: "If applied, this commit will <your message>".
Use Branches Effectively
Proper branch management keeps your codebase organized and collaboration smooth:
Branch Naming Conventions:
feature/add-user-profile
bugfix/fix-login-error
hotfix/critical-security-patch
release/v1.2.0
experiment/new-architecture
Pattern: <type>/<description>
- Use lowercase
- Use hyphens, not underscores
- Keep it descriptive but concise
- Include ticket number if applicable: feature/AUTH-123-login
Branch lifecycle best practices:
# 1. Create branch from updated main
git checkout main
git pull
git checkout -b feature/new-dashboard
# 2. Work on feature, commit regularly
git add .
git commit -m "feat: add dashboard layout"
# 3. Keep branch updated with main
git checkout main
git pull
git checkout feature/new-dashboard
git merge main # or git rebase main
# 4. Push and create PR
git push -u origin feature/new-dashboard
# 5. After merge, clean up
git checkout main
git pull
git branch -d feature/new-dashboard
git remote prune origin
Important: Delete branches after merging. Stale branches clutter the repository and confuse team members about what's active.
Keep History Clean
A clean Git history is easier to navigate and understand:
Before pushing to shared branches:
# Squash multiple small commits
git rebase -i HEAD~5
# Fix typos in recent commit message
git commit --amend
# Reorder commits logically
git rebase -i main
# Clean up "WIP" commits
git rebase -i --autosquash
Critical Rule: NEVER rebase or amend commits that have been pushed to shared branches. Only rewrite history on your local feature branches.
Using fixup commits for cleaner history:
# Make initial commit
git commit -m "feat: add login form"
# Later, fix something in that commit
git add .
git commit --fixup HEAD
# Before pushing, squash fixup commits
git rebase -i --autosquash main
Security Considerations
Protect your repositories and sensitive information:
Security Checklist:
✓ Never commit passwords, API keys, or secrets
✓ Use environment variables for sensitive data
✓ Review changes before committing
✓ Enable 2FA on GitHub/GitLab
✓ Use SSH keys or personal access tokens
✓ Regularly rotate credentials
✓ Audit repository access permissions
✓ Enable branch protection rules
✓ Require code review before merging
✓ Scan for secrets in commits
Never Commit Secrets
Accidentally committing secrets is a serious security risk:
Common secrets to avoid:
- Database passwords
- API keys and tokens
- Private keys (.pem, .key files)
- OAuth client secrets
- AWS/cloud credentials
- Encryption keys
- Session secrets
If you accidentally commit a secret:
# 1. IMMEDIATELY rotate the exposed credential
# 2. Remove it from Git history (if not yet pushed)
git reset --soft HEAD~1
# Edit files to remove secret
git add .
git commit -m "fix: remove accidentally committed secret"
# 3. If already pushed, use tools like BFG Repo-Cleaner
bfg --replace-text secrets.txt
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# 4. Force push (coordinate with team!)
git push --force-with-lease
Critical: Once a secret is pushed to a public repository, consider it compromised FOREVER. Even if you remove it, it exists in history and can be accessed. Always rotate the credential immediately.
.gitignore Best Practices
Proper .gitignore prevents committing unnecessary or sensitive files:
# Environment and secrets
.env
.env.local
*.key
*.pem
secrets.yml
# Dependencies
node_modules/
vendor/
*.egg-info/
# Build outputs
dist/
build/
*.pyc
*.class
# IDE files
.vscode/
.idea/
*.swp
*.swo
# OS files
.DS_Store
Thumbs.db
# Logs
*.log
logs/
# Temporary files
tmp/
temp/
*.tmp
Global gitignore for personal preferences:
# Configure global gitignore
git config --global core.excludesfile ~/.gitignore_global
# Create ~/.gitignore_global with IDE/OS-specific files
# Example content:
.DS_Store
.vscode/
.idea/
*.swp
Pro Tip: Use
gitignore.io to generate comprehensive .gitignore files for your tech stack.
Large File Strategies
Git is designed for source code, not large binary files. Handle them properly:
Options for Large Files:
1. Don't commit them (best for temporary files)
- Add to .gitignore
- Store in cloud storage (S3, Google Drive)
2. Git LFS (for versioned large files)
- Images, videos, datasets
- Design files (PSD, AI, Sketch)
- Large documentation PDFs
3. Separate repository
- Keep large assets in different repo
- Reference via submodules or package manager
Setting up Git LFS:
# Install Git LFS
git lfs install
# Track large file types
git lfs track "*.psd"
git lfs track "*.ai"
git lfs track "*.mp4"
git lfs track "*.zip"
# Commit the .gitattributes file
git add .gitattributes
git commit -m "chore: configure Git LFS"
# Add and commit large files normally
git add large-file.psd
git commit -m "feat: add design mockup"
git push
Size Limits: GitHub has a 100MB file size limit. Files larger than 50MB will generate warnings. Use Git LFS for files over 10MB.
Performance Best Practices
Keep your Git operations fast and efficient:
# Enable parallel processing
git config --global checkout.workers 8
# Use shallow clones for CI/CD
git clone --depth 1 <url>
# Optimize repository
git gc --aggressive
# Reduce clone size
git clone --single-branch --branch main <url>
# Enable file system monitor (for large repos)
git config core.fsmonitor true
# Enable commit graph for faster operations
git config core.commitGraph true
git commit-graph write --reachable
Code Review Best Practices
Make your commits easy to review:
Before requesting review:
✓ Self-review your changes
✓ Run tests and linters
✓ Update documentation
✓ Squash WIP commits
✓ Write descriptive PR description
✓ Link to related issues
✓ Add screenshots for UI changes
✓ Request specific reviewers
✓ Mark as draft if not ready
Daily Git Workflow Checklist
Follow this daily routine for smooth Git operations:
Morning:
1. git checkout main
2. git pull origin main
3. git checkout <feature-branch>
4. git merge main (or rebase)
Throughout day:
5. git add <files> (stage meaningful changes)
6. git commit -m "meaningful message"
7. Repeat as you complete work units
End of day:
8. git push origin <feature-branch>
9. git status (ensure clean working directory)
Before PR:
10. git rebase -i main (clean up commits)
11. git push --force-with-lease
12. Create pull request
Practice Exercise:
Audit Your Git Practices:
- Review your last 10 commits - do they follow best practices?
- Check your .gitignore - are all necessary files excluded?
- Scan your repository for large files (use du -sh *)
- Create a comprehensive .gitignore for your current project
- Write 3 commit messages following Conventional Commits
- Clean up any merged feature branches
- Set up Git LFS if you have large files
Summary
In this lesson, you learned:
- Commit often and push regularly to protect work
- Keep commits atomic, focused, and well-described
- Write meaningful commit messages using Conventional Commits
- Use branches effectively with clear naming conventions
- Maintain clean history without rewriting shared commits
- Security practices: never commit secrets, use .gitignore
- Handle large files with Git LFS or alternative strategies
- Optimize Git performance for better efficiency
- Follow daily workflow checklist for consistency
Next Up: In the next lesson, we'll explore advanced GitHub features that extend beyond basic Git functionality!