Every developer eventually breaks something in a repository. Good news: Git rarely loses data permanently – reflog records every HEAD change. Bisect cuts hours of regression hunting to minutes. Reset has three modes and mixing them up causes pain. Revert is the safe alternative on public branches. This post is the rescue map.
reset – three modes
git reset TARGET moves HEAD (and the branch) to TARGET. The difference is what happens to the index and working directory.
# --soft: undo commit, keep changes as staged git reset --soft HEAD~1 # Effect: last commit disappears, changes return to stage # Use: rewrite commit message, combine several commits # --mixed (default): undo commit and stage, keep changes in files git reset HEAD~1 # Effect: commit disappears, changes are unstaged # Use: reorganise files before re-commit # --hard: undo everything, DELETES changes! git reset --hard HEAD~1 # Effect: commit disappears, files return to TARGET state # Use: discard local changes, cleanup after bad merge
revert – safe alternative
Revert creates a new commit reversing the changes from a chosen commit. History is not rewritten – safe on public branches.
# Undo a specific commit by creating a new commit git revert a3d5e2f # Revert without auto-commit (for editing) git revert -n a3d5e2f # Revert a merge commit (-m 1 = choose first parent) git revert -m 1 merge-sha # When reset, when revert: # reset --hard: local branch, not yet pushed # revert: branch pushed to remote or shared with others
reflog – the safety net
Reflog records every HEAD change – even after reset –hard, even after branch deletion. Default retention: 90 days.
# Show HEAD history
git reflog
# HEAD@{0}: reset: moving to HEAD~1
# HEAD@{1}: commit: feat(export): add CSV export
# HEAD@{2}: commit: fix(cart): correct tax calculation
# Recover commit after reset --hard
git reset --hard HEAD@{1}
# Recover deleted branch
git checkout -b recovered-branch HEAD@{3}
# Reflog for a specific branch
git reflog show feature/order-export
bisect – find the commit that broke something
git bisect start git bisect bad # current commit = bad git bisect good v2.4.6 # last known good # Git picks the middle commit to test # Test, mark the result: git bisect good # or git bisect bad # After a few steps Git will identify the exact commit # With 100 commits you need at most 7 steps (log2) # Automated bisect with a script git bisect run php vendor/bin/phpunit tests/Unit/OrderServiceTest.php git bisect reset # return to HEAD
Recovering deleted files
# Restore a file from the last commit git checkout HEAD -- src/Model/OrderService.php # Restore a file from an older commit git checkout a3d5e2f -- src/Model/OrderService.php # Find when a file was last present git log --all --full-history -- "*.php" # Show file content from an old commit without checkout git show a3d5e2f:src/Model/OrderService.php
Stash – putting changes aside
# Stash unfinished changes
git stash push -m "WIP: order export in progress"
# List stashes
git stash list
# stash@{0}: WIP on feature/export: WIP: order export in progress
# Restore last stash
git stash pop
# Restore specific stash without removing
git stash apply stash@{0}
# Stash including untracked files
git stash push --include-untracked
Course summary
This is the final post of the Git course. We covered: data model (blobs, trees, commits, refs), commits and history, branching and merge, remote work, team workflow, hooks and automation, and now debugging and rescue. Git rarely loses data permanently – reflog is the safety net. Reset –hard is destructive for the working directory, but reflog lets you go back. Revert is the safe choice on public branches. Bisect saves hours of regression debugging.
