Why Git Disasters Happen and How Git Actually Works
Almost every Git panic stems from a common misconception: that running an undo or delete command destroys your code. In reality, Git is an append-only directed acyclic graph (DAG). When you delete a branch or reset a commit, Git rarely deletes the underlying blob or tree objects immediately. Instead, it merely moves a pointer.
The Git Lifesaver: Understanding Reflog
The git reflog (reference log) is Git's black-box flight recorder. It logs every action that changes branch pointers or HEADβincluding checkouts, commits, rebases, and resets. Even if you run git branch -D, the commit continues to exist in your local repository for up to 30 to 90 days before garbage collection runs.
Frequently Asked Questions
What is the safest way to undo an unpushed Git commit?
Run 'git reset --soft HEAD~1' to undo the commit while keeping all your code staged in the index, or run 'git reset HEAD~1' to keep the code in your working directory unstaged. Both options preserve 100% of your code.
How do I undo a Git commit that has already been pushed to GitHub?
Use 'git revert <commit-sha>'. This creates a new commit that cleanly inverts the bad changes without rewriting Git history, preventing broken divergent history for teammates.
Can I recover a Git branch deleted with 'git branch -D'?
Yes! Git rarely deletes commit objects immediately. Run 'git reflog' to find the commit hash before the deletion, then run 'git checkout -b <branch-name> <commit-sha>' to completely restore the branch.
What should I do if I accidentally committed and pushed secrets or API keys?
First, immediately rotate and revoke the exposed API credentials in your provider dashboard. Then use 'git reset --soft HEAD~1', remove the secret, add it to .gitignore, and force-push with 'git push --force-with-lease'.
What is the difference between git reset --soft, --mixed, and --hard?
'--soft' moves HEAD back but leaves files staged. '--mixed' (the default) moves HEAD and unstages files into your working tree. '--hard' permanently discards commit changes and wipes your working tree to match the previous commit.