History Workshop
Practice interactive rebase, bisect, tagging, and blame.
Setup
Create a repository with messy history:
bash1$ mkdir history-practice && cd history-practice2$ git init34# Create a series of commits5$ echo "line 1" > file.txt && git add . && git commit -m "add file"6$ echo "line 2" >> file.txt && git add . && git commit -m "WIP"7$ echo "line 3" >> file.txt && git add . && git commit -m "WIP 2"8$ echo "line 4" >> file.txt && git add . && git commit -m "typo fix"9$ echo "line 5" >> file.txt && git add . && git commit -m "done with feature"
Check the messy history:
bash1$ git log --oneline2abc12 done with feature3def34 typo fix4ghi56 WIP 25jkl78 WIP6mno90 add file
Part 1: Interactive Rebase
Exercise 1: Squash WIP Commits
Let's clean up those WIP commits:
bash1$ git rebase -i HEAD~4
Your editor opens. Change it to:
1pick jkl78 WIP2squash ghi56 WIP 23squash def34 typo fix4squash abc12 done with feature
Save and close. Another editor opens for the combined message. Write:
1feat: add lines 2-5 to file23Combined from multiple work-in-progress commits.
Save and close.
Verify Clean History
bash1$ git log --oneline2xyz00 feat: add lines 2-5 to file3mno90 add file45$ cat file.txt6line 17line 28line 39line 410line 5
All work preserved, history cleaned!
Part 2: Bisect
Setup: Create a "Bug"
Add more commits, one with a "bug":
bash1$ echo "good 1" >> file.txt && git add . && git commit -m "good commit 1"2$ echo "good 2" >> file.txt && git add . && git commit -m "good commit 2"3$ echo "BUG" >> file.txt && git add . && git commit -m "introduce bug"4$ echo "good 3" >> file.txt && git add . && git commit -m "good commit 3"5$ echo "good 4" >> file.txt && git add . && git commit -m "good commit 4"
Exercise 2: Find the Bug
The "bug" is any commit where file.txt contains "BUG".
bash1$ git bisect start2$ git bisect bad # HEAD has the bug3$ git bisect good HEAD~5 # 5 commits ago was good4Bisecting: 2 revisions left to test after this (roughly 2 steps)
Git checks out a middle commit. Test for the bug:
bash1$ grep "BUG" file.txt2# If output, the bug exists3$ git bisect bad45# If no output6$ git bisect good
Repeat until:
bash1abc123 is the first bad commit2commit abc1233Author: You <you@example.com>45 introduce bug
End Bisect
bash1$ git bisect reset
Exercise 3: Automated Bisect
Create a test script:
bash1$ cat > test.sh << 'EOF'2#!/bin/bash3if grep -q "BUG" file.txt; then4 exit 1 # bad5else6 exit 0 # good7fi8EOF9$ chmod +x test.sh
Run automated bisect:
bash1$ git bisect start HEAD HEAD~52$ git bisect run ./test.sh
Git automatically finds the bad commit!
bash1$ git bisect reset2$ rm test.sh
Part 3: Tags
Exercise 4: Create Release Tags
bash1# Tag current state2$ git tag -a v1.0.0 -m "First stable release"34# Tag a past commit5$ git tag -a v0.9.0 HEAD~3 -m "Beta release"
List and View Tags
bash1$ git tag2v0.9.03v1.0.045$ git tag -n6v0.9.0 Beta release7v1.0.0 First stable release89$ git show v1.0.010tag v1.0.011Tagger: You <you@example.com>12Date: ...1314First stable release1516commit ...
Exercise 5: Checkout a Tag
bash1$ git checkout v0.9.02Note: switching to 'v0.9.0'.3You are in 'detached HEAD' state...45$ cat file.txt6# Shows file at v0.9.078$ git checkout main
Delete a Tag
bash1$ git tag v0.9.0-test2$ git tag -d v0.9.0-test3Deleted tag 'v0.9.0-test'
Part 4: Blame
Exercise 6: Basic Blame
bash1$ git blame file.txt2xyz001 (You 2025-11-30 10:00:00 +0000 1) line 13xyz002 (You 2025-11-30 10:01:00 +0000 2) line 24xyz002 (You 2025-11-30 10:01:00 +0000 3) line 35...
Exercise 7: Blame Specific Lines
bash1$ git blame -L 3,5 file.txt
Only shows lines 3-5.
Exercise 8: Find When a Line Was Added
bash1$ git log -S "BUG" --oneline2abc123 introduce bug
The -S flag finds commits that added or removed the string.
Cleanup
bash1$ cd ..2$ rm -rf history-practice
Checklist
- Squashed multiple commits with interactive rebase
- Used bisect to find a bad commit
- Created automated bisect with a test script
- Created annotated tags
- Viewed tag details
- Used blame to see line history
- Used
git log -Sto find when a string was introduced
Key Commands Summary
| Task | Command |
|---|---|
| Interactive rebase | git rebase -i HEAD~N |
| Start bisect | git bisect start |
| Mark bad/good | git bisect bad/good |
| Auto bisect | git bisect run script |
| End bisect | git bisect reset |
| Create tag | git tag -a v1.0 -m "msg" |
| List tags | git tag -n |
| Blame file | git blame file |
| Find string history | git log -S "string" |
Key Takeaway
Interactive rebase cleans history before sharing. Bisect finds bugs efficiently through binary search. Tags mark releases. Blame reveals code history. These tools become essential as projects grow.