Undoing Mistakes in Git
1. Discarding Uncommitted Changes
a) git restore <file>
- Discards uncommitted modifications in the specified file.
- Irreversible: once applied, changes cannot be recovered.
b) git restore -p <file>
- The
-p
(patch) option lets you interactively choose hunks to discard. - Useful for selectively reverting parts of a file.
c) git restore .
- Discards all uncommitted changes in the working directory since the last commit.
2. Amending the Last Commit
git commit --amend -m "New Commit Message"
- Updates the message (and/or contents) of the last commit.
- Do not amend commits that have already been shared with others.
3. Reverting a Specific Commit
git revert <SHA>
- Creates a new commit that inverts the changes of the specified commit.
- Safe way to “undo” a change without rewriting history.
- Obtain the SHA from
git log
, e.g.74e3b2b
.
4. Resetting to an Earlier Commit
a) git reset --hard <SHA>
- Moves
HEAD
and current branch to the given commit, discarding all subsequent commits and uncommitted changes. - Warning: unpushed commits are permanently lost.
b) git reset --mixed <SHA>
(default)
- Similar to
--hard
, but preserves changes from discarded commits as unstaged modifications.
5. Restoring a File from a Past Commit
git restore --source <SHA> -- <file>
- Replaces the working copy of
<file>
with its state at the given commit. - Only affects the specified file.
6. Using the Reflog to Recover Lost Commits
git reflog
- Records updates to
HEAD
(including resets) for a limited time. - Find the SHA of a lost state and then create a branch or reset to it.
Restoring After a Hard Reset
- Locate the prior
HEAD
reference in the reflog. - Use
git branch <new-branch> <reflog-SHA>
to recover.
Recovering a Deleted Branch
- Identify the branch tip SHA via
git reflog
. - Recreate the branch:
git branch <branch-name> <SHA>
.
7. Moving Commits to Another Branch
a) To a New Branch
git branch <new-branch>
git reset --hard HEAD~1
- Creates
<new-branch>
at the currentHEAD
, then removes the last commit from the original branch.
b) To an Existing Branch
git checkout <target-branch>
git cherry-pick <SHA>
git checkout <original-branch>
git reset --hard HEAD~1
- Cherry-picks the commit into
<target-branch>
, then removes it from the source branch.
8. Interactive Rebase for History Rewriting
Use with caution: Interactive rebase rewrites commit history, which can break shared branches.
git rebase -i HEAD~N
- Opens an editor listing the last
N
commits beforeHEAD
. - For each commit, you can choose an action:
Command | Description |
---|---|
pick | Keep the commit as-is. |
reword | Change the commit message. |
edit | Pause during rebase to edit the commit (e.g., amend files). |
squash | Combine with the previous commit, combining messages. |
fixup | Combine with the previous commit, discarding current message. |
drop | Remove the commit from history. |
Typical Use Cases:
- Rewriting sloppy commit messages: Use
reword
. - Cleaning up small incremental commits: Use
squash
orfixup
. - Reordering commits for clarity: Move lines up/down.
- Removing unwanted changes: Use
drop
.
Workflow Example:
git rebase -i HEAD~3
- An editor opens with the last 3 commits.
- Modify the commands next to each commit.
- Save and exit.
- Git walks through the commits, applying the actions in order.
If a conflict occurs, Git will pause and let you resolve it:
- Fix the conflict.
git add <file>
git rebase --continue
To abort the rebase at any time:
git rebase --abort
Note: Never rebase public/shared branches. Use on local feature branches only