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.