Git Fundamentals for Developers

About This Mentoring Session

This material was created for developer mentoring sessions, designed to teach Git from scratch in a single day. Whether you’re learning through a structured program or self-study, this guide provides a complete foundation with clear explanations and practical examples. The content, flow, and analogies have been refined through real teaching experience to ensure maximum clarity.

If you prefer hands-on practice, check out the companion lab workbook after reading through the concepts here.


What You Will Learn (Day 1)

By the end of Day 1 you will understand:

This is Part 1 of our four-part mentorship series:

  1. Day 1 GuideYou are here. Conceptual foundations of Git and GitHub
  2. Day 1 Lab Workbook — Hands-on exercises for Day 1 topics
  3. Day 2 Guide — Advanced Git techniques (stash, tags, rebase, hooks, and more)
  4. Day 2 Lab Workbook — Hands-on exercises for Day 2 topics

Whether you are brand new to version control or looking to fill gaps in your understanding, this guide gives you the complete mental model you need before writing a single command.

Let us begin.


0. Editor Basics (Vim Quick Commands)

Before diving into Git, there is one prerequisite that trips up many beginners: the text editor that Git opens by default. On most systems, that editor is Vim. You do not need to become a Vim expert, but you do need to know how to save a file, quit, and enter text. Here are the essential commands.

Essential Vim Commands

  • :wq — Save all changes and quit Vim
  • :q! — Quit without saving changes
  • :w — Save changes without quitting
  • i — Enter insert mode (start typing)
  • Esc — Exit insert mode
  • :set number — Show line numbers
  • /searchterm — Search for text

Real-life analogy: Like writing in a notebook — :wq means save and close, :q! means close without saving.

When you will encounter Vim:

  • Git commit messages often open in Vim by default
  • Merge conflict resolution
  • Interactive rebase operations
  • Editing configuration files

Tip: If you prefer a different editor, you can change the default later in the configuration section. Many developers set VS Code as their Git editor with git config --global core.editor "code --wait".


1. Version Control Systems (VCS)

Why Version Control?

Version control systems solve critical problems in software development:

  1. Track changes in files over time
    • See who changed what, when, and why
    • Understand evolution of codebase
  2. Roll back to previous versions
    • Recover from mistakes
    • Compare different versions
  3. Collaborate with multiple developers safely
    • Work simultaneously without conflicts
    • Merge changes intelligently

Real-life analogy: Google Docs version history, but more powerful for code.

If you have ever lost work because you overwrote a file, emailed yourself backup copies, or had two people edit the same document at once, version control is the solution. It is one of those foundational skills — like learning to type or use a terminal — that pays dividends across your entire career.

Types of VCS

1. Local Version Control (LVCS)

How it works:

  • Changes stored in a local database on one machine
  • Simple patch sets applied to files
  • Example: RCS (Revision Control System)

Limitations:

  • No collaboration
  • No backup if disk fails
  • Single point of failure

When it was used:

  • Early days of programming (1980s)
  • Personal projects
  • Single-developer scenarios

2. Centralized Version Control (CVCS)

How it works:

  • Single central server contains all versions
  • Clients check out files from central place
  • Examples:
    • CVS (Concurrent Versions System)
    • SVN (Apache Subversion)
    • Perforce

Advantages:

  • Everyone sees what others are doing
  • Administrators control access
  • Easier to manage than LVCS

Drawback:

  • Server failure = no collaboration
  • No offline work
  • Slow operations (network dependent)
  • Single point of failure

Real-world example:

  • Company has one SVN server
  • If server goes down, no one can commit
  • If server disk corrupts, entire history lost

3. Distributed Version Control (DVCS)

How it works:

  • Every developer has full copy of entire repository
  • Full history available locally
  • Example: Git, Mercurial

Advantages:

  • Offline work – commit, branch, merge without network
  • Faster operations – everything is local
  • Multiple backups – every clone is a full backup
  • Flexible workflows – can have multiple remotes

Git meaning (joke):

  • Global Information Tracker (when it works)
  • Goddamn Idiotic Trash (when it doesn’t)

Real-world scenario:

  • Developer on plane writes code
  • Commits locally during flight
  • Pushes to server after landing
  • No work lost, full history maintained

2. Git Basics

What is Git?

Git is a distributed version control system created by Linus Torvalds in 2005.

Key characteristics:

  • Fast and lightweight
  • Designed for Linux kernel development
  • Handles projects of any size
  • Strong support for branching and merging

Git vs GitHub

  • Git — Software (VCS tool) – runs on your computer
  • GitHub — Online hosting service for Git repositories – web platform

Analogy:

  • Git is like Microsoft Word (software)
  • GitHub is like Google Drive (cloud storage)

This distinction matters. You can use Git without GitHub, and GitHub is not the only hosting option (GitLab, Bitbucket, and others exist). But GitHub is where the majority of open source development happens, which is why it features so prominently in this guide.

Before Git

Previous version control systems:

  • SVN (Subversion) – Centralized VCS
  • Mercurial (Hg) – Distributed VCS, competitor to Git
  • CVS – Older centralized system
  • Perforce – Used in gaming industry

Installation

Windows:

# Download from git-scm.com
# Verify installation
git --version

macOS:

# Using Homebrew
brew install git

# Verify
git --version

Linux:

# Ubuntu/Debian
sudo apt-get install git

# Fedora
sudo dnf install git

# Verify
git --version

GitHub Account

Steps:

  1. Go to github.com
  2. Sign up with email
  3. Verify email address
  4. Set up profile

Why needed:

  • Host repositories online
  • Collaborate with others
  • Showcase your work
  • Contribute to open source

3. Git Terminologies (Detailed)

Understanding the vocabulary is half the battle with Git. This section defines every core term you will encounter throughout this guide and in your daily work. Come back to this section whenever a term feels unfamiliar.

Repository (Repo)

Definition: A directory that Git tracks, containing all files and complete history.

Types:

  • Local Repository – On your computer
  • Remote Repository – On GitHub/GitLab/Bitbucket

Structure:

my-project/         # Working directory
├── .git/           # Hidden folder (Git metadata)
├── src/
├── README.md
└── .gitignore

Working Directory

Definition: The actual files you see and edit in your project folder.

States of files:

  • Untracked – New files Git doesn’t know about
  • Tracked – Files Git is monitoring
  • Unmodified – No changes since last commit
  • Modified – Changed but not staged
  • Staged – Marked for next commit

Staging Area (Index)

Definition: A holding area for changes before committing.

Purpose:

  • Review changes before committing
  • Selectively choose what to commit
  • Create atomic commits

Real-life analogy: Shopping cart before checkout.

Example:

# Modified 3 files: app.js, style.css, README.md
# Only want to commit app.js and style.css
git add app.js style.css  # Add to staging
git commit -m "Updated UI"  # Commit only these two
# README.md still modified but not committed

Commit

Definition: A snapshot of your repository at a specific point in time.

Components:

  • SHA-1 hash – Unique identifier (40 characters)
  • Author – Who made the commit
  • Date – When it was created
  • Message – Description of changes
  • Parent commit(s) – Previous commit(s)
  • Snapshot – Complete state of files

Example:

commit a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
Author: John Doe <john@example.com>
Date:   Mon Feb 6 14:30:00 2026 +0100

    Add user authentication feature

Branch

Definition: An independent line of development, a movable pointer to a commit.

Default branch: main (or master in older repos)

Types:

  • Feature branch – New feature development
  • Bugfix branch – Bug fixes
  • Release branch – Preparing releases
  • Hotfix branch – Emergency fixes

Real-life analogy: Parallel universes in multiverse.


HEAD

Definition: A pointer to the current branch reference, indicating where you are in the repository.

States:

  • Attached HEAD – Points to a branch
  • Detached HEAD – Points directly to a commit (not recommended for work)

Example:

# Normal state
HEAD -> main -> commit abc123

# After switching branch
HEAD -> feature -> commit def456

Remote

Definition: A version of your repository hosted on the internet or network.

Common names:

  • origin – Default name for primary remote
  • upstream – Original repository (in forks)

Commands:

git remote -v                    # List remotes
git remote add origin <url>      # Add remote
git remote remove origin         # Remove remote
git remote rename origin main    # Rename remote

Upstream

Definition: The original repository you forked from.

Usage in open source:

# Your fork: github.com/yourname/project
# Original: github.com/owner/project

git remote add upstream https://github.com/owner/project.git
git fetch upstream               # Get latest changes
git merge upstream/main          # Merge into your branch

Fork

Definition: A copy of someone else’s repository under your GitHub account.

Purpose:

  • Contribute to projects you don’t own
  • Experiment without affecting original
  • Create your own version of a project

Workflow:

  1. Fork on GitHub
  2. Clone your fork
  3. Make changes
  4. Push to your fork
  5. Create Pull Request to original

Clone

Definition: Download a complete copy of a repository from remote to local.

git clone https://github.com/user/repo.git

What it does:

  • Downloads all files
  • Downloads complete history
  • Sets up remote connection
  • Checks out default branch

Pull Request (PR)

Definition: A request to merge your changes into another repository/branch.

Process:

  1. Push branch to GitHub
  2. Open PR on GitHub
  3. Code review by maintainers
  4. Discussion and changes
  5. Approval and merge

Also called: Merge Request (in GitLab)


Merge

Definition: Combining changes from different branches.

Types:

  • Fast-forward – Linear history
  • 3-way merge – Creates merge commit
  • Squash merge – Combines all commits into one

Conflict

Definition: When Git cannot automatically merge changes because same lines were modified.

Causes:

  • Two people edit same line
  • One person deletes file, another modifies it
  • Complex refactoring

Stash

Definition: Temporary storage for uncommitted changes.

When to use:

  • Need to switch branches quickly
  • Pull latest changes without committing
  • Save work in progress

Tag

Definition: A named reference to a specific commit, typically used for releases.

Types:

  • Lightweight tag – Just a name
  • Annotated tag – Contains metadata (recommended)

Submodule

Definition: A Git repository embedded inside another Git repository, allowing you to keep external code separate while including it in your project.

Real-life analogy: Like a reference book kept inside your project folder – the book stays separate but you can access it.

When to use:

  • External dependencies that are independently developed
  • Shared components across multiple projects
  • Third-party libraries you might modify

Example:

git submodule add https://github.com/user/library.git vendor/library
git submodule update --init --recursive

Worktree

Definition: Multiple working directories attached to the same repository, each checking out a different branch simultaneously.

Real-life analogy: Having multiple copies of a book open to different chapters at the same time – work on different parts without losing your place.

When to use:

  • Working on multiple features simultaneously
  • Quick hotfixes without disrupting current work
  • Code reviews while continuing development

Example:

git worktree add ../project-feature feature-branch
git worktree list

Bisect

Definition: A tool that uses binary search to find the commit that introduced a bug.

Real-life analogy: Finding a typo in a 1000-page book by repeatedly checking the middle page – you find it in about 10 checks instead of 1000.

When to use:

  • Bug exists but don’t know when it was introduced
  • Performance degradation over time
  • Finding breaking changes

Example:

git bisect start
git bisect bad           # Current commit has bug
git bisect good abc123   # This old commit was good
# Test, mark as good/bad, repeat until found

Hook

Definition: Scripts that Git executes automatically before or after events like commit, push, or merge.

Real-life analogy: Automatic reminders or checklists that run before you submit a form – ensures you don’t forget important steps.

Common hooks:

  • pre-commit – Run tests before committing
  • commit-msg – Validate commit message format
  • pre-push – Prevent pushing to protected branches

Example:

# Hooks located in .git/hooks/
# pre-commit hook runs automatically before each commit

Alias

Definition: Custom shortcuts for Git commands to increase productivity and save typing.

Real-life analogy: Text shortcuts on your phone – “omw” expands to “On my way!”

When to use:

  • Frequently used commands
  • Complex commands you want to remember
  • Team-wide standard shortcuts

Example:

git config --global alias.co checkout    # Use: git co
git config --global alias.st status      # Use: git st
git config --global alias.lg 'log --oneline --graph'

4. Initial Git Configuration (Detailed)

With Git installed and the vocabulary in place, the next step is configuration. This only needs to happen once per machine, but getting it right saves headaches later. Think of it as setting up your identity badge before entering the building.

Global Configuration

Purpose: Set your identity for all Git repositories on your system.

# Required settings
git config --global user.name "Your Full Name"
git config --global user.email "your.email@example.com"

# Optional but useful settings
git config --global core.editor "code --wait"     # Use VS Code
git config --global init.defaultBranch main       # Default branch name
git config --global color.ui auto                 # Colored output
git config --global pull.rebase false             # Merge strategy

Configuration Levels

1. System level (--system)

  • Applies to all users on the computer
  • Rarely used
git config --system core.editor vim

2. Global level (--global)

  • Applies to all repositories for current user
  • Most commonly used
git config --global user.name "John"

3. Local level (default)

  • Applies only to current repository
  • Overrides global settings
git config user.email "work@company.com"

Viewing Configuration

# List all settings
git config --list

# List with origin
git config --list --show-origin

# Get specific value
git config user.name

# Edit config file directly
git config --global --edit

Useful Configurations

# Set default editor
git config --global core.editor "nano"
git config --global core.editor "vim"
git config --global core.editor "code --wait"

# Set line ending behavior
git config --global core.autocrlf true    # Windows
git config --global core.autocrlf input   # Mac/Linux

# Create aliases
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.visual 'log --oneline --graph --all'

# Now you can use:
git st              # instead of git status
git co main         # instead of git checkout main

5. Git Workflow (Core Concept – Detailed)

This section is arguably the most important in the entire guide. If you understand the three-state model and the flow of changes from working directory to remote repository, every Git command will make intuitive sense. If you skip this section, commands will feel like arbitrary magic.

The Three States

Git has three main states that files can be in:

┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│   Working       │─────>│    Staging      │─────>│   Committed     │
│   Directory     │ add  │     Area        │commit│  (Repository)   │
└─────────────────┘      └─────────────────┘      └─────────────────┘
        │                        │
        └──────────────────> restore <────────────────────┘

Complete Workflow

Working Directory  →  Staging Area  →  Local Repo  →  Remote Repo
        ↓                   ↓               ↓              ↓
      Files            git add        git commit      git push    GitHub/GitLab

Commands Mapping

StageCommandDescription
Modify(edit files)Make changes to files
Stagegit add <file>Add to staging area
Stagegit add .Add all changes
Commitgit commit -m "msg"Save to local repo
Pushgit push origin mainUpload to remote
Pullgit pull origin mainDownload from remote

Detailed Step-by-Step

Step 1: Modify files

# Edit app.js
echo "console.log('Hello');" > app.js

Step 2: Check status

git status
# Shows: modified: app.js (in red)

Step 3: Stage changes

git add app.js
# Or add all: git add .

Step 4: Verify staging

git status
# Shows: modified: app.js (in green)

Step 5: Commit

git commit -m "Add hello world log"

Step 6: Push to remote

git push origin main

Undo at Each Stage

StageUndo CommandEffect
Modified (not staged)git restore <file>Discard changes
Staged (not committed)git restore --staged <file>Unstage
Committed (not pushed)git reset --soft HEAD~1Undo commit, keep changes
Pushedgit revert <commit>Create opposite commit

This undo table is one of the most referenced parts of this guide. Bookmark it.


6. Creating a Git Repository (Detailed)

Method 1: Initialize New Repository

# Create project directory
mkdir my-project
cd my-project

# Initialize Git
git init

# What this does:
# - Creates .git folder
# - Sets up Git data structures
# - Creates default branch (main/master)

What’s inside .git folder:

.git/
├── HEAD              # Points to current branch
├── config            # Repository settings
├── description       # Repository description
├── hooks/            # Git hooks (automation)
├── info/             # Additional info
├── objects/          # All commits, files (database)
├── refs/             # Branch and tag pointers
│   ├── heads/        # Local branches
│   └── tags/         # Tags
└── index             # Staging area

Method 2: Clone Existing Repository

# Clone from GitHub
git clone https://github.com/username/repo.git

# Clone with different name
git clone https://github.com/username/repo.git my-project

# Clone specific branch
git clone -b develop https://github.com/username/repo.git

First Steps After Init

# 1. Check status
git status
# Output: On branch main, No commits yet, nothing to commit

# 2. Create initial files
echo "# My Project" > README.md
echo "node_modules/" > .gitignore

# 3. Check status again
git status
# Output: Untracked files: README.md, .gitignore

# 4. Stage files
git add .

# 5. Create first commit
git commit -m "Initial commit"

# 6. Verify
git log

Common Initial Commit Workflow

# Full initial setup
git init
echo "# Project Name" > README.md
echo "node_modules/
.env
*.log" > .gitignore
git add .
git commit -m "Initial commit: Add README and gitignore"

7. Viewing History (Detailed)

Once you start making commits, knowing how to navigate and read history becomes essential. Git provides powerful log and show commands that let you inspect any point in your project’s timeline. Mastering these commands is what separates someone who uses Git from someone who understands Git.

Basic Log Commands

# Full log
git log

# Output:
commit a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
Author: John Doe <john@example.com>
Date:   Mon Feb 6 14:30:00 2026 +0100

    Add user authentication feature
# Compact one-line log
git log --oneline

# Output:
a3f2b1c Add user authentication
b2c3d4e Fix login bug
c4d5e6f Update README

Advanced Log Options

# Show last 5 commits
git log -5

# Show commits with file changes
git log --stat

# Show commits with actual code changes
git log -p
git log --patch

# Show graph of branches
git log --graph --oneline --all

# Beautiful graph
git log --graph --oneline --decorate --all

# Filter by author
git log --author="John"

# Filter by date
git log --since="2 weeks ago"
git log --after="2026-01-01"
git log --before="2026-02-01"

# Filter by commit message
git log --grep="fix"

# Show commits that changed specific file
git log -- path/to/file.js

# Show commits in date range
git log --since="2026-01-01" --until="2026-02-01"

Custom Log Format

# Custom format
git log --pretty=format:"%h - %an, %ar : %s"

# Output:
a3f2b1c - John Doe, 2 hours ago : Add authentication
b2c3d4e - Jane Smith, 1 day ago : Fix bug

# Format placeholders:
# %h  - Abbreviated commit hash
# %H  - Full commit hash
# %an - Author name
# %ae - Author email
# %ad - Author date
# %ar - Author date, relative (e.g., "2 hours ago")
# %s  - Commit message subject
# %b  - Commit message body

Viewing Specific Commit

# Show complete commit details
git show a3f2b1c

# Show specific file from commit
git show a3f2b1c:path/to/file.js

# Show files changed in commit
git show --name-only a3f2b1c

# Show commit statistics
git show --stat a3f2b1c

Best Practice: Atomic Commits

What is an atomic commit?

  • One logical change = One commit
  • Easy to understand
  • Easy to revert
  • Clear history

Bad example:

git commit -m "Fixed bugs and added features and updated docs"

Good example:

git commit -m "Fix login validation bug"
git commit -m "Add password reset feature"
git commit -m "Update API documentation"

Commit Message Best Practices:

# Format: <type>: <description>

# Examples:
git commit -m "feat: Add user registration"
git commit -m "fix: Resolve null pointer exception in login"
git commit -m "docs: Update installation instructions"
git commit -m "refactor: Simplify authentication logic"
git commit -m "test: Add unit tests for user service"

# Types:
# feat      - New feature
# fix       - Bug fix
# docs      - Documentation
# style     - Formatting, no code change
# refactor  - Code restructuring
# test      - Adding tests
# chore     - Maintenance

Good commit messages are a form of documentation. When you need to understand why a change was made six months from now, the commit message is often the first place you look. Treat them as part of your code quality practice, just like you would treat naming variables or writing clear comments.


8. Ignoring and Tracking Files (Detailed)

.gitignore Purpose

What it does: Tells Git which files/folders to NOT track.

Why needed:

  • Avoid committing sensitive data (.env files)
  • Exclude build artifacts (node_modules, dist/)
  • Skip OS-specific files (.DS_Store, Thumbs.db)
  • Ignore IDE settings (.vscode/, .idea/)

Security matters here. Accidentally committing a .env file with API keys or database credentials is one of the most common mistakes developers make, and it can have serious consequences.

Creating .gitignore

# Create file
touch .gitignore

# Add patterns
echo "node_modules/" >> .gitignore
echo ".env" >> .gitignore
echo "*.log" >> .gitignore

.gitignore Patterns

# Ignore specific file
secret.txt

# Ignore all files with extension
*.log
*.tmp

# Ignore folder
node_modules/
dist/
build/

# Ignore files in any directory
**/*.log

# Ignore all .txt files except one
*.txt
!important.txt

# Ignore files only in root
/config.json

# Ignore all .md files in docs directory
docs/*.md

# Comments
# This is a comment

Complete .gitignore Example

# Dependencies
node_modules/
vendor/
bower_components/

# Environment variables
.env
.env.local
.env.production

# Build outputs
dist/
build/
out/
*.min.js
*.min.css

# Logs
logs/
*.log
npm-debug.log*

# Operating System
.DS_Store
Thumbs.db
desktop.ini

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# Testing
coverage/
.nyc_output/

# Temporary files
tmp/
temp/
*.tmp

# Compiled files
*.class
*.pyc
*.o
*.exe

Global .gitignore

For OS/IDE files across all projects:

# Create global gitignore
git config --global core.excludesfile ~/.gitignore_global

# Edit the file
nano ~/.gitignore_global

# Add patterns:
.DS_Store
Thumbs.db
.idea/
.vscode/

Untracking Already Committed Files

# Stop tracking file but keep it locally
git rm --cached filename

# Stop tracking folder
git rm -r --cached folder/

# Example: Accidentally committed .env
git rm --cached .env
echo ".env" >> .gitignore
git add .gitignore
git commit -m "Remove .env from tracking"

.gitkeep for Empty Folders

Problem: Git doesn’t track empty folders.

Solution: Add .gitkeep file.

# Create empty directory structure
mkdir -p logs/error
mkdir -p logs/access

# Git won't track these empty folders
git status  # Won't show logs/

# Add .gitkeep files
touch logs/error/.gitkeep
touch logs/access/.gitkeep

# Now Git tracks the structure
git add logs/
git commit -m "Add log directory structure"

When to use .gitkeep:

  • Required folder structure for application
  • Output directories for logs
  • Upload directories that start empty

Checking Ignored Files

# See which files are ignored
git status --ignored

# Check if specific file is ignored
git check-ignore -v filename

# Example output:
.gitignore:3:*.log    debug.log
# Shows: file .gitignore, line 3, pattern *.log matches debug.log

9. Git Behind the Scenes (Detailed)

You do not need to understand Git internals to use Git effectively, but understanding how it works under the hood will deepen your intuition and make troubleshooting far easier. This section lifts the curtain on what happens inside the .git directory.

Git Object Model

Git stores everything as objects in .git/objects/ directory.

Four types of objects:

  1. Blob (Binary Large Object)
    • Stores file content
    • Identified by SHA-1 hash of content
  2. Tree
    • Represents a directory
    • Contains blobs and other trees
    • Like a snapshot of file structure
  3. Commit
    • Points to a tree
    • Contains metadata (author, date, message)
    • Points to parent commit(s)
  4. Tag
    • Points to a commit
    • Contains additional information

How Git Stores a Commit

Commit Object (a3f2b1c)
├── Tree (def456)
│   ├── Blob (abc123) - README.md content
│   ├── Blob (789xyz) - app.js content
│   └── Tree (456abc) - src/ directory
│       └── Blob (xyz789) - index.js content
├── Parent: b2c3d4e
├── Author: John Doe
├── Date: 2026-02-06
└── Message: "Add authentication"

SHA-1 Hashing

# Git uses SHA-1 to create unique identifiers
# Example: a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3

# Content → Hash
echo "Hello Git" | git hash-object --stdin
# Output: 8d0e41234f24b6da002d962a26c2495ea16a4254

# Same content = Same hash (content-addressable storage)

Viewing Git Objects

# List all objects
find .git/objects -type f

# View object type
git cat-file -t a3f2b1c

# View object content
git cat-file -p a3f2b1c

# Example output for commit:
tree def456abc789
parent b2c3d4e5f6a7
author John Doe <john@example.com> 1675694400 +0100
committer John Doe <john@example.com> 1675694400 +0100

Add user authentication

How Git Stores Changes Efficiently

Git uses:

  1. Content-addressable storage
    • Objects identified by content hash
  2. Compression
    • Objects are zlib compressed
  3. Packing
    • Similar objects stored as deltas (differences)
# View repository size
du -sh .git

# Garbage collection and optimization
git gc

# Aggressive optimization
git gc --aggressive --prune=now

HEAD File

# View HEAD
cat .git/HEAD
# Output for normal state:
ref: refs/heads/main
# This means HEAD → main branch → commit

# View where main points
cat .git/refs/heads/main
# Output: a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3

10. Branching in Git (Detailed)

Branching is one of Git’s most powerful features and the foundation of every collaborative workflow. If the three-state model is the engine of Git, branching is the steering wheel. Understanding it well will shape how you work on teams and how you structure your own projects.

What is a Branch?

Technical definition: A lightweight movable pointer to a commit.

Practical definition: An independent line of development.

Why Use Branches?

  1. Feature development – Work on new features without affecting main code
  2. Bug fixes – Fix bugs in isolation
  3. Experimentation – Try new ideas safely
  4. Collaboration – Multiple people work simultaneously
  5. Release management – Maintain multiple versions

Branch Commands (Comprehensive)

# List all local branches
git branch

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

# List only remote branches
git branch -r

# Create new branch
git branch feature-login

# Create and switch to new branch
git switch -c feature-login
# OR (older syntax)
git checkout -b feature-login

# Switch to existing branch
git switch main
# OR
git checkout main

# Rename current branch
git branch -m new-name

# Rename other branch
git branch -m old-name new-name

# Delete branch (safe - won't delete if unmerged)
git branch -d feature-login

# Force delete branch (even if unmerged)
git branch -D feature-login

# Delete remote branch
git push origin --delete feature-login

# View last commit on each branch
git branch -v

# View merged branches
git branch --merged

# View unmerged branches
git branch --no-merged

Branch Workflows

1. Feature Branch Workflow

# Start new feature
git switch -c feature-user-profile

# Work on feature
# ... edit files ...
git add .
git commit -m "Add user profile page"

# More commits...
git commit -m "Add profile editing"

# Switch back to main
git switch main

# Merge feature
git merge feature-user-profile

# Delete feature branch
git branch -d feature-user-profile

2. Gitflow Workflow

main (production)
├── develop (integration)
│   ├── feature/login
│   ├── feature/signup
│   └── feature/profile
├── release/v1.0
└── hotfix/critical-bug

3. GitHub Flow (Simpler)

main
├── feature/add-api
├── feature/ui-update
└── bugfix/login-error

Viewing Branch History

# Visualize all branches
git log --graph --oneline --all

# Output example:
* a3f2b1c (HEAD -> main) Merge feature-login
|\
| * b2c3d4e (feature-login) Add login form
| * c4d5e6f Add validation
|/
* d5e6f7a Initial commit

# Show branch relationships
git show-branch

# Compare branches
git diff main..feature-login

When to Create a Branch

Always create a branch when:

  • Starting new feature
  • Fixing a bug
  • Experimenting with code
  • Working collaboratively
  • Making any significant change

Stay on main when:

  • Making quick hotfixes (though branch is still better)
  • Never – always use branches!

Real-world analogy:

  • Main branch = Published book
  • Feature branch = Draft manuscript
  • Merge = Publishing new edition

11. Undo and Restore (Comprehensive)

Mistakes happen. What separates productive developers from frustrated ones is knowing exactly which undo command to reach for. Git gives you multiple tools for different situations, and choosing the wrong one can make things worse. This section maps every possible mistake to the correct recovery command.

Understanding the States

Untracked  →  Modified  →  Staged  →  Committed  →  Pushed
    ↓           ↓           ↓           ↓            ↓
(delete)     restore    restore     reset/        revert
                        --staged     revert

1. Restore (Uncommitted Changes)

Discard changes in working directory:

# Restore single file (discard changes)
git restore app.js

# Restore all files
git restore .

# What it does:
# - Reverts file to last committed state
# - CAUTION: Changes are permanently lost!

Unstage files (keep changes):

# Remove from staging, keep modifications
git restore --staged app.js

# Unstage all
git restore --staged .

# What it does:
# - Moves file from staging to modified state
# - Changes still exist in working directory

Combined example:

# Scenario: Modified and staged app.js, want to discard
git restore --staged app.js   # Unstage
git restore app.js             # Discard changes

# Shorter (discard directly):
git restore app.js             # Discards even if staged

2. Reset (Before Push – Rewrite History)

Three types of reset:

a) Soft Reset

git reset --soft HEAD~1

# What it does:
# - Moves HEAD back 1 commit
# - Keeps changes in staging area
# - File modifications preserved
# - Use when: Want to recommit with better message

b) Mixed Reset (default)

git reset HEAD~1
# OR
git reset --mixed HEAD~1

# What it does:
# - Moves HEAD back 1 commit
# - Keeps changes in working directory (unstaged)
# - Use when: Want to reorganize commits

c) Hard Reset

git reset --hard HEAD~1

# What it does:
# - Moves HEAD back 1 commit
# - DELETES all changes
# - Working directory = that commit
# - CAUTION: Destructive! Use with care

Reset to specific commit:

# Reset to specific commit hash
git reset --soft a3f2b1c
git reset --mixed b2c3d4e
git reset --hard c4d5e6f

# Reset to 3 commits back
git reset --soft HEAD~3

3. Revert (After Push – Safe Undo)

# Create new commit that undoes changes
git revert HEAD

# Revert specific commit
git revert a3f2b1c

# Revert multiple commits
git revert HEAD~3..HEAD

# Revert without committing (review first)
git revert -n HEAD

# What it does:
# - Creates NEW commit
# - Opposite changes of specified commit
# - Doesn't rewrite history
# - Safe for shared/pushed commits

4. Clean (Remove Untracked Files)

# See what would be deleted (dry run)
git clean -n

# Delete untracked files
git clean -f

# Delete untracked files and directories
git clean -fd

# Delete ignored files too
git clean -fdx

# Interactive mode (choose what to delete)
git clean -i

Comparison Table

CommandScopeSafetyUse When
git restore <file>Working dirDestructiveDiscard local changes
git restore --stagedStagingSafeUnstage files
git reset --softCommitsSafeRedo commit message
git reset --mixedCommitsSafeReorganize commits
git reset --hardEverythingDestructiveCompletely undo
git revertCommitsSafeUndo pushed commits
git cleanUntrackedDestructiveRemove untracked files

Recovery from Mistakes

# OH NO! I did git reset --hard by mistake!
# Don't panic, use reflog

# View all HEAD movements
git reflog

# Output:
a3f2b1c HEAD@{0}: reset: moving to HEAD~1
b2c3d4e HEAD@{1}: commit: Add feature
c4d5e6f HEAD@{2}: commit: Fix bug

# Restore to before reset
git reset --hard HEAD@{1}
# Now back to commit b2c3d4e!

When to Use Each Command

ScenarioCommand
Typo in file, not stagedgit restore file.txt
Staged wrong filegit restore --staged file.txt
Bad commit message, not pushedgit reset --soft HEAD~1 then recommit
Want to reorganize last 3 commitsgit reset --mixed HEAD~3
Completely undo last commitgit reset --hard HEAD~1
Undo commit that’s already pushedgit revert HEAD
Remove all uncommitted changesgit restore . && git clean -fd

12. Git Diff (Comprehensive)

What is Git Diff?

Definition: Shows differences between files, commits, branches, or states.

Purpose:

  • Review changes before staging
  • Compare different versions
  • Review what’s being committed
  • Compare branches

If git log tells you what changed, git diff tells you how it changed. Together they give you complete visibility into your project’s evolution.

Basic Diff Commands

1. Working Directory vs Staging

# Show unstaged changes
git diff

# Example output:
diff --git a/app.js b/app.js
index a3f2b1c..b2c3d4e 100644
--- a/app.js
+++ b/app.js
@@ -1,3 +1,4 @@
 function login() {
   console.log("Login");
+  validateUser();
 }

# Meaning:
# - Lines removed (red)
# + Lines added (green)
# @@ Line numbers @@

2. Staging vs Last Commit

# Show staged changes (what will be committed)
git diff --staged
# OR
git diff --cached

# Shows what's in staging area vs HEAD

3. Working Directory vs Commit

# Compare current state with specific commit
git diff a3f2b1c

# Compare with HEAD (last commit)
git diff HEAD

# Compare with 2 commits ago
git diff HEAD~2

Comparing Commits

# Compare two commits
git diff a3f2b1c..b2c3d4e
# OR
git diff a3f2b1c b2c3d4e

# Show only file names that changed
git diff --name-only a3f2b1c..b2c3d4e

# Show file names with status
git diff --name-status a3f2b1c..b2c3d4e
# Output:
# M    modified.txt
# A    added.txt
# D    deleted.txt

# Show statistics
git diff --stat a3f2b1c..b2c3d4e
# Output:
#  app.js    | 10 +++++----- 
#  style.css |  3 +++
#  2 files changed, 8 insertions(+), 5 deletions(-)

Comparing Branches

# Compare current branch with main
git diff main

# Compare two branches
git diff main..feature-login

# Show only files that differ
git diff --name-only main..feature-login

# Show what's in feature but not in main
git diff main...feature-login

# Three-dot vs two-dot:
# Two dots (..)  : Compare branch tips directly
# Three dots (...): Compare from common ancestor

Diff for Specific Files

# Diff for single file
git diff app.js

# Diff for specific file between commits
git diff a3f2b1c..b2c3d4e -- app.js

# Diff for all files in directory
git diff src/

# Diff for files matching pattern
git diff '*.js'

Advanced Diff Options

# Ignore whitespace changes
git diff -w
# OR
git diff --ignore-all-space

# Show word-by-word diff
git diff --word-diff

# Show function names with changes
git diff --function-context

# Colorful diff with highlighting
git diff --color-words

# Show diff with more context (default 3 lines)
git diff -U10  # 10 lines of context

# Minimal diff (fewest changes)
git diff --minimal

Understanding Diff Output

diff --git a/app.js b/app.js           ← File being compared
index a3f2b1c..b2c3d4e 100644          ← Hash IDs and file mode
--- a/app.js                            ← Original file
+++ b/app.js                            ← Modified file
@@ -1,3 +1,4 @@                         ← Line numbers: old(1,3) new(1,4)
 function login() {                     ← Unchanged line
   console.log("Login");                ← Unchanged line
+  validateUser();                      ← Added line (green)
 }                                      ← Unchanged line

Diff Statistics

# Summary of changes
git diff --shortstat
# Output: 2 files changed, 10 insertions(+), 3 deletions(-)

# Detailed statistics
git diff --stat
# Output:
#  app.js    | 10 +++++----- 
#  README.md |  3 +++
#  style.css |  5 -----
#  3 files changed, 13 insertions(+), 8 deletions(-)

# Numerical statistics
git diff --numstat
# Output:
# 10    5    app.js
# 3     0    README.md
# 0     5    style.css

Diff Tools (External)

# Use external diff tool
git difftool

# Configure diff tool (e.g., VS Code)
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'

# Other popular tools:
# - meld
# - kdiff3
# - Beyond Compare
# - vimdiff

When to Use Git Diff

ScenarioCommand
Review before staginggit diff
Review before committinggit diff --staged
Compare with last commitgit diff HEAD
Compare branchesgit diff main..feature
Review specific filegit diff path/file.js
See what changed in commitgit show a3f2b1c
Compare two commitsgit diff abc123..def456

13. Git Show (Comprehensive)

What is Git Show?

Definition: Display detailed information about Git objects (commits, tags, trees).

Primary use: Inspect complete details of a specific commit.

Basic Show Commands

1. Show Last Commit

# Show HEAD (last commit)
git show

# Output:
commit a3f2b1c5d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3
Author: John Doe <john@example.com>
Date:   Mon Feb 6 14:30:00 2026 +0100

    Add user authentication feature

diff --git a/auth.js b/auth.js
new file mode 100644
index 0000000..a3f2b1c
--- /dev/null
+++ b/auth.js
@@ -0,0 +1,5 @@
+function authenticate(user) {
+  // authentication logic
+}

2. Show Specific Commit

# By commit hash
git show a3f2b1c

# By relative reference
git show HEAD~1    # Previous commit
git show HEAD~2    # 2 commits ago
git show HEAD^     # Parent of HEAD

# By branch
git show main
git show feature-login

Show Specific Files

# Show file as it was in specific commit
git show a3f2b1c:path/to/file.js

# Show file from HEAD
git show HEAD:app.js

# Show file from different branch
git show feature:app.js

# Show file from tag
git show v1.0:README.md

Show Options

1. Show Only Changes (No Diff)

# Show commit metadata only
git show --no-patch a3f2b1c
# OR
git show -s a3f2b1c

# Output: Just commit info, no diff

2. Show Only File Names

# List files changed in commit
git show --name-only a3f2b1c

# Output:
# commit a3f2b1c...
# Author: John Doe...
#
# Add authentication
#
# auth.js
# login.js
# config.js

3. Show File Names with Status

# Show file names with change status
git show --name-status a3f2b1c

# Output:
# A    auth.js      (Added)
# M    login.js     (Modified)
# D    old-auth.js  (Deleted)

4. Show Statistics

# Show change statistics
git show --stat a3f2b1c

# Output:
# commit a3f2b1c...
#
#  auth.js   | 45 +++++++++++++++++++++++++++++ 
#  login.js  | 12 ++++++---
#  config.js |  3 ++-
#  3 files changed, 56 insertions(+), 4 deletions(-)

Show Tags

# Show annotated tag
git show v1.0

# Output:
# tag v1.0
# Tagger: John Doe <john@example.com>
# Date:   Mon Feb 6 14:30:00 2026 +0100
#
# Release version 1.0
#
# commit a3f2b1c...
# (shows commit details)

Show Tree Objects

# Show tree (directory listing) from commit
git show a3f2b1c^{tree}

# Show specific directory
git show a3f2b1c:src/

# Show blob (file content)
git show a3f2b1c:app.js

Show with Formatting

# Custom format
git show --pretty=format:"%h - %an, %ar : %s" a3f2b1c

# Show only specific parts
git show --format="%an %ae" --no-patch a3f2b1c
# Output: John Doe john@example.com

# Show with color
git show --color a3f2b1c

Show Multiple Commits

# Show multiple commits
git show a3f2b1c b2c3d4e

# Show range
git show HEAD~3..HEAD

# Show last 2 commits
git show HEAD~2..HEAD

Comparing Show vs Diff

Featuregit showgit diff
PurposeView single commitCompare two states
DefaultShows last commitShows unstaged changes
OutputCommit info + diffJust diff
UsageInspect commitsCompare versions

Practical Show Examples

1. Quick commit inspection

# What changed in last commit?
git show --stat

# Who made this commit?
git show --format="%an <%ae>" --no-patch

# When was this commit made?
git show --format="%ad" --no-patch

2. Review specific commit

# Full details of a commit
git show a3f2b1c

# Just see what files changed
git show --name-status a3f2b1c

# See file as it was then
git show a3f2b1c:old-version.js

3. Debugging

# Check file state in previous version
git show HEAD~5:src/bug.js

# Compare file between commits
git show commit1:file.js > /tmp/old.js
git show commit2:file.js > /tmp/new.js
diff /tmp/old.js /tmp/new.js

When to Use Git Show

ScenarioCommand
View last commit detailsgit show
Inspect specific commitgit show a3f2b1c
See file from commitgit show a3f2b1c:file.js
Check what changedgit show --stat
View tag informationgit show v1.0
Quick commit summarygit show --no-patch

14. When to Use Which Command (Decision Guide)

This section ties everything together. When you are in the middle of work and something goes wrong, you do not want to read through entire sections — you want a quick answer. Use the tables below as a rapid reference. Bookmark this section.

Scenario-Based Command Selection

Scenario 1: Want to see my uncommitted changes

# See what you modified (unstaged)
git diff

# See what you staged
git diff --staged

Scenario 2: Review specific commit

# See full commit details
git show a3f2b1c

# See only what files changed
git show --name-status a3f2b1c

Scenario 3: Compare branches

# See differences between branches
git diff main..feature

# See divergence from common ancestor
git diff main...feature

Scenario 4: Undo mistakes

# Discard uncommitted changes
git restore file.txt

# Undo last commit (keep changes)
git reset --soft HEAD~1

# Undo pushed commit (safe)
git revert HEAD

Scenario 5: View history

# See all commits
git log --oneline

# See commit graph
git log --graph --all --oneline

# See last commit
git show

Command Cheat Sheet by Purpose

VIEWING CHANGES:

git status            # What's changed overall
git diff              # Unstaged changes
git diff --staged     # Staged changes
git show              # Last commit details
git show a3f2b1c      # Specific commit
git log               # Commit history

MAKING CHANGES:

git add <file>        # Stage changes
git commit            # Save snapshot
git restore           # Discard changes
git reset             # Undo commits (local)
git revert            # Undo commits (safe)

BRANCHING:

git branch            # List/create branches
git switch            # Change branches
git merge             # Combine branches
git rebase            # Reapply commits

COLLABORATION:

git clone             # Download repository
git pull              # Get updates
git push              # Share changes
git fetch             # Download without merge

Usage Summary Tables

File State Commands

Current StateWant toCommand
ModifiedDiscard changesgit restore file
ModifiedStage changesgit add file
StagedUnstagegit restore --staged file
StagedCommitgit commit -m "msg"
Committed (local)Undo commitgit reset --soft HEAD~1
Committed (pushed)Undo safelygit revert HEAD

Viewing Commands

Want to seeCommand
Unstaged changesgit diff
Staged changesgit diff --staged
Last commitgit show
Specific commitgit show a3f2b1c
Commit historygit log --oneline
File from commitgit show a3f2b1c:file.js
HEAD movementsgit reflog

Branch Operations

ActionCommand
Create branchgit branch name
Create + switchgit switch -c name
Switch branchgit switch name
Delete branchgit branch -d name
List branchesgit branch -a
Merge branchgit merge name

Frequently Asked Questions

Is Git the same as GitHub?

No. Git is the version control software that runs locally on your machine. GitHub is a web platform that hosts Git repositories online and adds collaboration features like pull requests, issues, and project boards. You can use Git without GitHub, and there are alternatives like GitLab and Bitbucket.

Do I need to memorize all these commands?

Not at all. Focus on the core workflow first: git add, git commit, git push, git pull, git status, and git log. The rest you can look up as needed. Over time, the commands you use frequently will become muscle memory. Use the decision guide as a quick reference.

What happens if I accidentally commit sensitive data like passwords or API keys?

Simply deleting the file and committing again does not remove it from history. You will need to rewrite history using tools like git filter-repo or BFG Repo-Cleaner. Better yet, use a .gitignore file to prevent sensitive files from being tracked in the first place. If credentials have been exposed, rotate them immediately.

Should I use git checkout or git switch?

git switch was introduced in Git 2.23 to make branch operations clearer. git checkout still works and does more (it can also restore files), but git switch is recommended for switching branches because its intent is unambiguous.

What is the difference between git pull and git fetch?

git fetch downloads changes from the remote repository but does not modify your working directory. git pull does a git fetch followed by a git merge, which means it downloads and immediately integrates changes. Use fetch when you want to review changes before merging.

How often should I commit?

Commit whenever you complete a logical unit of work. A good commit should be atomic — it represents one change that makes sense on its own. Small, frequent commits are better than large, infrequent ones because they are easier to review, revert, and understand.


What’s Next: Day 1 Labs and Day 2

You now have the complete conceptual foundation for Git. The next step is to put these concepts into practice.

  • Day 1 Lab Workbook — Hands-on exercises covering repository creation, branching, merging, conflict resolution, and recovery. Every command from this guide gets practiced in a real terminal.
  • Day 2 Guide — Advanced Git techniques including stash, tags, cherry-pick, rebase, reflog, submodules, worktree, bisect, hooks, aliases, and more. If Day 1 gives you the steering wheel, Day 2 gives you the full dashboard.
  • Day 2 Lab Workbook — Hands-on exercises for all Day 2 advanced topics.

Happy versioning!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top