12 minworkshop

History Workshop

History Workshop

Practice interactive rebase, bisect, tagging, and blame.

Setup

Create a repository with messy history:

bash
1$ mkdir history-practice && cd history-practice
2$ git init
3
4# Create a series of commits
5$ 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:

bash
1$ git log --oneline
2abc12 done with feature
3def34 typo fix
4ghi56 WIP 2
5jkl78 WIP
6mno90 add file

Part 1: Interactive Rebase

Exercise 1: Squash WIP Commits

Let's clean up those WIP commits:

bash
1$ git rebase -i HEAD~4

Your editor opens. Change it to:

1pick jkl78 WIP
2squash ghi56 WIP 2
3squash def34 typo fix
4squash abc12 done with feature

Save and close. Another editor opens for the combined message. Write:

1feat: add lines 2-5 to file
2
3Combined from multiple work-in-progress commits.

Save and close.

Verify Clean History

bash
1$ git log --oneline
2xyz00 feat: add lines 2-5 to file
3mno90 add file
4
5$ cat file.txt
6line 1
7line 2
8line 3
9line 4
10line 5

All work preserved, history cleaned!

Part 2: Bisect

Setup: Create a "Bug"

Add more commits, one with a "bug":

bash
1$ 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".

bash
1$ git bisect start
2$ git bisect bad # HEAD has the bug
3$ git bisect good HEAD~5 # 5 commits ago was good
4Bisecting: 2 revisions left to test after this (roughly 2 steps)

Git checks out a middle commit. Test for the bug:

bash
1$ grep "BUG" file.txt
2# If output, the bug exists
3$ git bisect bad
4
5# If no output
6$ git bisect good

Repeat until:

bash
1abc123 is the first bad commit
2commit abc123
3Author: You <you@example.com>
4
5 introduce bug

End Bisect

bash
1$ git bisect reset

Exercise 3: Automated Bisect

Create a test script:

bash
1$ cat > test.sh << 'EOF'
2#!/bin/bash
3if grep -q "BUG" file.txt; then
4 exit 1 # bad
5else
6 exit 0 # good
7fi
8EOF
9$ chmod +x test.sh

Run automated bisect:

bash
1$ git bisect start HEAD HEAD~5
2$ git bisect run ./test.sh

Git automatically finds the bad commit!

bash
1$ git bisect reset
2$ rm test.sh

Part 3: Tags

Exercise 4: Create Release Tags

bash
1# Tag current state
2$ git tag -a v1.0.0 -m "First stable release"
3
4# Tag a past commit
5$ git tag -a v0.9.0 HEAD~3 -m "Beta release"

List and View Tags

bash
1$ git tag
2v0.9.0
3v1.0.0
4
5$ git tag -n
6v0.9.0 Beta release
7v1.0.0 First stable release
8
9$ git show v1.0.0
10tag v1.0.0
11Tagger: You <you@example.com>
12Date: ...
13
14First stable release
15
16commit ...

Exercise 5: Checkout a Tag

bash
1$ git checkout v0.9.0
2Note: switching to 'v0.9.0'.
3You are in 'detached HEAD' state...
4
5$ cat file.txt
6# Shows file at v0.9.0
7
8$ git checkout main

Delete a Tag

bash
1$ git tag v0.9.0-test
2$ git tag -d v0.9.0-test
3Deleted tag 'v0.9.0-test'

Part 4: Blame

Exercise 6: Basic Blame

bash
1$ git blame file.txt
2xyz001 (You 2025-11-30 10:00:00 +0000 1) line 1
3xyz002 (You 2025-11-30 10:01:00 +0000 2) line 2
4xyz002 (You 2025-11-30 10:01:00 +0000 3) line 3
5...

Exercise 7: Blame Specific Lines

bash
1$ git blame -L 3,5 file.txt

Only shows lines 3-5.

Exercise 8: Find When a Line Was Added

bash
1$ git log -S "BUG" --oneline
2abc123 introduce bug

The -S flag finds commits that added or removed the string.

Cleanup

bash
1$ 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 -S to find when a string was introduced

Key Commands Summary

TaskCommand
Interactive rebasegit rebase -i HEAD~N
Start bisectgit bisect start
Mark bad/goodgit bisect bad/good
Auto bisectgit bisect run script
End bisectgit bisect reset
Create taggit tag -a v1.0 -m "msg"
List tagsgit tag -n
Blame filegit blame file
Find string historygit 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.

History Workshop - Anko Academy