All tutorials

Tutorial 7 of 8

Reading and Fixing History

Find who changed what and when, and undo a bad commit without rewriting history.

About 6 minutes

What you will be able to do

  1. Use git show to read a commit's author, date, message and changes.
  2. Filter git log by author and by dates, and limit it to the last few commits with -n.
  3. Undo a commit's changes with git revert <id>, including a merge commit with -m 1, and explain why revert is safe on shared branches.

Title

Reading and Fixing History. Ask the history questions, then undo safely.

This tutorial shows how to search your history and how to undo a commit by adding a new one.

Analogy: reading a photo's caption

git show <id> displays one commit: its author, date, message and the exact changes.

git show 3d88f33

git show prints one commit's details and its changes, and it shows HEAD if you do not give an ID.

The analogy, and where it breaks

Turning a photo over to read the caption on the back: who took it, when, and what it shows.

The date shown is the author date, when the change was first written, and a commit also has a separate committer date that can differ after a rebase or cherry-pick.

Just the summary

Too much output? Add --stat for a list of changed files, or -s to hide the changes.

git show --stat 3d88f33    # which files changed, and how much
git show -s 3d88f33        # author, date and message only
git show                   # the commit HEAD is on

Options like --stat and -s (short for --no-patch) trim git show down to the part you need.

The last five commits

git log -n 5 shows only the five newest commits.

git log -n 5 --oneline

The -n option limits how many commits git log prints, and git log always starts with the newest.

Analogy: searching a checkout register

Filter by person with --author. Git searches the author's name and email.

git log --author="JohnDoe" --oneline

The --author option keeps only commits whose author name or email matches your pattern.

The analogy, and where it breaks

Like searching a library's checkout register for every entry with one member's name.

A register search usually matches the exact name, but --author treats your text as a pattern, so JohnDoe also matches JohnDoeJr, and it checks the author, not the committer.

Between two dates

Add --since and --until to see commits between two dates.

git log --author="JohnDoe" --since="2025-01-01" --until="2025-12-31"

Combining --author with --since and --until narrows the log to one person's work in a date range.

Two tips for exact searches

A date without a time uses the current clock time. Add times for exact edges. Anchor a name to match only that name.

git log --author="JohnDoe" --since="2025-01-01 00:00:00" --until="2025-12-31 23:59:59"
git log --author="^JohnDoe <"    # JohnDoe only, not JohnDoeJr

Adding explicit times and anchoring the author pattern makes your search match exactly what you mean.

Analogy: a newspaper correction

git revert <id> makes a new commit that undoes that commit's changes. Nothing is deleted.

Revert keeps the mistake in history and adds a new commit that cancels its effect.

The analogy, and where it breaks

A newspaper does not recall yesterday's papers; it prints a correction in today's issue.

A printed correction is written by hand, but git revert works out the exact opposite changes for you, and if later commits changed the same lines you must fix a conflict.

Revert a commit

Git writes the message for you and names the commit it undoes. Add --no-edit to skip the editor.

git log --oneline -n 3
git revert 3d88f33
# or, without opening an editor:
git revert --no-edit 3d88f33

git revert needs a clean working folder, then creates the undo commit with a ready-made message.

Reverting a merge needs -m

Reverting a merge commit? Tell Git which parent is the main line with -m 1.

git revert 932d4df
# error: commit 932d4df... is a merge but no -m option was given.
git revert -m 1 932d4df

A merge has two parents, so git revert needs -m to know which side to keep, and -m 1 keeps the main line.

Why revert on shared branches

On shared branches, prefer revert. It adds history instead of rewriting it, so teammates stay in sync.

Because revert only adds a commit, everyone can pull it normally, unlike commands that remove commits from shared history.

Recap

show reads one commit. log filters by author and dates. -n limits the list. revert adds an undo commit. Merges need -m.

Authors in this repo: JohnDoe, JohnDoeJr, Priya
$ git log --author="JohnDoe" --oneline

You can now answer history questions and undo mistakes safely, and next you will make your first open-source contribution.

Check yourself

0 of 5 answered

Check 1 of 5

Which command shows one commit's author, date, message and changes?

Check 2 of 5

Whose commits does this command list?

Authors in this repo: JohnDoe, JohnDoeJr, Priya
$ git log --author="JohnDoe" --oneline

Check 3 of 5

You want to see only the last five commits. Which command do you use?

Check 4 of 5

Click the commit that now holds the undo of C2's changes.

C1C2C3C4R1HEAD: main

Before: main has C1, C2, C3, C4. After running git revert C2, the graph shows C1, C2, C3, C4 and a new commit R1 after C4.

Check 5 of 5

git revert <merge-id> fails with "is a merge but no -m option was given". What should you run?

mkdir -p ~/git-practice/t07-history && cd ~/git-practice/t07-history
git init -b main

export GIT_AUTHOR_DATE="2024-12-20T10:00:00" GIT_COMMITTER_DATE="2024-12-20T10:00:00"
echo "price = 100" > cart.txt && git add cart.txt
git commit --author="JohnDoe <john@example.com>" -m "Add cart"

export GIT_AUTHOR_DATE="2025-03-10T10:00:00" GIT_COMMITTER_DATE="2025-03-10T10:00:00"
echo "discount = 10" >> cart.txt && git add cart.txt
git commit --author="Priya <priya@example.com>" -m "Add discount"

export GIT_AUTHOR_DATE="2025-06-15T10:00:00" GIT_COMMITTER_DATE="2025-06-15T10:00:00"
echo "discount = 90" >> cart.txt && git add cart.txt
git commit --author="JohnDoe <john@example.com>" -m "Add bad discount"

export GIT_AUTHOR_DATE="2025-08-01T10:00:00" GIT_COMMITTER_DATE="2025-08-01T10:00:00"
echo "tax = 18" > tax.txt && git add tax.txt
git commit --author="JohnDoeJr <jr@example.com>" -m "Add tax"

unset GIT_AUTHOR_DATE GIT_COMMITTER_DATE     # back to real dates

git log -n 5 --oneline
git log --author="JohnDoe" --oneline                                          # includes JohnDoeJr
git log --author="JohnDoe" --since="2025-01-01" --until="2025-12-31" --oneline
git show HEAD~1                              # HEAD~1 is the commit before HEAD; press q to leave
git revert --no-edit HEAD~1                  # undo "Add bad discount"
cat cart.txt                                 # the discount = 90 line is gone
git log --oneline -n 3

# Optional: reverting a merge
git switch -c feature
echo "extra" > extra.txt && git add extra.txt && git commit -m "Add extra"
git switch main
git merge --no-ff -m "Merge feature" feature
git revert HEAD                              # fails: a merge needs -m
git revert --no-edit -m 1 HEAD               # works: extra.txt is removed