Hands-on Lab TP2 — Git Fundamentals
Hands-on Lab 45 min Module 01
Objectives
By the end of this lab, you will have practiced:
- Precise staging with
git add -p - Writing professional commit messages
- Exploring history with
git logvariants - Using
git blameto track changes - Undoing changes with
git restore,git reset, andgit revert - Using
git stashto switch contexts
Setup
mkdir git-tp2-fundamentals
cd git-tp2-fundamentals
git init
echo "*.pyc" > .gitignore
echo "__pycache__/" >> .gitignore
Create app.py with this initial content:
def calculate_total(items):
total = 0
for item in items:
total += item['price']
return total
def apply_discount(total, discount_percent):
return total * (1 - discount_percent / 100)
def format_price(amount):
return f"${amount:.2f}"
Create README.md:
# Shopping Cart Application
A Python application for shopping cart management.
## Features
- Calculate totals
- Apply discounts
- Format prices
# Initial commit
git add .
git commit -m "feat: initial shopping cart application"
Part 1: Precise Staging
Update app.py with two different features added at the same time:
def calculate_total(items):
"""Calculate the total price of all items."""
total = 0
for item in items:
total += item['price'] * item.get('quantity', 1) # NEW: quantity support
return total
def apply_discount(total, discount_percent):
"""Apply a percentage discount to a total."""
if discount_percent < 0 or discount_percent > 100:
raise ValueError("Discount must be between 0 and 100") # NEW: validation
return total * (1 - discount_percent / 100)
def format_price(amount, currency="USD"): # NEW: currency parameter
"""Format a price for display."""
symbols = {"USD": "$", "EUR": "€", "GBP": "£"}
symbol = symbols.get(currency, "$")
return f"{symbol}{amount:.2f}"
def calculate_tax(total, tax_rate=0.20): # NEW: tax function
"""Calculate tax on a total."""
return total * tax_rate
Now use interactive staging to create 2 separate commits:
# Use interactive staging
git add -p app.py
# Commit 1: only the quantity and discount validation
git commit -m "feat(cart): add quantity support and discount validation"
# Commit 2: currency and tax function
git add app.py
git commit -m "feat(cart): add multi-currency support and tax calculation"
# Verify you have 3 commits
git log --oneline
Part 2: Exploring History
# View full history
git log
# Compact history
git log --oneline
# History with diff stats
git log --stat
# History with full diff
git log -p --oneline
# Filter by commit message
git log --grep="feat"
git log --grep="validation"
Track a Specific Change
Add this function to the end of app.py:
def apply_coupon(total, coupon_code):
"""Apply a coupon code discount."""
coupons = {
"SAVE10": 10,
"SAVE20": 20,
"WELCOME": 15
}
discount = coupons.get(coupon_code, 0)
return apply_discount(total, discount)
git add app.py
git commit -m "feat(cart): add coupon code system"
# Now find when "apply_discount" first appeared
git log -S "apply_discount" --oneline
# View the exact change
git log -p -S "apply_discount" --oneline
Using git blame
# See who wrote each line
git blame app.py
# Focus on specific lines
git blame -L 1,10 app.py
Part 3: Undoing Changes
3a. Restore Working Tree Changes
# Modify README.md
echo "## WORK IN PROGRESS - DON'T USE YET" >> README.md
# Check status
git status
git diff README.md
# Oops! Discard the change
git restore README.md
# Verify the change is gone
git diff README.md
cat README.md
3b. Unstage a File
# Create a new file accidentally included
echo "my_password=secret123" > secrets.txt
# Add everything by mistake
git add .
git status
# secrets.txt is now staged — oops!
# Unstage it
git restore --staged secrets.txt
git status
# secrets.txt is back to untracked
# Add it to .gitignore so it never happens again
echo "secrets.txt" >> .gitignore
git add .gitignore
git commit -m "chore: add secrets.txt to .gitignore"
3c. Undo a Commit with git reset
# Make a messy commit
echo "# TODO: fix this later" >> app.py
echo "import pdb; pdb.set_trace()" >> app.py
git add app.py
git commit -m "WIP temp commit"
# Oops! Undo but keep the changes in working tree
git reset HEAD~1
git status
# app.py is modified but not committed
# Remove the debug lines, then:
git restore app.py
git status
# Clean working tree, the bad commit is gone
3d. Safe Undo with git revert
Add this broken function to the end of app.py:
def broken_function():
# This function has a critical bug
return 1/0 # Division by zero!
git add app.py
git commit -m "feat: add broken function (simulating a bad publish)"
# We can't use reset because it's "published"
# Use revert to create a safe undo commit
git revert HEAD --no-edit
# Verify the function is gone from app.py
cat app.py
# View the full history
git log --oneline
Part 4: Using git stash
Add this function to the end of app.py:
def loyalty_points(total, multiplier=1.0):
"""Calculate loyalty points earned for a purchase."""
base_points = int(total)
return int(base_points * multiplier)
# You're halfway through and get an urgent request
# DON'T commit half-finished work — use stash!
git status
git stash save "WIP: loyalty points feature"
# Verify working tree is clean
git status
cat app.py # loyalty_points function is gone
# Do the urgent work
echo "# Emergency fix documentation" >> README.md
git add README.md
git commit -m "docs: add emergency fix note"
# Come back to your feature
git stash list
git stash pop
# Verify the feature is back
cat app.py # loyalty_points function is back
# Finish and commit
git add app.py
git commit -m "feat(cart): add loyalty points system"
# Clean up README.md change
git restore README.md
Validation Checklist
- History shows at least 8 commits with meaningful messages
- All commit messages follow the
type: descriptionformat -
git log --onelineshows a clean history - You successfully used
git add -pfor partial staging - You can use
git restore,git reset, andgit revertin the right context - You used
git stashfor context switching
Final History Check
# View complete project history
git log --oneline --stat
# Verify final file state
cat app.py
Expected final functions in app.py:
calculate_total(with quantity)apply_discount(with validation)format_price(with currency)calculate_taxapply_couponloyalty_points
Bonus Challenges
git bisect: Introduce a bug in a new commit, then usegit bisectto find which commit introduced it- Multi-line commits: Redo one of your commits with a detailed body using
git commit --amend git log --format: Create a custom format that shows: hash, author, date, subject
Summary
In this lab you practiced all the core Git fundamentals:
- Precise staging and meaningful commits
- History navigation and search
- Safe and unsafe undo methods
- Context switching with stash
You're ready for Module 02 — Branches & Merge!