We are still cooking the magic in the way!
Git & GitHub
Tracking Changes
Tracking Changes
Now that you know the basic Git workflow, let's dive deeper into tracking changes. In this lesson, you'll learn how to use git status effectively, understand different ways to stage files, move and remove files, and control which files Git ignores.
Understanding git status Output
The git status command is your best friend in Git. It shows you exactly what's happening in your repository:
# Check repository status
git status
Typical Output:
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: index.html
modified: style.css
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: script.js
Untracked files:
(use "git add <file>..." to include in what will be committed)
config.json
Breaking Down the Output
1. Branch Information:
"On branch main" - You're currently on the main branch
"Your branch is up to date" - Your local branch matches remote
2. Changes to be committed (Staged):
Files that are staged and ready for commit
• new file: Brand new file added to Git
• modified: Existing file that was changed and staged
3. Changes not staged for commit (Modified):
Files that Git tracks but have unstaged changes
You've modified them but haven't run git add yet
4. Untracked files:
Files Git sees but isn't tracking
New files that have never been added
Compact Status Output
# Short status format
git status -s
git status --short
Output:
M style.css # Staged modification
M script.js # Unstaged modification
A index.html # Staged new file
?? config.json # Untracked file
MM README.md # Modified, staged, then modified again
Status Codes:
?? = Untracked
A = Added (staged new file)
M = Modified
D = Deleted
R = Renamed
C = Copied
MM = Modified in staging and working directory
Pro Tip: Use git status -s for a quick overview, and git status for detailed information with helpful hints.
Different Ways to Stage Files
1. Stage Specific Files
# Stage one file
git add filename.txt
# Stage multiple specific files
git add file1.txt file2.css file3.js
# Stage files with pattern
git add *.html # All HTML files in current directory
git add src/*.js # All JS files in src directory
git add **/*.css # All CSS files recursively
2. Stage All Changes
# Stage all changes in current directory and subdirectories
git add .
# Stage all changes in entire repository (recommended)
git add -A
git add --all
# Stage only modified and deleted files (not new files)
git add -u
git add --update
Difference between git add . and git add -A:
git add .
• Stages everything in current directory and subdirectories
• Relative to your current location
git add -A
• Stages everything in entire repository
• Works from any directory
• More predictable and safer
Recommendation: Use git add -A for consistency
3. Interactive Staging (git add -p)
Stage parts of files rather than entire files:
# Interactive patch mode
git add -p filename.txt
git add --patch
What happens:
Git shows each change (hunk) and asks what to do:
Stage this hunk [y,n,q,a,d,s,e,?]?
y - Yes, stage this hunk
n - No, don't stage this hunk
q - Quit, don't stage this or remaining hunks
a - Stage this and all remaining hunks
d - Don't stage this or remaining hunks
s - Split this hunk into smaller hunks
e - Manually edit this hunk
? - Show help
Example Scenario:
You have one file with two separate bug fixes:
1. Fix for login validation
2. Fix for password reset
Using git add -p:
• Stage fix #1: y
• Don't stage fix #2: n
Result: You can commit fix #1 separately!
This keeps your commits atomic and logical.
Use Case: Interactive staging is perfect when you've made multiple unrelated changes to the same file and want to commit them separately.
4. Interactive Mode (git add -i)
# Full interactive mode
git add -i
git add --interactive
Provides a menu:
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
Allows you to:
• See status
• Stage files interactively
• Unstage files
• Add untracked files
• View diffs
Moving and Renaming Files
# Rename a file
git mv old-name.txt new-name.txt
# Move a file to different directory
git mv file.txt src/file.txt
# Rename and move in one command
git mv old-name.txt src/new-name.txt
What git mv does:
1. Renames/moves the file in working directory
2. Stages the deletion of old file
3. Stages the addition of new file
4. Git recognizes it as a rename (not delete + add)
Why use git mv instead of regular mv?
Regular way (manual):
mv old.txt new.txt
git rm old.txt
git add new.txt
Git way (automatic):
git mv old.txt new.txt
Benefits:
✓ One command instead of three
✓ Git preserves file history
✓ Cleaner commit history
Removing Files
# Remove file from Git and working directory
git rm filename.txt
# Remove file from Git but keep in working directory
git rm --cached filename.txt
# Remove multiple files
git rm *.log
# Remove directory
git rm -r directory-name/
# Force removal (if file has changes)
git rm -f filename.txt
When to use git rm vs rm:
Regular rm:
rm file.txt # Only removes from disk
git add file.txt # Must manually stage deletion
Git rm:
git rm file.txt # Removes and stages in one step
Common Use Cases:
# Accidentally committed sensitive file
git rm --cached .env # Remove from Git, keep locally
# Remove all log files
git rm *.log # Remove completely
# Remove file but keep local copy
git rm --cached temp.txt # Keep for local development
Important: git rm --cached removes the file from Git but keeps it in your working directory. This is useful for files you want to keep locally but not track in Git (like configuration files).
Ignoring Files with .gitignore
Not all files should be tracked by Git. The .gitignore file tells Git which files to ignore:
Creating .gitignore
# Create .gitignore file
touch .gitignore
# Edit with your preferred editor
nano .gitignore
# Add to Git
git add .gitignore
git commit -m "Add .gitignore"
Common .gitignore Patterns
# Example .gitignore file
# Dependencies
node_modules/
vendor/
# Environment files
.env
.env.local
.env.*.local
# Logs
*.log
logs/
npm-debug.log*
# Operating System files
.DS_Store # macOS
Thumbs.db # Windows
*.swp # Vim
# IDE files
.vscode/
.idea/
*.sublime-project
# Build output
dist/
build/
*.min.js
*.min.css
# Temporary files
*.tmp
*.temp
tmp/
# Database files
*.sqlite
*.db
# Compiled files
*.class # Java
*.pyc # Python
*.o # C/C++
# Specific file
config/secret.json
# All files in directory
cache/*
# All .txt files in root only
/*.txt
# Exception: Don't ignore this file
!important.txt
.gitignore Pattern Rules
Pattern Matching:
*.log # Ignore all .log files
build/ # Ignore entire build directory
temp # Ignore temp file or directory
/TODO.txt # Ignore only in root directory
doc/**/*.pdf # Ignore PDFs anywhere under doc/
Negation (Exceptions):
*.log # Ignore all log files
!important.log # But track important.log
Comments:
# This is a comment
# Use # at the start of line
Blank Lines:
Blank lines are ignored (use for organization)
Best Practice: Create .gitignore at the start of your project. It's much easier than removing files later that were accidentally tracked.
What Should You Ignore?
Always Ignore:
✓ Dependencies (node_modules/, vendor/)
✓ Build output (dist/, build/)
✓ Environment variables (.env)
✓ API keys and secrets
✓ Passwords and credentials
✓ Operating system files (.DS_Store)
✓ IDE configuration (.vscode/, .idea/)
✓ Log files (*.log)
✓ Temporary files (*.tmp)
✓ Database files (*.sqlite)
Never Ignore:
✗ Source code
✗ Documentation
✗ Configuration templates (.env.example)
✗ Tests
✗ README files
Global .gitignore
# Set up global .gitignore for all repositories
git config --global core.excludesfile ~/.gitignore_global
# Create the file
touch ~/.gitignore_global
# Add common patterns
echo ".DS_Store" >> ~/.gitignore_global
echo "*.swp" >> ~/.gitignore_global
echo ".vscode/" >> ~/.gitignore_global
Use Case:
Put personal preferences here (IDE, OS files)
Keep project-specific ignores in project .gitignore
Checking Ignored Files
# See which files are ignored
git status --ignored
# Check if specific file is ignored
git check-ignore -v filename.txt
Output shows:
.gitignore:3:*.txt filename.txt
(file, line number, pattern, filename)
# List all ignored files
git ls-files --others --ignored --exclude-standard
Untracking Already-Tracked Files
Problem:
You added a file to .gitignore, but Git still tracks it
(because it was committed before .gitignore was created)
Solution:
# Remove from Git but keep locally
git rm --cached filename.txt
# Remove directory from Git but keep locally
git rm -r --cached directory/
# Remove everything and re-add (nuclear option)
git rm -r --cached .
git add .
# Commit the changes
git commit -m "Remove ignored files from tracking"
Result:
File is no longer tracked but remains on your disk
Important: If a file was previously committed and pushed, it's in Git history. Even after removing it, others can still see it in old commits. Use tools like git-filter-repo to completely remove sensitive data from history.
Template .gitignore Files
GitHub provides templates for different languages/frameworks:
Visit: https://github.com/github/gitignore
Templates available:
• Node.js
• Python
• Java
• Ruby
• PHP
• Laravel
• React
• And 100+ more
Using a template:
1. Visit the repository
2. Find your language/framework
3. Copy the .gitignore content
4. Paste into your .gitignore file
Or use GitHub when creating repository:
• Select "Add .gitignore" dropdown
• Choose your language
Practical Example: Complete Workflow
# Start new project
mkdir my-app && cd my-app
git init
# Create .gitignore first
cat > .gitignore << EOF
node_modules/
.env
*.log
dist/
EOF
# Create project files
echo "console.log('Hello');" > app.js
echo "API_KEY=secret123" > .env
mkdir dist
# Check status
git status
Output:
Untracked files:
.gitignore
app.js
(Notice .env is NOT shown - it's ignored!)
# Stage and commit
git add .
git commit -m "Initial commit with source code"
# Create log file (will be ignored)
echo "Error log" > error.log
# Check status
git status
Output:
nothing to commit, working tree clean
(error.log is ignored)
# Verify ignored files
git status --ignored
Output shows error.log is ignored
Hands-On Exercise:
Practice tracking and ignoring files:
- Create a new Git repository
- Create a .gitignore that ignores *.log and temp/
- Create: index.html, style.css, debug.log, temp/cache.txt
- Run git status and verify .log and temp/ are ignored
- Stage only index.html
- Check status with git status -s
- Stage remaining tracked files
- Commit all changes
Commands:
mkdir test-repo && cd test-repo git init echo -e "*.log\ntemp/" > .gitignore touch index.html style.css debug.log mkdir temp && touch temp/cache.txt git status git add index.html git status -s git add . git commit -m "Add website files"
Summary
In this lesson, you learned:
- How to read and interpret git status output in detail
- Different ways to stage files: specific, all, patterns, interactive
- How to use git add -p for staging parts of files
- Moving and renaming files with git mv
- Removing files with git rm and git rm --cached
- Creating and using .gitignore files
- Common .gitignore patterns and best practices
- How to check which files are ignored
- Untracking previously tracked files
- Using .gitignore templates for different projects
Next Up: In the next lesson, we'll learn about making commits, writing professional commit messages, and amending commits when you make mistakes!