Lesson 13 / 15
Reverting
A new commit that reverses another's effect; undoing without disturbing history, verifying with the tree ID, reverting without committing, and reverting a revert.
Contents
Reset and amending both work by rewriting history; this is why they cannot be used on shared commits. If a shared commit is wrong, only one path remains: leave the past as it is, and write a new commit that reverses the mistake’s effect. This operation is called reverting.
The Mistake
The search script’s output is meant to be limited to just the Turkish column, and
grep’s output is passed through a filter:
if ! grep -i -- "$1" terimler.txt | cut -d '|' -f 1; then echo "eşleşme yok: $1" >&2 exit 2 fi
git commit -m "Arama çıktısını yalnızca Türkçe sütuna indir"
[main ad60f31] Arama çıktısını yalnızca Türkçe sütuna indir 1 file changed, 1 insertion(+), 1 deletion(-)
The change produces the intended output but carries a hidden flaw: the shell takes the
pipeline’s exit code from the last command. Because cut always finishes successfully,
the condition comes out false even when grep finds no match:
./ara.sh yokboyle echo "exit code: $?"
exit code: 0
The script printed no no-match notice and exited with code zero; yet there is no match, and the exit code should be 2. The flaw is not in the output itself but in the error reporting; this is why it is prone to going unnoticed.
The commit has been shared, and it cannot be dropped from history.
Reverting
git revert --no-edit ad60f31
[main a58791f] Revert "Arama çıktısını yalnızca Türkçe sütuna indir" Date: Mon Mar 11 10:12:00 2024 +0300 1 file changed, 1 insertion(+), 1 deletion(-)
--no-edit accepts the prepared message without opening the editor. The script works
correctly again:
./ara.sh yokboyle
eşleşme yok: yokboyle
git log --oneline -n 4
a58791f Revert "Arama çıktısını yalnızca Türkçe sütuna indir" ad60f31 Arama çıktısını yalnızca Türkçe sütuna indir 18600c5 README'ye kullanım bölümü ekle bfe57d3 Öbek ve dizi terimlerini ekle
The faulty commit stands in history. Alongside it, a commit that reverses its effect has been added.
The Content of a Revert Commit
git show HEAD
commit a58791f8f8b5325563397d592015cb2009b5e567 Author: Deniz Kaya <[email protected]> Date: Mon Mar 11 10:12:00 2024 +0300 Revert "Arama çıktısını yalnızca Türkçe sütuna indir" This reverts commit ad60f311bd296f370a18d98a40173d878160d809. diff --git a/ara.sh b/ara.sh index 64b5b70..582ddde 100755 --- a/ara.sh +++ b/ara.sh @@ -6,7 +6,7 @@ if [ $# -ne 1 ]; then exit 1 fi -if ! grep -i -- "$1" terimler.txt | cut -d '|' -f 1; then +if ! grep -i -- "$1" terimler.txt; then echo "eşleşme yok: $1" >&2 exit 2 fi
The diff is the reverse of the reverted commit’s diff: the deleted line has been added, the added line has been deleted. The automatically generated message writes the reverted commit’s full ID into the body; thanks to this line, what a revert undoes can be read straight from history.
Verifying the Result
Whether the revert really returned things to the previous state can be tested with certainty by comparing tree IDs:
git log --format='%h %T %s' -n 4
a58791f ac0eb40463f387ce1cb40623aa9c16a9a7ed229f Revert "Arama çıktısını yalnızca Türkçe sütuna indir" ad60f31 9ab09543909d738602a2a947e858b1457972ef28 Arama çıktısını yalnızca Türkçe sütuna indir 18600c5 ac0eb40463f387ce1cb40623aa9c16a9a7ed229f README'ye kullanım bölümü ekle bfe57d3 c6ec3cea3b8943f818cd8bb423c65f0cb5c553ea Öbek ve dizi terimlerini ekle
The revert commit’s tree, ac0eb40, is the same as the tree of 18600c5, the commit
before the faulty one. Two different commits point at the same tree: the project content
has returned to its old state, byte for byte. This equality check, which
content-addressed storage provides, removes the need to compare diffs by eye.
Why Reverting Does Not Disturb History
Reverting only adds: it touches no existing object, it changes no ID. Copies that already have this history keep the chain they hold and take on just one new commit on top. The incompatibility that arises with reset does not occur here.
The cost is that the mistake stays visible in history. This is not a flaw; it is, most of the time, the desired behavior: when a faulty change went in, and when and why it was undone, ends up on record.
Reverting Without Committing
The result of a revert can be inspected without committing it directly:
git revert -n bfe57d3 git status --short
M terimler.txt
git diff --staged
diff --git a/terimler.txt b/terimler.txt index a5350ef..17af3b8 100644 --- a/terimler.txt +++ b/terimler.txt @@ -5,5 +5,3 @@ ağaç | tree karma tablosu | hash table bağlı liste | linked list küme | set -öbek | heap -dizi | array
The -n option puts the change in the staging area but does not commit it. This is
used to combine multiple commits into a single revert commit, or to inspect the result
before committing it. The operation can be canceled:
git revert --abort
The command returns the working directory and the staging area to their state before the revert began.
In the example, the reverted commit was not history’s most recent one. A revert can be applied to any commit; what is computed is that commit’s diff, reversed, applied to the current content. If the commits in between touched the same lines, the application fails and a conflict is reported. Resolving conflicts is the subject of the Branching and Collaboration course.
Reverting a Revert
A revert is a commit too; it can be reverted. This is the way to reapply a change that was undone:
git revert --no-edit a58791f
[main 464855e] Reapply "Arama çıktısını yalnızca Türkçe sütuna indir" Date: Mon Mar 11 15:00:00 2024 +0300 1 file changed, 1 insertion(+), 1 deletion(-)
This time the message starts with Reapply, not Revert: reverting a revert is, in
essence, reapplying.
git log --format='%h %T %s' -n 4
464855e 9ab09543909d738602a2a947e858b1457972ef28 Reapply "Arama çıktısını yalnızca Türkçe sütuna indir" a58791f ac0eb40463f387ce1cb40623aa9c16a9a7ed229f Revert "Arama çıktısını yalnızca Türkçe sütuna indir" ad60f31 9ab09543909d738602a2a947e858b1457972ef28 Arama çıktısını yalnızca Türkçe sütuna indir 18600c5 ac0eb40463f387ce1cb40623aa9c16a9a7ed229f README'ye kullanım bölümü ekle
Four commits alternate back and forth between two trees. This last step was not kept in the example repository’s history — the flawed change was not reapplied; the revert was left standing.
Reverting or Resetting
| Criterion | Reverting | Resetting |
|---|---|---|
| History | Preserved, a new commit is added | Rewritten |
| On a shared commit | Suitable | Not suitable |
| Visibility of the mistake | Stays on record | Erased |
| Which commit it applies to | Any commit | Backward from the branch tip |
There is a single criterion: if the commit has been shared, revert; if not, either can be used.
Summary
- Reverting creates a new commit that applies the reverse of another commit’s diff.
- History is preserved; no object changes, only a new commit is added.
- A revert commit’s tree is the same as the tree before the reverted commit; this equality is a verification tool.
- The
-noption puts the result in the staging area without committing it;--abortcancels the operation. - A revert can be reverted too; the result is the change being reapplied.
Next Step
The tools covered so far were about completed changes. So what happens when there is unfinished work and it becomes necessary to switch to something else? Committing is premature, and undoing is a loss. The next lesson takes up the stash, which sets unfinished work aside temporarily, and what that storage corresponds to in the object model.
To keep your progress and take notes, Log in
My notes
Log in to take notes.