Saltar al contenido principal

Hands-on Lab TP3 — Branches, Merge & Conflict Resolution

Hands-on Lab 60 min Module 02

Objectives

By the end of this lab, you will have:

  • Created and managed multiple branches
  • Performed fast-forward and 3-way merges
  • Intentionally created and resolved a merge conflict
  • Used interactive rebase to clean up history
  • Applied a Git workflow to a simulated project

Part 1: Branch Management

mkdir git-tp3-branches
cd git-tp3-branches
git init

Create app.py with the initial content:

class ShoppingCart:
def __init__(self):
self.items = []

def add_item(self, name, price):
self.items.append({"name": name, "price": price})

def total(self):
return sum(item["price"] for item in self.items)

Create README.md:

# Shopping Cart App

Simple shopping cart implementation in Python.
git add .
git commit -m "feat: initial shopping cart class"

Create Feature Branches

git switch -c feature/discounts
git branch # Verify you're on feature/discounts

Add these methods to app.py (inside the class):

    def apply_discount(self, percent):
"""Apply a percentage discount to the total."""
return self.total() * (1 - percent / 100)

def apply_coupon(self, code):
"""Apply a coupon code."""
coupons = {"SAVE10": 10, "SAVE20": 20}
percent = coupons.get(code, 0)
return self.apply_discount(percent)
git add app.py
git commit -m "feat(cart): add percentage discount method"
git add app.py
git commit -m "feat(cart): add coupon code support"
git switch main
git switch -c feature/tax

Add these tax methods to app.py:

    def calculate_tax(self, rate=0.20):
"""Calculate tax amount on total."""
return self.total() * rate

def total_with_tax(self, rate=0.20):
"""Get total including tax."""
return self.total() + self.calculate_tax(rate)
git add app.py
git commit -m "feat(cart): add tax calculation methods"

View Branch Structure

git log --oneline --graph --all
# Should show: main, feature/discounts, feature/tax

Part 2: Fast-Forward Merge

git switch main

git merge feature/tax
git log --oneline --graph --all
# Notice: no merge commit, linear history

git branch -d feature/tax
git log --oneline --graph --all

Part 3: Three-Way Merge

Add this to README.md:

## Installation

```bash
pip install -r requirements.txt

```bash
git add README.md
git commit -m "docs: add installation instructions"

git merge feature/discounts
git log --oneline --graph --all
# You can see the merge commit with 2 parents

Part 4: Intentional Conflict

git switch -c branch-alice

Replace the entire app.py with Alice's version:

class ShoppingCart:
def __init__(self, currency="USD"):
self.items = []
self.currency = currency # Alice adds currency

def add_item(self, name, price):
self.items.append({"name": name, "price": price})

def total(self):
return sum(item["price"] for item in self.items)

def format_total(self):
symbols = {"USD": "$", "EUR": "€", "GBP": "£"}
symbol = symbols.get(self.currency, "$")
return f"{symbol}{self.total():.2f}"
git add app.py
git commit -m "feat: Alice adds currency support"
git switch main
git switch -c branch-bob

Replace app.py with Bob's version:

class ShoppingCart:
def __init__(self, owner="anonymous"):
self.items = []
self.owner = owner # Bob adds owner

def add_item(self, name, price, quantity=1):
self.items.append({"name": name, "price": price, "qty": quantity})

def total(self):
return sum(item["price"] * item["qty"] for item in self.items)

def summary(self):
return f"Cart for {self.owner}: ${self.total():.2f}"
git add app.py
git commit -m "feat: Bob adds owner and quantity support"
git switch main
git merge branch-alice

# Now merge Bob's work: CONFLICT!
git merge branch-bob

cat app.py
git status

Resolve the Conflict

Edit app.py to combine both features:

class ShoppingCart:
def __init__(self, owner="anonymous", currency="USD"):
self.items = []
self.owner = owner # From Bob
self.currency = currency # From Alice

def add_item(self, name, price, quantity=1):
self.items.append({"name": name, "price": price, "qty": quantity})

def total(self):
return sum(item["price"] * item["qty"] for item in self.items)

def format_total(self):
symbols = {"USD": "$", "EUR": "€", "GBP": "£"}
symbol = symbols.get(self.currency, "$")
return f"{symbol}{self.total():.2f}"

def summary(self):
return f"Cart for {self.owner}: {self.format_total()}"
git add app.py
git commit -m "merge: combine Alice's currency and Bob's owner/quantity features"

git branch -d branch-alice
git branch -d branch-bob

git log --oneline --graph --all

Part 5: Interactive Rebase

git switch -c feature/checkout

Create checkout.py:

def start_checkout(cart):
print("Starting checkout...")
git add checkout.py
git commit -m "WIP checkout"

echo " cart.validate()" >> checkout.py
git add checkout.py
git commit -m "add validation"

echo " process_payment(cart)" >> checkout.py
git add checkout.py
git commit -m "add payment"

echo " print('Done!')" >> checkout.py
git add checkout.py
git commit -m "typo fix"

echo "# Payment processing module" >> checkout.py
git add checkout.py
git commit -m "forgot comment"

git log --oneline
# Shows 5 messy commits

Clean Up History with Interactive Rebase

git rebase -i HEAD~5

# In the editor, change to:
# pick <first> WIP checkout
# squash <second> add validation
# squash <third> add payment
# squash <fourth> typo fix
# squash <fifth> forgot comment

# Write the new combined commit message:
# feat(checkout): add complete checkout flow with validation and payment

git log --oneline
# Now shows only 1 clean commit

git switch main
git merge feature/checkout
git branch -d feature/checkout

Validation Checklist

  • git log --oneline --graph --all shows a clean history
  • At least one fast-forward merge was performed
  • At least one 3-way merge commit is visible in the history
  • The conflict was resolved by combining both features
  • Interactive rebase cleaned up the messy commits
  • All feature branches are deleted

Bonus Challenges

  1. Hotfix simulation: Create a hotfix/critical-bug from main, fix the bug, merge back, then rebase your feature branch to include the fix
  2. git cherry-pick: Create a separate branch, make 3 commits, then cherry-pick only the second commit onto main
  3. Rebase strategy: Compare git log --graph after a merge vs after a rebase of the same branch

Summary

You've practiced the complete branching workflow:

  • Feature branches isolate work cleanly
  • Fast-forward merges create linear history
  • 3-way merges preserve full context
  • Conflicts are normal — resolve them thoughtfully
  • Interactive rebase cleans history before sharing

Ready for Module 03 — GitHub & Remotes!