Git Essentials: Version Control for Developers

Contents

Git Essentials: Version Control for Developers#

Git is the most important tool in modern software development. Whether youโ€™re working solo or on a team of 1000, Git helps you track changes, collaborate, and never lose work.

What Youโ€™ll Learn#

  • What version control is and why it matters

  • Core Git concepts (commits, branches, repositories)

  • Essential Git commands for daily use

  • Branching and merging workflows

  • Collaborating with GitHub

  • Best practices and common workflows

  • Fixing mistakes and recovering work

๐Ÿ’ก Real-World Analogy#

Think of Git like saving your video game progress:

  • Commits = Save points (you can go back to any save)

  • Branches = Alternate storylines (try different paths without losing main game)

  • Merge = Combining storylines when you find the best path

  • Remote = Cloud save (backup on GitHub/GitLab)


1. What is Version Control?#

Version Control tracks changes to your code over time, allowing you to:

  • See what changed, when, and by whom

  • Revert to any previous version

  • Work on features without breaking the main code

  • Collaborate with others without overwriting each otherโ€™s work

Why Git?#

Before Git:

project_final.py
project_final_v2.py
project_final_v2_actually_final.py
project_final_v2_actually_final_for_real.py

๐Ÿ˜ฑ Sound familiar?

With Git:

project.py (one file, full history preserved!)

๐Ÿ˜Š Clean, organized, powerful!

Git vs GitHub#

Common confusion:

  • Git = Version control tool (runs on your computer)

  • GitHub = Hosting service for Git repositories (like Google Drive for code)

  • Other hosts: GitLab, Bitbucket, Gitea

Git works perfectly fine without GitHub, but GitHub adds collaboration features!


2. Core Git Concepts#

Repository (Repo)#

  • A folder tracked by Git

  • Contains all files + complete history

  • Lives in hidden .git folder

Commit#

  • A snapshot of your project at a point in time

  • Like a save point in a video game

  • Has a unique ID (SHA hash)

  • Contains: changes, message, author, timestamp

Branch#

  • An independent line of development

  • Default branch: main (or master in older repos)

  • Create branches for new features, experiments

Working Directory#

  • Your actual files (what you see and edit)

Staging Area (Index)#

  • Files ready to be committed

  • Lets you choose what to include in next commit

Remote#

  • A version of your repo hosted elsewhere (GitHub, GitLab)

  • Named origin by default

The Three States#

Files in Git can be in three states:

Working Directory โ†’ Staging Area โ†’ Repository
   (modified)         (staged)      (committed)

3. Setting Up Git#

Installation#

Check if Git is installed:

!git --version

If not installed:

  • macOS: brew install git or comes with Xcode

  • Linux: sudo apt install git (Ubuntu/Debian) or sudo yum install git (RedHat/CentOS)

  • Windows: Download from git-scm.com

Initial Configuration#

Set your identity (do this once):

# Set your name (appears in commits)
!git config --global user.name "Your Name"

# Set your email
!git config --global user.email "your.email@example.com"

# Set default branch name to 'main'
!git config --global init.defaultBranch main

# Verify configuration
!git config --list | grep user

Pro Tips:

  • Use the same email as your GitHub account for attribution

  • --global applies to all repos; omit for per-repo settings


4. Creating Your First Repository#

Method 1: Start a New Project#

# Create a new project directory
!mkdir my_project
!cd my_project

# Initialize Git repository
!git init

# Creates a .git folder (hidden)
!ls -la

Method 2: Clone an Existing Repository#

# Clone from GitHub (example)
!git clone https://github.com/username/repo-name.git

# Clone and rename the folder
!git clone https://github.com/username/repo-name.git my-folder-name

5. Basic Git Workflow#

The daily Git cycle:

1. Make changes to files
2. Stage changes (git add)
3. Commit changes (git commit)
4. Push to remote (git push)

Checking Status#

# See what's changed
!git status

# Short format (more concise)
!git status -s

Understanding the output:

?? file.txt          # Untracked (new file)
 M file.txt          # Modified (not staged)
M  file.txt          # Modified (staged)
A  file.txt          # Added (new file, staged)
D  file.txt          # Deleted

Staging Changes#

# Stage a specific file
!git add file.txt

# Stage multiple files
!git add file1.txt file2.txt

# Stage all changes in current directory and subdirectories
!git add .

# Stage all changes in the entire repository
!git add -A

# Stage all modified and deleted files (not new files)
!git add -u

# Interactive staging (choose what to stage)
!git add -p

Committing Changes#

# Commit with message
!git commit -m "Add user authentication feature"

# Commit with multi-line message
!git commit -m "Add user authentication" -m "- Implemented login system" -m "- Added password hashing"

# Stage all tracked files and commit
!git commit -am "Quick fix for bug"

# Open editor for detailed commit message
!git commit

Writing Good Commit Messages#

Bad commits:

git commit -m "fix"
git commit -m "updates"
git commit -m "asdfasdf"

Good commits:

git commit -m "Fix login button alignment on mobile"
git commit -m "Add user profile page with avatar upload"
git commit -m "Refactor database queries for better performance"

Best Practice Format:

Short summary (50 chars or less)

More detailed explanation if needed. Explain what
and why, not how (code shows how).

- Bullet points are fine
- Multiple paragraphs are okay

Fixes #123

Conventional Commits (popular style):

feat: add user registration
fix: resolve login timeout issue
docs: update README with setup instructions
style: format code with black
refactor: simplify authentication logic
test: add tests for user model
chore: update dependencies

6. Viewing History#

# View commit history
!git log

# One-line format (compact)
!git log --oneline

# Show last 5 commits
!git log -5

# Show commits with diff
!git log -p

# Show commits with stats
!git log --stat

# Pretty graph view
!git log --oneline --graph --all --decorate

# Search commits by message
!git log --grep="bug fix"

# Show commits by author
!git log --author="Alice"

# Show commits in date range
!git log --since="2 weeks ago" --until="1 week ago"

Viewing Changes#

# Show unstaged changes
!git diff

# Show staged changes
!git diff --staged
# or
!git diff --cached

# Show changes in specific file
!git diff file.txt

# Compare two commits
!git diff abc123 def456

# Compare branches
!git diff main feature-branch

# Show who changed each line of a file
!git blame file.txt

7. Branching and Merging#

Branches are Gitโ€™s killer feature! They let you work on features without affecting the main code.

Why Branch?#

  • Isolation: Work on features independently

  • Experimentation: Try ideas without risk

  • Collaboration: Multiple people work simultaneously

  • Organization: Separate production code from development

Branch Commands#

# List all branches
!git branch

# List all branches (including remote)
!git branch -a

# Create a new branch
!git branch feature-login

# Switch to a branch
!git checkout feature-login
# or (newer syntax)
!git switch feature-login

# Create and switch in one command
!git checkout -b feature-dashboard
# or
!git switch -c feature-dashboard

# Delete a branch
!git branch -d feature-login

# Force delete (even if not merged)
!git branch -D feature-login

# Rename current branch
!git branch -m new-name

Merging Branches#

Scenario: You finished work on feature-login and want to add it to main

# Switch to the branch you want to merge INTO
!git checkout main

# Merge feature branch into main
!git merge feature-login

# If there are conflicts, Git will tell you
# Fix conflicts, then:
!git add .
!git commit -m "Merge feature-login into main"

Merge Conflicts#

Conflicts occur when the same lines were changed in both branches.

What a conflict looks like:

<<<<<<< HEAD
print("Hello from main branch")
=======
print("Hello from feature branch")
>>>>>>> feature-login

How to resolve:

  1. Open the file

  2. Edit to keep what you want (remove markers)

  3. git add the resolved file

  4. git commit to complete the merge

Tools to help:

git mergetool  # Opens visual merge tool
git merge --abort  # Cancel the merge

8. Working with Remotes (GitHub)#

Adding a Remote#

# Add remote repository
!git remote add origin https://github.com/username/repo.git

# View remotes
!git remote -v

# Remove a remote
!git remote remove origin

# Rename a remote
!git remote rename origin upstream

Pushing Changes#

# Push to remote (first time)
!git push -u origin main

# Push after first time
!git push

# Push specific branch
!git push origin feature-branch

# Push all branches
!git push --all

# Push tags
!git push --tags

What -u does:

  • Sets upstream tracking

  • After this, you can just use git push and git pull

Pulling Changes#

# Fetch + merge in one command
!git pull

# Pull specific branch
!git pull origin main

# Pull with rebase (cleaner history)
!git pull --rebase

Fetching Changes#

# Download changes without merging
!git fetch

# Fetch from specific remote
!git fetch origin

# Fetch all remotes
!git fetch --all

pull vs fetch:

  • fetch: Downloads changes, doesnโ€™t modify your files

  • pull: Downloads changes AND merges them (fetch + merge)


9. Undoing Changes#

Unstaging Files#

# Unstage a file (keep changes)
!git restore --staged file.txt
# or (older way)
!git reset HEAD file.txt

Discarding Changes#

# Discard changes in working directory
!git restore file.txt
# or (older way)
!git checkout -- file.txt

# Discard all changes
!git restore .

# Remove untracked files (be careful!)
!git clean -n  # Dry run (shows what would be deleted)
!git clean -f  # Actually delete

Amending Commits#

# Fix the last commit (change message)
!git commit --amend -m "New message"

# Add forgotten files to last commit
!git add forgotten_file.txt
!git commit --amend --no-edit

# Edit last commit in editor
!git commit --amend

โš ๏ธ Warning: Never amend commits that have been pushed to shared branches!

Reverting Commits#

# Undo a commit by creating a new commit
!git revert abc123

# Revert without committing (stage changes)
!git revert --no-commit abc123

Resetting#

# Soft reset (keep changes staged)
!git reset --soft HEAD~1

# Mixed reset (keep changes unstaged) - DEFAULT
!git reset HEAD~1
!git reset --mixed HEAD~1

# Hard reset (DISCARD all changes) - DANGEROUS!
!git reset --hard HEAD~1

# Reset to specific commit
!git reset --hard abc123

Understanding HEAD~1:

  • HEAD = Current commit

  • HEAD~1 = One commit before current

  • HEAD~2 = Two commits before current

  • HEAD^ = Same as HEAD~1


10. .gitignore: Ignoring Files#

Some files shouldnโ€™t be tracked (secrets, build files, OS files)

Creating .gitignore#

%%writefile .gitignore
# Python
__pycache__/
*.pyc
*.pyo
.pytest_cache/
venv/
.env

# IDEs
.vscode/
.idea/
*.swp

# OS files
.DS_Store
Thumbs.db

# Build outputs
dist/
build/
*.egg-info/

# Logs
*.log

# Secrets
.env
secrets.txt
credentials.json

Patterns:

*.txt          # All .txt files
!important.txt # Except important.txt
folder/        # Entire folder
**/*.log       # .log files in all subdirectories

Get templates: github.com/github/gitignore


11. Common Workflows#

Feature Branch Workflow#

Most common in teams:

# 1. Update main
git checkout main
git pull

# 2. Create feature branch
git checkout -b feature/user-auth

# 3. Work on feature
# ... make changes ...
git add .
git commit -m "Add login endpoint"

# 4. Push feature branch
git push -u origin feature/user-auth

# 5. Create Pull Request on GitHub

# 6. After merge, delete branch
git checkout main
git pull
git branch -d feature/user-auth

Fork and Pull Request (Open Source)#

# 1. Fork repo on GitHub

# 2. Clone your fork
git clone https://github.com/YOUR-USERNAME/repo.git

# 3. Add upstream remote
git remote add upstream https://github.com/ORIGINAL-OWNER/repo.git

# 4. Create branch
git checkout -b fix-typo

# 5. Make changes, commit, push
git push origin fix-typo

# 6. Create Pull Request from your fork to original repo

# 7. Keep fork updated
git fetch upstream
git checkout main
git merge upstream/main

Hotfix Workflow#

For urgent production fixes:

# Create from main/production
git checkout main
git checkout -b hotfix/critical-bug

# Fix, commit, push
git commit -am "Fix critical security issue"
git push origin hotfix/critical-bug

# Merge to main AND develop
git checkout main
git merge hotfix/critical-bug
git checkout develop
git merge hotfix/critical-bug

12. Advanced Tips & Tricks#

Stashing Changes#

# Save work in progress
!git stash

# Stash with message
!git stash save "WIP: refactoring auth"

# List stashes
!git stash list

# Apply most recent stash
!git stash pop

# Apply specific stash
!git stash apply stash@{0}

# Delete stash
!git stash drop stash@{0}

Tagging Releases#

# Create lightweight tag
!git tag v1.0.0

# Create annotated tag (recommended)
!git tag -a v1.0.0 -m "Release version 1.0.0"

# List tags
!git tag

# Push tag to remote
!git push origin v1.0.0

# Push all tags
!git push --tags

# Delete tag
!git tag -d v1.0.0
!git push origin --delete v1.0.0

Rebasing (Advanced)#

# Rebase feature branch onto main
!git checkout feature-branch
!git rebase main

# Interactive rebase (edit history)
!git rebase -i HEAD~3

# Abort rebase if something goes wrong
!git rebase --abort

# Continue after resolving conflicts
!git rebase --continue

Merge vs Rebase:

  • Merge: Preserves history, creates merge commits

  • Rebase: Rewrites history, linear timeline

Golden Rule: Never rebase commits that exist on shared branches!

Useful Aliases#

# Set up useful shortcuts
!git config --global alias.st status
!git config --global alias.co checkout
!git config --global alias.br branch
!git config --global alias.ci commit
!git config --global alias.unstage 'reset HEAD --'
!git config --global alias.last 'log -1 HEAD'
!git config --global alias.lg "log --oneline --graph --all --decorate"

# Now you can use:
# git st  instead of  git status
# git co  instead of  git checkout
# git lg  instead of  git log --oneline --graph --all --decorate

13. Git Best Practices#

Commit Often, Push Regularly#

  • Small, focused commits are better than large ones

  • Commit working code, not broken code

  • Push at least daily to backup work

Write Meaningful Commit Messages#

โœ… Fix: Resolve login timeout on slow networks
โœ… Add: User profile page with avatar upload
โœ… Refactor: Simplify database connection logic

โŒ fix stuff
โŒ updates
โŒ asdf

Use Branches#

  • main should always be stable

  • Create branches for features, bugs, experiments

  • Delete branches after merging

Pull Before Push#

git pull  # Get latest changes
# ... resolve any conflicts ...
git push  # Upload your changes

Never Commit Secrets#

  • No passwords, API keys, tokens in code

  • Use .env files (add to .gitignore)

  • Use secret management tools in production

Review Before Committing#

git diff          # What changed?
git status        # What will be committed?
git commit        # Commit with confidence

Use Pull Requests#

  • Code review catches bugs

  • Knowledge sharing in teams

  • Discussion of implementation

  • Required for most professional teams


14. Troubleshooting Common Issues#

โ€œI committed to the wrong branch!โ€#

# Move commit to correct branch
git log  # Copy commit hash
git checkout correct-branch
git cherry-pick abc123
git checkout wrong-branch
git reset --hard HEAD~1

โ€œI need to undo the last commit!โ€#

# Keep changes
git reset --soft HEAD~1

# Discard changes
git reset --hard HEAD~1

โ€œI have merge conflicts!โ€#

# 1. See which files conflict
git status

# 2. Open conflicted files, resolve manually

# 3. Stage resolved files
git add resolved_file.txt

# 4. Complete merge
git commit

# Or abort the merge
git merge --abort

โ€œI accidentally deleted a file!โ€#

# If not yet committed
git restore file.txt

# If already committed
git checkout HEAD~1 -- file.txt

โ€œHelp! I broke everything!โ€#

# The time machine - see all actions
git reflog

# Go back to before you broke it
git reset --hard abc123

๐Ÿ“ Exercises#

Exercise 1: First Repository#

  1. Create a new folder for a project

  2. Initialize a Git repository

  3. Create a README.md file

  4. Add and commit the file

  5. View the commit history

# Your commands here

Exercise 2: Branching Practice#

  1. Create a branch called feature-test

  2. Switch to that branch

  3. Create a file test.txt

  4. Commit the file

  5. Switch back to main

  6. Merge feature-test into main

  7. Delete the feature branch

# Your commands here

Exercise 3: GitHub Workflow#

  1. Create a new repository on GitHub

  2. Connect your local repo to GitHub

  3. Push your commits

  4. Make a change locally

  5. Commit and push again

# Your commands here

Exercise 4: Undoing Mistakes#

  1. Make a change to a file

  2. Stage it with git add

  3. Unstage it

  4. Make another change

  5. Discard the change

# Your commands here

Exercise 5: .gitignore Practice#

  1. Create a .gitignore file

  2. Add patterns to ignore .log files and a secrets/ folder

  3. Create a test .log file

  4. Run git status and verify itโ€™s ignored

# Your commands here

โœ… Self-Check Quiz#

  1. What is version control?

  2. Whatโ€™s the difference between Git and GitHub?

  3. What is a commit?

  4. What is a branch?

  5. What are the three states in Git?

  6. What does git add do?

  7. Whatโ€™s the difference between git pull and git fetch?

  8. What is a merge conflict?

  9. Why should you never commit secrets?

  10. What does git stash do?


๐ŸŽฏ Key Takeaways#

  • Git tracks changes to code over time

  • Commits are snapshots of your project

  • Branches let you work on features independently

  • Three states: Working Directory โ†’ Staging โ†’ Repository

  • Basic workflow: add โ†’ commit โ†’ push

  • Branches enable parallel development

  • Merge combines branches

  • Remotes (GitHub) backup and enable collaboration

  • .gitignore prevents committing unwanted files

  • Good commits are small, focused, and well-described


๐Ÿš€ Next Steps#

You now know Git! This is a career-changing skill.

Practice by:

  • Using Git for ALL your projects

  • Contributing to open source on GitHub

  • Reading other peopleโ€™s code and commits

Continue learning:

  • Shell Scripting: tools/02_shell_scripting.ipynb

  • Text Editors: tools/04_text_editors.ipynb

  • Debugging: tools/06_debugging_profiling.ipynb


๐Ÿ’ก Pro Tips#

  1. Commit early, commit often - Small commits are easier to understand

  2. Write good messages - Future you will thank you

  3. Branch for everything - main should always work

  4. Pull before push - Avoid conflicts

  5. Use .gitignore - Never commit secrets or build files

  6. Learn to read diffs - Understand what changed

  7. Donโ€™t fear mistakes - Git has many undo mechanisms

  8. Use Pull Requests - Code review makes better code


๐Ÿ“š Resources#

Official Documentation:

Interactive Learning:

Cheat Sheets:

Visual Tools:


Git is not optional - itโ€™s essential! Every professional developer uses it. Master Git and youโ€™ll never lose work again. ๐ŸŽ‰