Pular para o conteúdo principal

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 log variants
  • Using git blame to track changes
  • Undoing changes with git restore, git reset, and git revert
  • Using git stash to 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: description format
  • git log --oneline shows a clean history
  • You successfully used git add -p for partial staging
  • You can use git restore, git reset, and git revert in the right context
  • You used git stash for 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_tax
  • apply_coupon
  • loyalty_points

Bonus Challenges

  1. git bisect: Introduce a bug in a new commit, then use git bisect to find which commit introduced it
  2. Multi-line commits: Redo one of your commits with a detailed body using git commit --amend
  3. 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!