lesson ── git-labs ── ~22 мин ── 8 шагов
The goal is to walk through three ways to "rewind" and learn when to
use each one. reset rewrites history, which suits your own local
branch. revert creates a compensating commit and is safe on a
shared branch. reflog saves you once everything is already broken.
интерактивный sandbox
Поднимется контейнер gitlab/git-base с git, bash, pre-commit. В браузере откроется терминал, можно сразу git init. Каждый шаг проверяется автоматически. Сеть air-gapped, github.com недоступен.
stack ── git · bash · 256 MB RAM · air-gapped · самоуничтожается через 30 мин простоя
cd /home/student/work
mkdir -p undo-lab && cd undo-lab
git init -b main
for i in 1 2 3 4 5; do
echo "line $i" >> file.txt
git add file.txt
git commit -m "line $i"
done
git log --oneline
Five commits, the file holds 5 lines. This is your practice range for undos.
✓ Five commits in place.
--soft drops the commit but keeps its content in the index.
cd /home/student/work/undo-lab
git reset --soft HEAD~1 # --soft = move the branch only, do not touch index or working
git log --oneline # log is 1 shorter
git status # content of the dropped commit is in the index
The log is now 4 commits. The index holds line 5 and is ready
to recommit with a different message.
✓ Commit dropped, the change is in the index.
--mixed (the default) also clears the index. It leaves the working tree alone.
cd /home/student/work/undo-lab
git reset HEAD~1 # no flag = --mixed: branch + index, do not touch working
git log --oneline
git status # changes in working as unstaged
The log is 3 commits. The index is empty. The working tree holds
line 4 and line 5 as unstaged changes. Useful when a commit
was made with the wrong files in the index.
✓ Index cleared. Changes are in working.
cd /home/student/work/undo-lab
git reset --hard HEAD~1 # --hard = branch + index + working, all set to HEAD~1
git log --oneline
cat file.txt # only 2 lines, everything above is gone
git status # working tree clean
The log is 2 commits. file.txt holds only 2 lines. The working
tree is clean. All the "lost" changes are no longer visible
through log, but...
Dangerous? Yes. But reflog still remembers.
✓ Hard reset done. History 'seems' lost.
reflog is a local journal of HEAD moves. All the "deleted"
commits are still there.
cd /home/student/work/undo-lab
git reflog # local log of every HEAD move (90 days)
You see entries HEAD@{0}, HEAD@{1}, and so on. These are your
recent positions. Find the one where there were 5 commits:
# HEAD@{n} = "where HEAD was n steps ago" per refloggit reset --hard HEAD@{4}git log --oneline # all 5 commits are back
All 5 commits are back. reflog keeps entries for 90 days by default.
✓ Five commits restored. reflog saved you.
Suppose commit line 3 is bad, and someone has already pushed it
to shared. reset is dangerous here: it rewrites history. Use revert.
cd /home/student/work/undo-lab
# awk '{print $1}' = first column of `log --oneline`, the short shaSHA=$(git log --oneline | grep 'line 3' | awk '{print $1}')git revert --no-edit $SHA # --no-edit = take the default message "Revert ..."
git log --oneline
cat file.txt # line 3 is gone, the rest are kept
The log grew by one commit (Revert "line 3"). History is
preserved, and both of you can see what happened. file.txt now
holds line 1, line 2, line 4, line 5, without line 3.
✓ Revert created an inverse commit. History was not rewritten.
Remember the difference:
cd /home/student/work/undo-lab
git log --oneline --graph
You see a linear history of 6 entries: 5 original ones plus the revert. No "missing" SHAs.
✓ Six commits. History intact, the mistake undone.
Make a commit:
cd /home/student/work/undo-lab
echo "extra" >> file.txt
git add file.txt && git commit -m "add extra"
git log --oneline | head -1
Note the SHA. Run amend:
git commit --amend -m "add extra (corrected)" # replaces HEAD with a new commit
git log --oneline | head -1 # different SHA, new message
The commit's SHA is different. The old version is in reflog:
git reflog | head -5 # top 5 entries: both commit and commit (amend) are visible
Both versions are visible: one commit:, the other
commit (amend):. If you want to undo the amend, run
git reset --hard HEAD@{1}. The lesson ends here: you know how to
undo almost anything you did by accident.
✓ Amend and reflog worked. Most of what is 'lost' in Git can be brought back.
reset moves the branch pointer back (3 levels of aggressiveness).
revert creates a commit that is the inverse by content. reflog
keeps every HEAD position for the last 90 days, and even "deleted"
commits are recovered from there.
команды
git reset --soft HEAD~1drop the commit, keep the indexgit reset --hard <sha>move to a commit and wipe everythinggit revert <sha>create an inverse commitgit refloglog of every HEAD positiongit reset --hard HEAD@{n}restore a state from reflogконцепции