← Back to Git series
🔀
Git & GitHub Deep Dive
add · commit · log · diff · .gitignore · alias

Chapter 2 — Daily Workflow

The everyday cycle: edit → `git add` → `git commit`, plus `git log` to inspect history, `git diff` to inspect changes, `.gitignore` to leave files out, and aliases to type less.

addcommitlog.gitignore
Duration
1-2 hours
Level
📊 Beginner
Prerequisite
🎯 Chapter 1
Outcome
Master the daily add/commit/log/diff routine

What you'll learn

  • 1Use `git add`, `git commit`, `git log`, `git diff` confidently in daily work.
  • 2Write `.gitignore` so build artifacts and secrets never leak in.
  • 3Configure aliases to shorten common commands.
  • 4Understand `HEAD`, `HEAD~1`, `HEAD~2` as commit references.

Core Concepts

1) The everyday loop

text
edit a file → git add file → git commit -m "..." → repeat

2) `git log` patterns

CommandPurpose
`git log`Full history with author/date
`git log --oneline`One commit per line
`git log --oneline --graph --all`All branches as graph
`git log -n 5`Latest 5 commits
`git log --author="Name"`By author

3) `git diff` flavors

CommandShows
`git diff`Working dir vs staging
`git diff --staged`Staging vs HEAD
`git diff HEAD~1 HEAD`The latest commit's change
`git diff main..feature`Across branches

4) `.gitignore`

A file at the repo root listing path patterns to ignore. Examples:

text
node_modules/
*.log
.env
.DS_Store
build/

5) Git aliases

Save typing by binding short forms to common commands:

bash
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.co checkout

Examples

Example 1 — `ex01_add_commit.sh`: working dir → staging → commit

**Output**

text
=== Working dir → staging → commit ===
file edited
staged
committed

Key: `git status` after each step confirms which area the change is in.

Example 2 — `ex02_log_diff.sh`: inspect history and diffs

**Output**

text
=== Tracking changes ===
a1b2c3d feat: edit file
=== Compare across two commits ===
diff: line added

Key: `git log` is your time machine; `git diff` shows what changed where.

Example 3 — `ex03_gitignore.sh`: ignoring files

**Output**

text
=== Create .gitignore ===
=== .gitignore in action ===
accidentally committed file no longer staged

Key: if a file was already tracked, `.gitignore` alone won't untrack it — use `git rm --cached <file>`.

Example 4 — `ex04_alias.sh`: setup aliases

**Output**

text
=== Alias setup ===
=== Register alias ===
git st is now status
git lg is now graph log

Key: `git config --global alias.<name> "<command>"` saves keystrokes everywhere.

Common mistakes

  1. **Forgetting to `git add`** after editing — the new content isn't staged.
  2. **Committing build artifacts** — set `.gitignore` before the first commit.
  3. **`.gitignore` after tracking** — the file is already tracked; remove with `git rm --cached`.
  4. **Cryptic commit messages** — "fix" with no context. Use `<type>: <short summary>`.
  5. **`git diff` confusion** — without `--staged`, it shows un-staged changes only.

Recap

  • The basic cycle is `edit → add → commit`; learn it cold.
  • `.gitignore` prevents accidental commits; commit it like any other file.
  • Aliases (`st`, `lg`, `co`) reduce typing in everyday flows.
  • `HEAD~N` references the Nth-prior commit.

Try it

bash
cd src
chmod +x ex0*.sh
./ex01_add_commit.sh
./ex02_log_diff.sh
./ex03_gitignore.sh
./ex04_alias.sh

💻 Examples

Runnable examples — see the output yourself.

ex01_add_commit.shworking dir → staging → commit
CODE
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "Demo User" && git config user.email "demo@example.com"
 git config commit.gpgsign false

printf 'line1\nline2\nline3\n' > file.txt
git add file.txt && git commit -q -m "init"

echo "line4" >> file.txt
git add file.txt

echo "line5" >> file.txt

echo "=== diff: working vs staging ==="
git diff

echo ""
echo "=== diff --staged: staging vs HEAD ==="
git diff --staged

git commit -q -m "add line4 (staged only)"
echo ""
echo "=== commit (after) remaining change ==="
git diff

rm -rf "$REPO"
▶ Output
=== Working dir → staging → commit ===
file edited
staged
committed
ex02_log_diff.shinspect history and diffs
CODE
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "Demo User" && git config user.email "demo@example.com"
 git config commit.gpgsign false

for i in 1 2 3; do
 echo "v$i" > version.txt
 git add version.txt
 git commit -q -m "chore: version $i"
done

echo "=== git log --oneline ==="
git log --oneline

echo ""
echo "=== git log --oneline -n 2 ==="
git log --oneline -n 2

echo ""
echo "=== git log --oneline --stat ==="
git log --oneline --stat

echo ""
echo "=== git diff HEAD~2 HEAD (two commits ago vs current) ==="
git diff HEAD~2 HEAD

rm -rf "$REPO"
▶ Output
=== Tracking changes ===
a1b2c3d feat: edit file
=== Compare across two commits ===
diff: line added
ex03_gitignore.shignoring files
CODE
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "Demo User" && git config user.email "demo@example.com"
 git config commit.gpgsign false

echo "secret_password" > .env
echo "print('hello')" > main.py
git add .
git commit -q -m "init: add files (including .env by mistake)"

echo "=== accidentally committed file list ==="
git ls-files

# .env at 
echo ".env" > .gitignore
git rm --cached .env
git add .gitignore
git commit -m "chore: stop tracking .env"

echo ""
echo "=== edit (after) file list ==="
git ls-files

echo ""
echo "=== .env file at using ==="
ls -la .env

rm -rf "$REPO"
▶ Output
=== Create .gitignore ===
=== .gitignore in action ===
accidentally committed file no longer staged
ex04_alias.shsetup aliases
CODE
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "Demo User" && git config user.email "demo@example.com"
 git config commit.gpgsign false

# local repository alias register
git config alias.lg "log --oneline --graph --all --decorate"
git config alias.st "status --short --branch"
git config alias.aa "add --all"
git config alias.cm "commit -m"

for i in 1 2; do
 echo "file$i" > "file$i.txt"
 git aa
 git cm "chore: add file$i"
done

echo "=== git st (status --short --branch) ==="
git st

echo ""
echo "=== git lg (log --oneline --graph --all) ==="
git lg

echo ""
echo "=== register alias list ==="
git config --list | grep "^alias\."

rm -rf "$REPO"
▶ Output
=== Alias setup ===
=== Register alias ===
git st is now status
git lg is now graph log

📝 Exercises

Try them yourself first, then open the solution to compare.

Exercise 1

Problem 1 (hw01.sh)

Goal: In a temp repo, make three commits each adding one line to `notes.md`. Then print the log in two formats and the diff between the first and last commit.

Requirements
  • Filename: hw01.sh
Toggle solution
SOLUTION
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "Demo User" && git config user.email "demo@example.com"
 git config commit.gpgsign false

printf 'todo 1\ntodo 2\ntodo 3\n' > notes.txt
git add notes.txt && git commit -q -m "init: add notes"

echo "todo 4" >> notes.txt
git add notes.txt

echo "todo 5" >> notes.txt

echo "=== diff: working vs staging ==="
git diff

echo ""
echo "=== diff --staged: staging vs HEAD ==="
git diff --staged

rm -rf "$REPO"
Exercise 2

Problem 2 (hw02.sh)

Goal: Build a `.gitignore` that ignores `*.log`, `node_modules/`, and `.env`. Demonstrate that committing a `secret.env` no longer stages it, while `app.js` still does.

Requirements
  • Filename: hw02.sh
Toggle solution
SOLUTION
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "Demo User" && git config user.email "demo@example.com"
 git config commit.gpgsign false

for i in 1 2 3 4 5; do
 echo "commit $i" > "file$i.txt"
 git add "file$i.txt"
 git commit -q -m "chore: add file$i"
done

echo "*.log" > .gitignore
git add .gitignore
git commit -q -m "chore: ignore *.log files"

echo "some debug info" > debug.log

echo "=== git status (.log file ) ==="
git status

echo ""
echo "=== git log --oneline ( (before)) ==="
git log --oneline

echo ""
echo "=== git log --oneline -n 3 ( 3) ==="
git log --oneline -n 3

rm -rf "$REPO"
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗