Computing Foundations › Git and GitHub › Day 29
Hands-on lab — Day 29: Why Version Control Exists
- ← Back to the Day 29 lesson
- Open the hands-on files on GitHub — clone or download them from the public labs repository
- Local path in your clone:
labs/sections/computing-foundations/day-029-why-version-control-exists/
Commands
Setup
cd labs/sections/computing-foundations/day-029-why-version-control-exists Run
bash examples/history_demo.sh
bash starter/history_demo.sh Test
bash tests/run_tests.sh File tree
examples/history_demo.sh expected-output/FIELDS.md expected-output/sample-run.txt metadata.yml README.md requirements/README.md security.md starter/history_demo.sh starter/vcs-worksheet.md tests/run_tests.sh troubleshooting.md
Lab README
Day 029 lab — Your First Repository's History
Lesson
- Lesson title: Why Version Control Exists
- Day number: 29 of 365
- Lesson article: https://ai-roadmap-365.github.io/day-029-why-version-control-exists
- Lab files: everything you need is in this directory — follow “How to run” below.
- Browse the course locally: from the repository root, this lab also appears in the course website at
/labs/day-029-why-version-control-existswhen the site is running.
Purpose
Day 29's lesson explains why version control exists. This lab makes it concrete without asking you to learn any commands yet: a short script builds a real, throwaway git repository, makes three commits to one file, and then shows you the history four ways — the one-line log, a diff between two versions, the full detail of one commit, and a restore of an earlier version (the "time machine"). You watch history get built and then travel through it, all locally, with nothing left behind afterward.
Learning objectives
- See a repository's history as a chain of three commits you can list at a glance.
- Read a diff and identify exactly which line one commit added.
- Read a commit's author, timestamp, and message with
git show. - Restore an earlier version of a file and understand why nothing is lost.
- Complete four small exercises that name the exact git commands, and record what you learned in a worksheet.
Prerequisites
- The Day 29 lesson (read it first — it explains every idea this lab shows).
- A terminal: Terminal.app (macOS), any terminal (Linux), or Git Bash / WSL (Windows).
gitinstalled (or installable — see Installation); no prior version control experience required.
Supported operating systems
- macOS — fully supported (tested on macOS with Apple Silicon, git 2.50.1).
- Linux — fully supported (any distribution with
gitand a POSIX shell). - Windows — use Git Bash (bundled with Git for Windows), or run the scripts unmodified inside WSL.
Hardware requirements
Any computer that runs git. The lab creates a tiny temporary repository and a few small text files; it needs no meaningful RAM, disk, or GPU.
Required software
bash(3.2 or newer — preinstalled on macOS and Linux).git(any 2.x release;git restoreneeds 2.23+, and the scripts fall back togit checkouton older git).- Standard utilities only:
mktemp,printf,cat,grep,sed,awk— all part of the base system.
Free and open-source options
Everything here is free and open source: git itself, bash, and every utility used. No account, API key, network connection, or purchase is required — git is the free, open-source standard this whole week teaches.
Installation
Confirm git is present:
git --version
If that prints a version, you are ready. If not, install git (it is free
everywhere) — full per-platform instructions are in
requirements/README.md. Then change into this
directory:
cd labs/sections/computing-foundations/day-029-why-version-control-exists
File structure
day-029-why-version-control-exists/
├── README.md ← you are here
├── metadata.yml ← machine-readable lab metadata
├── starter/
│ ├── history_demo.sh ← YOUR working file (4 exercises)
│ └── vcs-worksheet.md ← worksheet for the practice assignment
├── examples/
│ └── history_demo.sh ← completed reference demo
├── tests/
│ └── run_tests.sh ← automated checks
├── expected-output/
│ ├── sample-run.txt ← a real captured run (macOS)
│ └── FIELDS.md ← what is stable vs. what varies per run
├── requirements/
│ └── README.md ← how to install git (the only dependency)
├── troubleshooting.md
└── security.md
How to run
From this directory:
## 1. See the finished demo first
bash examples/history_demo.sh
## 2. Your task: complete the four exercises in the starter, then run it
bash starter/history_demo.sh
## 3. Check your work
bash tests/run_tests.sh
What the commands do
bash examples/history_demo.sh— creates a throwaway git repository in a temporary directory, sets a local git identity (so it works even if you have never configured git), makes three commits tonotes.txt, then runsgit log --oneline, agit diffbetween commits 1 and 2, agit showof commit 2, and a restore ofnotes.txtto commit 1 — deleting the temporary directory on exit.bash starter/history_demo.sh— the same script with the four inspection steps left as numbered exercises; each comment names the exact git command to fill in (git log --oneline,git diff,git show,git restore).bash tests/run_tests.sh— runs the reference demo and checks real behavior: three commits made, three commits in the log, a diff showing an added line,git showrevealing the author, the restore returning commit 1's content, and the temporary directory gone afterward — then confirms the starter names the four required commands.
Expected output
See expected-output/sample-run.txt — a
real captured run. The shape is fixed but the commit ids and the temporary
path differ every run:
=== Version control history demo ===
Creating a throwaway repository in a temporary directory...
(temporary directory: /var/folders/.../day029-vcs-demo.XXXXXX)
Made commit 1: Start notes with a first point
Made commit 2: Expand the notes with a second point
Made commit 3: Add a closing line to the notes
--- git log --oneline (newest first) ---
ee169af Add a closing line to the notes
5da934c Expand the notes with a second point
64258c3 Start notes with a first point
--- git diff between commit 1 and commit 2 (notes.txt) ---
+Point two: every commit records who, when, and why.
--- git show of commit 2 ---
Author: Course Learner <learner@example.com>
Expand the notes with a second point
--- Time machine: restoring notes.txt to commit 1 ---
Restored. notes.txt now reads:
Point one: version control keeps history.
Cleaning up the temporary repository...
Done. Nothing left behind.
Your commit ids will differ — that is expected, because a commit's id is a
hash of its content, author, and time. expected-output/FIELDS.md
lists exactly what stays stable and what varies.
Validation steps
- Run
bash examples/history_demo.sh— it must exit without errors and print three "Made commit" lines. - Confirm
git log --onelineshows exactly three commits, newest first. - Confirm the diff shows the single added line
+Point two: .... - Confirm the restore step brings back
Point one: version control keeps history.. - Confirm the final two lines report cleanup, and that the temporary directory named near the top no longer exists.
- Run the tests (next section) — all checks must pass.
Tests
bash tests/run_tests.sh
Expected final line: 12 checks, 0 failure(s). (8 behavior checks against
the reference demo — including that its temporary directory is gone
afterward — and 4 checks that the starter names the four required git
commands.) The command exits 0 on success and non-zero on any failure, so it
can run in CI. It uses no network.
Cleanup
Nothing to clean up: each script deletes its own temporary directory on exit,
even if interrupted. To reset your edits to the starter, restore it from git:
git checkout -- starter/history_demo.sh.
Troubleshooting
See troubleshooting.md for the full list — git not
installed, the "author identity unknown" message (the scripts set a local one),
git restore on older git, a lingering temporary directory after Ctrl-C, and
Windows notes.
Security notes
See security.md. Short version: the scripts operate only inside a temporary directory they create and delete, set no global git config, make no network calls, and need no elevated privileges.
Extension exercises
- Copy
examples/history_demo.sh, remove the cleanuptrapline, run it, thencdinto the temporary directory and explore:git log --stat(which files changed and by how much) andgit cat-file -p HEAD(the raw commit object — tree, parent, author, message). Delete the folder yourself when done. - Add a fourth commit that removes a line, then diff it against the third commit and read how deletions appear (with a leading
-). - Create a second branch in your throwaway repo (
git switch -c experiment), make a commit on it, and usegit log --oneline --graph --allto see the branch structure you read about in the lesson.
Navigation
- Previous day: Day 28 — Consuming a Public API from the Command Line (
labs/sections/computing-foundations/day-028-consuming-a-public-api-from-the/). - Next day: Day 30 — Git Fundamentals: Repositories, Staging, and Commits (
labs/sections/computing-foundations/day-030-git-fundamentals-repositories-staging-and-commits/, to be written).
Expected output
FIELDS.md
# Expected output — what is stable, what varies
`sample-run.txt` in this directory is a real captured run of
`examples/history_demo.sh` (macOS, Apple Silicon, git 2.50.1, 2026-07-12).
A correct run on any platform prints, in order:
1. `=== Version control history demo ===`
2. `Creating a throwaway repository in a temporary directory...`
3. `(temporary directory: <path>)` — **the path varies** by machine and run.
4. `Made commit 1: Start notes with a first point`
5. `Made commit 2: Expand the notes with a second point`
6. `Made commit 3: Add a closing line to the notes`
7. `--- git log --oneline (newest first) ---` followed by **three** commit
lines, newest first. **The short commit ids vary** — a commit's hash is
computed from its content, author, and time, so they differ every run.
8. `--- git diff between commit 1 and commit 2 (notes.txt) ---` followed by
`+Point two: every commit records who, when, and why.`
9. `--- git show of commit 2 ---` followed by the author and message.
10. `--- Time machine: restoring notes.txt to commit 1 ---` and
`Point one: version control keeps history.`
11. `Cleaning up the temporary repository...` and `Done. Nothing left behind.`
## Platform notes
- **Commit ids differ every run** on every platform — this is expected and
correct, not a failure. The messages and structure are what stay fixed.
- **The temporary path differs** by OS: macOS puts it under a long
`/var/folders/...` path; Linux typically uses `/tmp`. The script honors
`$TMPDIR` if set.
- **`git restore` vs `git checkout`.** The script prefers `git restore`
(git 2.23 and newer). On an older git it automatically falls back to
`git checkout <commit> -- notes.txt`; the printed result is identical.
- No field depends on network access; the whole demo is local.
sample-run.txt
=== Version control history demo ===
Creating a throwaway repository in a temporary directory...
(temporary directory: /var/folders/7j/4qzljp553ndfjm_y6zbygsz00000gn/T//day029-vcs-demo.ygzaDA)
Made commit 1: Start notes with a first point
Made commit 2: Expand the notes with a second point
Made commit 3: Add a closing line to the notes
--- git log --oneline (newest first) ---
ee169af Add a closing line to the notes
5da934c Expand the notes with a second point
64258c3 Start notes with a first point
--- git diff between commit 1 and commit 2 (notes.txt) ---
+Point two: every commit records who, when, and why.
--- git show of commit 2 ---
Author: Course Learner <learner@example.com>
Expand the notes with a second point
--- Time machine: restoring notes.txt to commit 1 ---
Restored. notes.txt now reads:
Point one: version control keeps history.
Cleaning up the temporary repository...
Done. Nothing left behind.
Source files
examples/history_demo.sh (3567 bytes)
#!/usr/bin/env bash
# Day 029 lab — completed reference implementation.
#
# Builds a THROWAWAY git repository in a temporary directory, makes three
# commits to a single file, then shows the history four ways:
# 1. git log --oneline (the shelf of snapshots)
# 2. git diff (what changed between two commits)
# 3. git show (the full detail of one commit)
# 4. restore an earlier version (the "time machine")
# It sets a LOCAL git identity inside the temp repo only, so it works even
# if you have never configured git globally, and it deletes the temporary
# directory on exit (including on Ctrl-C) so nothing is left behind.
#
# Local only: no network is used at any point.
set -euo pipefail
# --- create a throwaway working area, and guarantee cleanup on exit ---------
tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/day029-vcs-demo.XXXXXX")"
cleanup() {
echo
echo "Cleaning up the temporary repository..."
rm -rf "${tmp_dir}"
echo "Done. Nothing left behind."
}
trap cleanup EXIT
echo "=== Version control history demo ==="
echo "Creating a throwaway repository in a temporary directory..."
echo "(temporary directory: ${tmp_dir})"
cd "${tmp_dir}"
# --- initialize the repository and set a LOCAL identity ---------------------
# --initial-branch keeps output stable across git versions; the identity is
# scoped to THIS repo only (no --global), so your machine's config is untouched.
git init --quiet --initial-branch=main
git config user.name "Course Learner"
git config user.email "learner@example.com"
# --- commit 1 ---------------------------------------------------------------
printf 'Point one: version control keeps history.\n' > notes.txt
git add notes.txt
git commit --quiet -m "Start notes with a first point"
c1="$(git rev-parse HEAD)"
echo "Made commit 1: Start notes with a first point"
# --- commit 2 ---------------------------------------------------------------
printf 'Point two: every commit records who, when, and why.\n' >> notes.txt
git add notes.txt
git commit --quiet -m "Expand the notes with a second point"
c2="$(git rev-parse HEAD)"
echo "Made commit 2: Expand the notes with a second point"
# --- commit 3 ---------------------------------------------------------------
printf 'Closing line: nothing committed is ever truly lost.\n' >> notes.txt
git add notes.txt
git commit --quiet -m "Add a closing line to the notes"
echo "Made commit 3: Add a closing line to the notes"
# --- view 1: the one-line log ----------------------------------------------
echo
echo "--- git log --oneline (newest first) ---"
git log --oneline
# --- view 2: a diff between commit 1 and commit 2 ---------------------------
echo
echo "--- git diff between commit 1 and commit 2 (notes.txt) ---"
# Show only the added/removed content lines to keep the demo readable.
git diff "${c1}" "${c2}" -- notes.txt | grep -E '^[+-][^+-]' || true
# --- view 3: the full detail of commit 2 -----------------------------------
echo
echo "--- git show of commit 2 ---"
git show --no-patch --format='Author: %an <%ae>%n %s' "${c2}"
# --- view 4: the time machine — restore notes.txt to commit 1 ---------------
echo
echo "--- Time machine: restoring notes.txt to commit 1 ---"
# 'git restore' (git >= 2.23) is preferred; fall back to 'git checkout' if the
# installed git is older, so the demo works everywhere.
if git restore --source="${c1}" -- notes.txt 2>/dev/null; then
:
else
git checkout "${c1}" -- notes.txt
fi
echo "Restored. notes.txt now reads:"
cat notes.txt
# cleanup runs automatically via the EXIT trap.
metadata.yml (586 bytes)
lesson_id: D029
day: 29
kind: command-line-inspection
languages: [bash]
setup_commands:
- cd labs/sections/computing-foundations/day-029-why-version-control-exists
run_commands:
- bash examples/history_demo.sh
- bash starter/history_demo.sh
test_commands:
- bash tests/run_tests.sh
cleanup_commands:
- '# none needed: each script deletes its own temporary directory on exit'
requires_network: false
requires_api_key: false
estimated_minutes: 30
last_executed: '2026-07-12'
executed_on: 'macOS (Apple Silicon), git 2.50.1, bash tests/run_tests.sh → 12 checks, 0 failure(s).'
requirements/README.md (1134 bytes)
# Dependencies — Day 029 lab
**Just `git` and a POSIX shell.** This lab has no installable project
dependencies and needs no network, account, or API key.
- `bash` (3.2 or newer — preinstalled on macOS and every mainstream Linux
distribution).
- `git` (2.x). Checking whether you already have it:
```bash
git --version
```
If that prints a version, you are ready. If it says `command not found`,
install git — it is free and open source on every platform:
- **macOS:** ships with the Command Line Tools. Install them with
`xcode-select --install`, or install git via Homebrew: `brew install git`.
- **Debian/Ubuntu Linux:** `sudo apt update && sudo apt install git`
- **Fedora/RHEL Linux:** `sudo dnf install git`
- **Windows:** install Git for Windows (which includes Git Bash), or run the
lab inside WSL and use the Linux instructions.
Standard utilities the scripts use — `mktemp`, `printf`, `cat`, `grep`,
`sed`, `awk` — are part of the base system on macOS and Linux. `git restore`
needs git 2.23 or newer; on older git the scripts fall back to `git checkout`
automatically, so any 2.x release works.
starter/history_demo.sh (3296 bytes)
#!/usr/bin/env bash
# Day 029 lab — YOUR working file.
#
# The repository-building part is done for you: this script creates a
# THROWAWAY git repo in a temporary directory, sets a LOCAL identity, makes
# three commits to notes.txt, and cleans up on exit. Your job is the four
# numbered exercises below — each names the EXACT git command to run so you
# can inspect the history you built. Replace each 'echo "FILL-IN ..."' line with
# the command named in the comment above it, then run:
#
# bash starter/history_demo.sh
#
# The completed reference version is examples/history_demo.sh — try it
# yourself first, then come back and fill these in.
#
# Local only: no network is used at any point.
set -euo pipefail
tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/day029-vcs-demo.XXXXXX")"
cleanup() {
echo
echo "Cleaning up the temporary repository..."
rm -rf "${tmp_dir}"
echo "Done. Nothing left behind."
}
trap cleanup EXIT
echo "=== Version control history demo (starter) ==="
echo "Creating a throwaway repository in a temporary directory..."
echo "(temporary directory: ${tmp_dir})"
cd "${tmp_dir}"
git init --quiet --initial-branch=main
git config user.name "Course Learner"
git config user.email "learner@example.com"
printf 'Point one: version control keeps history.\n' > notes.txt
git add notes.txt
git commit --quiet -m "Start notes with a first point"
c1="$(git rev-parse HEAD)"
echo "Made commit 1: Start notes with a first point"
printf 'Point two: every commit records who, when, and why.\n' >> notes.txt
git add notes.txt
git commit --quiet -m "Expand the notes with a second point"
c2="$(git rev-parse HEAD)"
echo "Made commit 2: Expand the notes with a second point"
printf 'Closing line: nothing committed is ever truly lost.\n' >> notes.txt
git add notes.txt
git commit --quiet -m "Add a closing line to the notes"
echo "Made commit 3: Add a closing line to the notes"
# ===================== YOUR EXERCISES =====================================
# --- Exercise 1: show the one-line history -------------------------------
# Replace the FILL-IN line with the command: git log --oneline
echo
echo "--- Exercise 1: git log --oneline (newest first) ---"
echo "FILL-IN Exercise 1: run 'git log --oneline'"
# --- Exercise 2: diff commit 1 against commit 2 --------------------------
# The commit ids are already saved in ${c1} and ${c2}. Replace the FILL-IN with:
# git diff "${c1}" "${c2}" -- notes.txt
echo
echo "--- Exercise 2: git diff between commit 1 and commit 2 (notes.txt) ---"
echo "FILL-IN Exercise 2: run 'git diff \"\${c1}\" \"\${c2}\" -- notes.txt'"
# --- Exercise 3: show the full detail of commit 2 ------------------------
# Replace the FILL-IN with: git show "${c2}"
echo
echo "--- Exercise 3: git show of commit 2 ---"
echo "FILL-IN Exercise 3: run 'git show \"\${c2}\"'"
# --- Exercise 4: time machine — restore notes.txt to commit 1 ------------
# Replace the FILL-IN with (git 2.23+): git restore --source="${c1}" -- notes.txt
# On older git, use instead: git checkout "${c1}" -- notes.txt
echo
echo "--- Exercise 4: restore notes.txt to commit 1 ---"
echo "FILL-IN Exercise 4: run 'git restore --source=\"\${c1}\" -- notes.txt'"
echo "notes.txt now reads:"
cat notes.txt
# cleanup runs automatically via the EXIT trap.
starter/vcs-worksheet.md (1615 bytes)
# Version control worksheet — Day 29
Fill this in after running `bash examples/history_demo.sh`. Answer in your own
words; there are no trick questions.
## 1. How many commits did the demo make, and what did each one do?
Number of commits: ____________
- Commit 1 did: ______________________________________________________
- Commit 2 did: ______________________________________________________
- Commit 3 did: ______________________________________________________
## 2. What did `git log --oneline` show?
Paste the three lines from your own run (the short id + message for each
commit, newest first):
```text
________________________________________
________________________________________
________________________________________
```
Why are your commit ids different from the ones in the lesson's sample?
(One sentence.)
____________________________________________________________________
## 3. One thing version control can recover that plain file copies cannot
Name one specific thing you could recover or answer using this history that
you could NOT get from a folder of dated copies like `notes_v1.txt`,
`notes_v2.txt` — for example: the exact author and reason behind a single
changed line, a precise line-by-line diff between two versions, or a clean
restore of one file without disturbing the others.
____________________________________________________________________
____________________________________________________________________
## 4. In one sentence: what problem does version control solve for a team?
____________________________________________________________________
tests/run_tests.sh (3543 bytes)
#!/usr/bin/env bash
# Tests for the Day 029 lab. Run from the lab directory:
# bash tests/run_tests.sh
#
# Verifies that the reference demo:
# - builds a repository with exactly three commits,
# - shows a diff (an added line) between two commits,
# - restores an earlier version (the time machine), and
# - cleans up its temporary directory, leaving nothing behind.
# Also checks the starter file names the four required git commands.
# No network is used.
set -u
lab_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
demo="${lab_dir}/examples/history_demo.sh"
starter="${lab_dir}/starter/history_demo.sh"
failures=0
checks=0
check() {
local label="$1" ok="$2"
checks=$((checks + 1))
if [ "${ok}" = "yes" ]; then
echo " ok: ${label}"
else
echo " FAIL: ${label}"
failures=$((failures + 1))
fi
}
# --- git must be available --------------------------------------------------
if ! command -v git >/dev/null 2>&1; then
echo "FAIL: git is not installed — see requirements/README.md"
exit 1
fi
echo "Testing ${demo} ..."
if ! output="$(bash "${demo}" 2>&1)"; then
check "demo script exits successfully" "no"
echo "${output}" | sed 's/^/ /'
echo
echo "${checks} checks, ${failures} failure(s)."
exit 1
fi
check "demo script exits successfully" "yes"
# Three commits were made.
made_count="$(printf '%s\n' "${output}" | grep -c '^Made commit [123]:')"
[ "${made_count}" -eq 3 ] && check "demo reports three commits made" "yes" || check "demo reports three commits made" "no"
# git log --oneline showed three commit lines (between its header and the next blank line).
log_count="$(printf '%s\n' "${output}" | awk '/^--- git log --oneline/{f=1;next} /^$/{f=0} f' | grep -c '.')"
[ "${log_count}" -eq 3 ] && check "git log --oneline lists three commits" "yes" || check "git log --oneline lists three commits" "no"
# A diff was shown: the added second-point line appears with a leading '+'.
printf '%s\n' "${output}" | grep -q '^+Point two:' && check "a diff shows an added line between two commits" "yes" || check "a diff shows an added line between two commits" "no"
# git show revealed an author line.
printf '%s\n' "${output}" | grep -q '^Author: Course Learner' && check "git show reveals the commit author" "yes" || check "git show reveals the commit author" "no"
# The time machine restored commit 1's content.
printf '%s\n' "${output}" | grep -q '^Point one: version control keeps history\.$' && check "restore brings back commit 1's version" "yes" || check "restore brings back commit 1's version" "no"
# Cleanup ran and the temporary directory it named no longer exists.
printf '%s\n' "${output}" | grep -q '^Done\. Nothing left behind\.$' && check "demo prints its cleanup confirmation" "yes" || check "demo prints its cleanup confirmation" "no"
tmp_path="$(printf '%s\n' "${output}" | sed -n 's/^(temporary directory: \(.*\))$/\1/p')"
if [ -n "${tmp_path}" ] && [ ! -e "${tmp_path}" ]; then
check "temporary directory is gone after the run" "yes"
elif [ -z "${tmp_path}" ]; then
check "temporary directory path was reported" "no"
else
check "temporary directory is gone after the run" "no"
fi
# --- starter names the four required git commands ---------------------------
echo "Testing ${starter} ..."
for cmd in "git log --oneline" "git diff" "git show" "git restore"; do
grep -q "${cmd}" "${starter}" && check "starter names '${cmd}'" "yes" || check "starter names '${cmd}'" "no"
done
echo
echo "${checks} checks, ${failures} failure(s)."
[ "${failures}" -eq 0 ]
Troubleshooting
Troubleshooting — Day 029 lab
git: command not found
Git is not installed. It is free on every platform — see
requirements/README.md for the one-line install for macOS, Linux, and
Windows. Confirm with git --version.
Author identity unknown or git asks for your name and email
Git needs an author name and email to make a commit, and this appears when you have never set a global identity. The lab scripts avoid this entirely by setting a local identity inside the temporary repository only:
git config user.name "Course Learner"
git config user.email "learner@example.com"
Because there is no --global, your own machine's configuration is never
touched. If you run git commands by hand in your own test folder and hit this
message, set a local identity the same way (inside that repo), or set a global
one if you are ready: git config --global user.name "Your Name".
git restore: unknown command or unknown option
Your git predates git restore (added in git 2.23). The scripts already fall
back to git checkout <commit> -- notes.txt, which does the same job on older
git. If you are typing commands yourself, use the git checkout form.
The temporary directory seems to still be there
The scripts delete their temporary directory on exit via a trap, including
on normal completion and on errors. If you pressed Ctrl-C in the middle of a
step, a leftover folder may remain — its path is printed near the top of the
output as (temporary directory: ...). Delete it with rm -rf <that path>.
The scripts never write anywhere except that one temporary directory.
The commit ids do not match the sample output
That is expected and correct. A commit's identifier is a hash of its content,
author, and time, so it differs every run and on every machine. Only the
messages and the overall structure should match expected-output/sample-run.txt.
Permission denied when running a script
Run it through bash explicitly rather than as an executable:
bash examples/history_demo.sh. If you prefer ./examples/history_demo.sh,
first make it executable with chmod +x examples/history_demo.sh.
Windows: bash is not recognized
Use Git Bash (installed with Git for Windows) or WSL (wsl --install, then
open your Linux distribution and follow the Linux path). The scripts are
plain POSIX shell and run unchanged in both.
Security notes
Security notes — Day 029 lab
- Where the scripts operate: each script works only inside a temporary
directory it creates itself with
mktemp, and deletes that directory on exit (via atrap, including on errors and interrupts). It writes nothing outside that one folder and leaves no repository behind on your machine. - No global configuration is changed. The scripts set the git author name
and email locally inside the temporary repository only (no
--global), so your own git configuration is never modified. This is the safe pattern: a throwaway repo can have a throwaway identity. - No network, no privileges. Every operation is local git work. The
scripts make no network connections, need no
sudo, and require no account or API key. If any tutorial ever asks you tosudoa script you have not read, stop and read it first. - No secrets committed. The demo commits only a tiny plain-text file it writes itself. This is also the lesson's own security rule in practice: never commit passwords, API keys, or personal data — a repository's history keeps everything ever committed, so a leaked secret must be rotated, not merely deleted in a later commit.
- Reading before running: both scripts are short and commented — read them first. Running unread shell scripts is one of the most common ways developers get compromised; every script in this course is small enough to read and understand before you execute it.