Appendix F: Version Control Systems#
What is Git?#
Git is a distributed version control system that:
Tracks changes — Every edit is recorded with who made it and when
Enables collaboration — Multiple developers work on the same project
Preserves history — You can revert to any previous version
Branches — Develop features independently without affecting main code
Centralized vs Distributed#
Centralized (SVN):
Developer ←→ Central Server
Single source of truth
Requires server access
No offline history
Distributed (Git):
Developer A's Repo ←→ GitHub ←→ Developer B's Repo
Full history on each machine
Works offline
More resilient (multiple backups)
Installing and Configuring Git#
Installation#
macOS (using Homebrew):
$ brew install git
Ubuntu/Debian:
$ sudo apt-get install git
Windows: Download from git-scm.com
Verify Installation#
$ git --version
git version 2.39.2
Configure Git#
Set your identity (used in all commits):
$ git config --global user.name "Your Name"
$ git config --global user.email "you@example.com"
# Verify
$ git config --global user.name
Your Name
# View all settings
$ git config --global --list
Optional: Configure Default Editor#
# Use vim
$ git config --global core.editor vim
# Use nano
$ git config --global core.editor nano
Git Fundamentals#
The Three Stages#
┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ Working Dir │ add │ Staging │ commit│ Repository │
│ (modified) │─────→│ (staged) │──────→│ (committed) │
└──────────────┘ └─────────────┘ └──────────────┘
Working Directory — Your local files (modified but not tracked)
Staging Area — Files marked for commit
Repository — Committed history (.git folder)
Initialize a Repository#
# Create a new project
$ mkdir myproject
$ cd myproject
# Initialize git
$ git init
Initialized empty Git repository in /Users/user/myproject/.git/
# Verify
$ ls -la
total 0
drwxr-xr-x 3 user group 96 Jan 15 myproject
drwxr-xr-x 9 user group 288 Jan 15 .git
Check Repository Status#
# Create a file
$ echo "Hello" > README.md
# Check status
$ git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (tracking)
Basic Git Workflow#
1. Stage Files#
# Stage a specific file
$ git add README.md
# Stage all changes
$ git add .
# Stage with pattern
$ git add *.py
# Check staging area
$ git status
On branch main
Initial commit
Changes to be committed:
(use "rm --cached <file>..." to unstage)
new file: README.md
2. Commit Changes#
# Commit with message
$ git commit -m "Add README"
[main (root-commit) a1b2c3d] Add README
1 file changed, 1 insertion(+)
create mode 100644 README.md
# Commit with detailed message
$ git commit -m "Add README" -m "Includes project description and setup instructions"
# Skip staging, commit all tracked files
$ git commit -am "Update documentation"
3. View History#
# View commits
$ git log
commit a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Author: Your Name <you@example.com>
Date: Mon Jan 15 14:30:00 2024 -0500
Add README
# Condensed view
$ git log --oneline
a1b2c3d Add README
# See what changed in each commit
$ git log -p
# Limit commits
$ git log -5 # Last 5 commits
$ git log --since="2 weeks ago"
4. View Differences#
# Changes in working directory (not staged)
$ git diff
# Changes in staging area
$ git diff --staged
# Differences between commits
$ git diff a1b2c3d..e5f6g7h
# Changes to specific file
$ git diff README.md
Branching and Merging#
Branches allow parallel development without affecting the main codebase.
Understanding Branches#
main: o———o———o (stable, production-ready)
\ \\
feature: o———o———o (new feature under development)
Branch Operations#
# List branches
$ git branch
* main
# Create a new branch
$ git branch feature/login
# Switch to branch
$ git checkout feature/login
Switched to branch 'feature/login'
# Shortcut: create and switch
$ git checkout -b feature/login
Switched to a new branch 'feature/login'
# Make changes and commit
$ echo "login code" > login.py
$ git add login.py
$ git commit -m "Add login functionality"
# Switch back to main
$ git checkout main
Switched to branch 'main'
Merging Branches#
# Merge feature into main
$ git checkout main
$ git merge feature/login
Updating a1b2c3d..e5f6g7h
Fast-forward
login.py | 1 +
1 file changed, 1 insertion(+)
# Delete feature branch (cleanup)
$ git branch -d feature/login
Deleted branch feature/login
Merge Conflicts#
When the same file is edited in different branches:
$ git merge feature/new-ui
Auto-merging app.py
CONFLICT (content): Merge conflict in app.py
# View conflicted file
$ cat app.py
<<<<<<< HEAD
# Main branch version
print("version 1")
=======
# Feature branch version
print("version 2")
>>>>>>> feature/new-ui
# Edit file to resolve
$ echo 'print("version 1 + feature")' > app.py
# Stage and commit
$ git add app.py
$ git commit -m "Resolve merge conflict"
Working with Remote Repositories#
Remote repositories (on GitHub, GitLab, etc.) enable collaboration and backup.
Adding a Remote#
# Add remote (after creating repo on GitHub)
$ git remote add origin https://github.com/username/myproject.git
# Verify
$ git remote -v
origin https://github.com/username/myproject.git (fetch)
origin https://github.com/username/myproject.git (push)
Pushing to Remote#
# Push main branch
$ git push -u origin main
Branch 'main' set up to track remote branch 'main' from 'origin'.
# After setup, just use git push
$ git push
# Push specific branch
$ git push origin feature/login
Pulling from Remote#
# Get changes from remote
$ git pull
remote: Enumerating objects: 3, done.
Updating a1b2c3d..e5f6g7h
Fast-forward
file.py | 2 +-
1 file changed, 1 insertion(+)
# Equivalent to:
$ git fetch # Download changes
$ git merge origin/main # Apply changes
Cloning a Repository#
# Clone existing project
$ git clone https://github.com/username/project.git
Cloning into 'project'...
# Navigate to it
$ cd project
# Verify remote is set up
$ git remote -v
origin https://github.com/username/project.git (fetch)
origin https://github.com/username/project.git (push)
GitHub Basics#
GitHub is a platform for hosting Git repositories and collaborating.
Creating a Repository on GitHub#
Go to github.com and sign in
Click New → New repository
Fill in:
Repository name:
myprojectDescription: (optional)
Public/Private: Choose visibility
Initialize with README: Optional (skip if you have local repo)
Click Create repository
Push Existing Project to GitHub#
# From local project directory
$ git remote add origin https://github.com/username/myproject.git
$ git branch -M main
$ git push -u origin main
GitHub Collaboration#
# Clone a project
$ git clone https://github.com/otheruser/project.git
$ cd project
# Create feature branch
$ git checkout -b feature/my-addition
# Make changes
$ echo "my code" > feature.py
$ git add feature.py
$ git commit -m "Add my feature"
# Push to your fork (if contributing to others' projects)
$ git push origin feature/my-addition
Then create a Pull Request on GitHub to propose changes.
Reading GitHub Project#
# Check out others' branches to test
$ git fetch origin
$ git checkout origin/feature/interesting
# Follow a project without cloning
$ git remote add upstream https://github.com/originalauthor/project.git
$ git fetch upstream # Get their updates
Common Tasks and Tricks#
Undoing Changes#
# Discard changes in working directory
$ git checkout -- file.py
# Unstage file
$ git reset HEAD file.py
# Undo last commit (keep changes)
$ git reset --soft HEAD~1
# Undo last commit (discard changes)
$ git reset --hard HEAD~1
# Revert a commit (create new commit that undoes it)
$ git revert a1b2c3d
Viewing File History#
# Who changed each line
$ git blame file.py
# History of a file
$ git log file.py
# Show specific commit
$ git show a1b2c3d
Stashing Work#
Save work temporarily without committing:
# Save current changes
$ git stash
Saved working directory and index state WIP on main: a1b2c3d Add README
# Switch branches
$ git checkout feature/urgent
# Return to saved work
$ git checkout main
$ git stash pop
Searching History#
# Find commit by message
$ git log --grep="bug fix"
# Find commits that changed a specific line
$ git log -S"function_name" -p
# Find who deleted something
$ git log -S"deleted_text"
Creating Aliases#
# Shorter commands
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
$ git config --global alias.unstage 'reset HEAD --'
# Now use:
$ git co main
$ git ci -m "message"
Best Practices#
Commit Messages#
Good commit messages are:
Concise: First line ≤ 50 characters
Imperative: “Add feature” not “Added feature”
Descriptive: Explain why, not just what
# Good
$ git commit -m "Fix login form validation"
$ git commit -m "Refactor database connection handling"
$ git commit -m "Update dependencies to address security CVE-2024-xxx"
# Bad
$ git commit -m "fixed stuff"
$ git commit -m "asdf"
$ git commit -m "work in progress"
Branching Strategy#
main (always deployable)
↓
release/v1.0 (for fixes before release)
↓
develop (integration branch)
↓
feature/login, feature/signup, bugfix/404 (feature branches)
Workflow:
Create feature branch from
developMake changes and commit
Push to GitHub
Create Pull Request (PR)
Review and merge to
developWhen ready, merge
develop→main
Before Pushing#
# Verify you're on the right branch
$ git status
# Review your changes
$ git diff
# Check log
$ git log -1
# Run tests (if available)
$ npm test # or pytest, etc.
# Then push
$ git push
Keep Local Updated#
# Fetch changes from remote
$ git fetch origin
# Rebase your work on top of latest
$ git rebase origin/main
# Or merge
$ git merge origin/main
Troubleshooting#
“Detached HEAD” State#
# You checked out a commit instead of a branch
$ git checkout a1b2c3d
You are in 'detached HEAD' state
# Fix: Go back to a branch
$ git checkout main
“File already exists in the index”#
# You added a file that already exists
$ git add file.txt
error: The following files have matches:
file.txt
# Use --force or --ignore-all-space
$ git add -f file.txt
Lost Commits#
# View all commits ever made (even "lost" ones)
$ git reflog
a1b2c3d HEAD@{0}: reset: moving to HEAD~1
e5f6g7h HEAD@{1}: commit: Latest work
# Recover the commit
$ git reset --hard e5f6g7h
Need to Check Something in Old Code?#
# Create temporary branch from old commit
$ git checkout -b temp-check a1b2c3d
# Look around
$ cat old-version-file.py
# Go back
$ git checkout main
$ git branch -d temp-check
Quick Reference#
Essential Commands#
Task |
Command |
|---|---|
Setup |
|
Initialize |
|
Status |
|
Stage |
|
Commit |
|
History |
|
Create branch |
|
Switch branch |
|
Merge |
|
Push |
|
Pull |
|
Clone |
|
Where to Learn More#
Git Documentation: git-scm.com/doc
Interactive Tutorial: learngitbranching.js.org
GitHub Guides: guides.github.com
Pro Git Book: git-scm.com/book (free, online)
Practice#
Create a test repository and practice:
$ mkdir git-practice
$ cd git-practice
$ git init
$ echo "test" > file.txt
$ git add file.txt
$ git commit -m "Initial commit"
$ git branch feature
$ git checkout feature
$ echo "feature work" >> file.txt
$ git commit -am "Add feature"
$ git checkout main
$ git merge feature