Chapter 14: Time Travel & Multiverses (Version Control / Git)
Learning Objectives
- Understand why saving files normally is completely inadequate for teams.
- Learn the concept of Commits, Branches, and Merges.
- Understand the distributed nature of Git vs central servers.
- Stop naming files
final_final_v2_USE_THIS.py.
Prerequisites
Chapter 11: File I/O.
Why Does This Exist?
You write a great feature on Monday. On Tuesday, you try to add a new button, break everything, and can't remember how to fix it.
You work on a file. Your coworker works on the exact same file. When you both try to save, one of you overwrites the other's work permanently.
Without Version Control, software development is a chaotic nightmare of overwriting, losing work, and fear of making changes.
We needed a system that acts as an indestructible "Undo" button, a time machine, and a collaboration engine.
History
Early systems like CVS and SVN used a single central server. If the server went down, nobody could save their work. If you were on an airplane without WiFi, you couldn't code.
In 2005, Linus Torvalds (creator of Linux) was frustrated by this. Over a weekend, he wrote the first version of Git.
Git is "Distributed". Everyone has a full copy of the entire history on their local laptop. You can work offline, branch, and merge seamlessly.
Mental Model
Think of Git as a Video Game Save System with Alternate Realities.
A Commit is a Save State. You play the game, beat a boss, and save. If you die in the next room, you don't start from the beginning; you just reload the Commit.
A Branch is an Alternate Reality. You create a branch called "Evil Playthrough". You make choices there. Meanwhile, your "Good Playthrough" branch remains completely untouched in a parallel universe. You can switch between them instantly.
A Merge is bringing those realities together.
Internal Working
Git does not just save full copies of your files every time you commit (that would take too much hard drive space).
It acts like a camera taking a snapshot. It calculates a mathematical Hash (SHA-1) of exactly what your files look like at that second.
If you only changed one line of code, Git just saves the "Diff" (the difference: +1 line, -0 lines). It chains these Diffs together into a Directed Acyclic Graph (DAG) using Pointers.
When you checkout an old commit, Git rapidly plays the diffs in reverse to perfectly reconstruct your files as they existed 3 years ago.
Syntax
Git is a command-line tool, not a programming language.
1git init # Creates a new repository here
2git status # Shows what files have changed
3git add my_script.py # Stages the file (prepares for saving)
4git commit -m "Fix bug" # Physically saves the snapshot
5git checkout -b new-ui # Creates a parallel universe (branch)Token breakdown:
init: Creates a hidden.gitfolder to track history.add: Moves files to the "Staging Area". Like putting items in a shipping box.commit: Tapes the box shut and puts it in the warehouse forever, with a message label.checkout: Moves the "HEAD" pointer (your current reality) to a different branch or commit.
Visual Explanation
Tiny Example
The standard developer workflow loop:
1# 1. Edit code in your IDE.
2# 2. Check what you changed:
3git diff
4# 3. Add all changes:
5git add .
6# 4. Save:
7git commit -m "Added login button"Common Mistakes
The Merge Conflict
Why it fails: You change line 10 to say "Blue". Your coworker changes line 10 to say "Red". You both commit. When you try to Merge, Git panics. It is a robot; it cannot decide which color is correct. It halts the merge and throws a "Merge Conflict".
The Fix: Git inserts warning markers into the actual code file (like <<<<<<< HEAD). You must manually open the file, delete the markers, keep the correct line, save, and commit to resolve it.
Debugging
When you break your code and want to go back in time, use git log to see the history.
Every commit has a unique hash (e.g., a1b2c3d4).
You can run git checkout a1b2c3d4.
Instantly, all the files on your hard drive will revert to exactly how they looked at that moment. It feels like magic.
Mini Project
Time: 20 minutes.
Goal: The Time Traveler.
Open a terminal. Create a folder. Run git init. Create a text file. Add "Line 1". Add, commit. Add "Line 2". Add, commit. Run git log, copy the hash of the first commit, and checkout that hash. Open the text file and verify that Line 2 has vanished!
💡 See One Approach (Mini Project)
This is one valid solution — yours may differ.
# Simulating Git concepts in Python (not real Git — for understanding)
class Commit:
def __init__(self, message, parent=None, snapshot=None):
import hashlib, time
self.message = message
self.parent = parent
self.snapshot = snapshot or {}
self.timestamp = time.time()
self.hash = hashlib.sha1(
f"{message}{self.timestamp}".encode()
).hexdigest()[:8]
def __repr__(self):
parent_hash = self.parent.hash if self.parent else "None"
return f"[{self.hash}] {self.message} (parent: {parent_hash})"
class GitSimulator:
def __init__(self):
self.commits = []
self.branches = {"main": None}
self.head = "main"
self.staging = {}
self.working = {}
def add(self, filename, content):
self.staging[filename] = content
print(f" git add {filename}: staged")
def commit(self, message):
snapshot = {**self.working, **self.staging}
parent = self.branches[self.head]
c = Commit(message, parent=parent, snapshot=snapshot)
self.commits.append(c)
self.branches[self.head] = c
self.working.update(self.staging)
self.staging.clear()
print(f" git commit: {c}")
return c
def branch(self, name):
self.branches[name] = self.branches[self.head]
print(f" git branch {name}: created at {self.branches[name].hash if self.branches[name] else 'root'}")
def checkout(self, name):
self.head = name
print(f" git checkout {name}: HEAD now at {name}")
def log(self):
print(f"
=== git log ({self.head}) ===")
current = self.branches[self.head]
while current:
print(f" {current}")
current = current.parent
git = GitSimulator()
git.add("README.md", "# My Project")
git.commit("Initial commit")
git.add("main.py", "print('hello')")
git.commit("Add main script")
git.branch("feature/login")
git.checkout("feature/login")
git.add("auth.py", "def login(): pass")
git.commit("Add login function")
git.log()
git.checkout("main")
git.log()
Bigger Project
Time: 1 hour.
Goal: GitHub Collaboration.
Git is local. GitHub is a website that hosts Git repositories in the cloud. Create a free GitHub account. Create a repository. Link your local folder to it using git remote add origin [URL]. Push your code to the cloud with git push. Have a friend "Clone" it, make a change, push it back, and you "Pull" it down.
💡 See One Approach (Bigger Project)
This is one valid solution — yours may differ.
# Git branching strategy simulator — models a real team workflow
# This is a conceptual simulation, not actual Git commands.
class BranchingStrategy:
"""
Simulates GitFlow:
main ← protected, production
develop ← integration branch
feature/* ← new features
hotfix/* ← emergency prod fixes
"""
BRANCHES = {
"main": "🔒 Production — always deployable",
"develop": "🔧 Integration — features merge here first",
"feature/*":"✨ Feature work — branched from develop",
"hotfix/*": "🚨 Emergency fix — branched from main",
"release/*":"📦 Release prep — branched from develop",
}
@staticmethod
def start_feature(name):
print(f" $ git checkout develop")
print(f" $ git pull origin develop")
print(f" $ git checkout -b feature/{name}")
print(f" ✅ Ready to work on '{name}'
")
@staticmethod
def finish_feature(name):
print(f" $ git checkout develop")
print(f" $ git merge --no-ff feature/{name}")
print(f" $ git push origin develop")
print(f" $ git branch -d feature/{name}")
print(f" ✅ Feature '{name}' merged to develop
")
@staticmethod
def create_release(version):
print(f" $ git checkout develop")
print(f" $ git checkout -b release/{version}")
print(f" # (fix version numbers, run final tests)")
print(f" $ git checkout main && git merge --no-ff release/{version}")
print(f" $ git tag -a v{version} -m 'Version {version}'")
print(f" $ git checkout develop && git merge --no-ff release/{version}")
print(f" ✅ Release {version} shipped to main
")
@staticmethod
def hotfix(version, issue):
print(f" $ git checkout main")
print(f" $ git checkout -b hotfix/{version}")
print(f" # (fix: {issue})")
print(f" $ git checkout main && git merge --no-ff hotfix/{version}")
print(f" $ git tag -a v{version} -m 'Hotfix: {issue}'")
print(f" $ git checkout develop && git merge --no-ff hotfix/{version}")
print(f" ✅ Hotfix deployed!
")
print("=== GitFlow Branching Strategy Demo ===
")
gs = BranchingStrategy()
print("--- Sprint 1: User Authentication ---")
gs.start_feature("user-auth")
gs.finish_feature("user-auth")
print("--- Sprint 1: Dashboard ---")
gs.start_feature("dashboard")
gs.finish_feature("dashboard")
print("--- Release 1.0.0 ---")
gs.create_release("1.0.0")
print("--- Critical Bug Fix ---")
gs.hotfix("1.0.1", "Fix login token expiry calculation")
Production Usage
No software company on earth operates without Git.
At massive scale, companies use "Pull Requests" (PRs). When you finish a feature on your branch, you don't merge it yourself. You open a PR on GitHub. Senior engineers review your code line-by-line, leave comments, and only click "Merge" when it is perfectly safe.
Best Practices
- Commit Often, Commit Small: Don't work for 3 weeks and make one massive commit called "Finished project". If it breaks, you can't undo specific parts. Commit every time you finish a tiny, logical chunk (e.g., "Added button", "Fixed padding").
- Never Commit Secrets: Never commit API keys, database passwords, or AWS tokens. Anyone with access to the repo can read the history forever. Use
.gitignorefiles to hide sensitive files from Git.
Interview Questions
🟢 Easy:What is a .gitignore file?
🔍 Reveal Answer
🟡 Medium:What is the difference between Git and GitHub?
🔍 Reveal Answer
🔴 Hard:What is the difference between git merge and git rebase?
🔍 Reveal Answer
Revision Sheet
- Git: A distributed version control system.
- Commit: A permanent snapshot of your files at a specific moment in time.
- Branch: A parallel universe to test changes without breaking the main code.
- Push/Pull: Sending your local commits to a cloud server (like GitHub) and downloading others' commits.
Connections
- Previous Chapter: Git uses highly optimized Hashing Algorithms (like the ones from Chapter 7) to instantly verify if files have changed.
- Future Chapters: Git tracks code. But what about massive amounts of user data? For that, we need Databases (Chapter 15).