Recover From Common Git Mistakes
Recovering from Git mistakes starts with identifying what changed: the working tree, staging area, a local commit, or shared history. Inspect that state before choosing a command that moves or discards it.
git status --short
git diff
git diff --staged
Those views answer different questions. The first summarizes state, the second shows unstaged edits, and the third shows what the index is ready to commit.
For work you cannot reproduce, make a separate copy before experimenting. A recovery branch preserves committed work, but it does not automatically preserve uncommitted files.
Recover from Git mistakes by choosing the right layer
A useful starting distinction is:
| Situation | First tool to investigate |
|---|---|
| A staged change should remain editable | git restore --staged |
| A local commit seems lost | git reflog and a recovery branch |
| The latest unshared commit needs another file | git commit --amend |
| A shared commit needs to be undone | git revert |
| One file needs an older version | git restore --source |
The restore documentation distinguishes the working tree and index. Undoing a staging decision is a different operation from discarding the file’s contents.
Find a lost commit before moving another branch
Inspect the local reference history:
git reflog --date=iso
Identify the desired entry, then preserve that commit with a new branch. For example, if inspection shows that HEAD@{1} is the commit you need:
git branch recovery 'HEAD@{1}'
git log --oneline recovery -5
The selector is an example, not a universal answer. Your reflog entry may have another number, and unrelated operations can change which entry sits at that position.
The reflog manual describes this local history. It is useful for commits Git still knows about; it is not an indefinite backup of every edit or every deleted untracked file.
Creating the branch first gives you a reference to inspect before deciding whether to cherry-pick, reset, or keep working from it.
Add a file to the last unshared commit
When the most recent commit is still local:
git add path/to/file
git diff --staged
git commit --amend --no-edit
The commit documentation explains that amending creates a replacement commit. Other changes already staged will also be included, which is why checking the staged diff matters.
To change only the message without opening an editor in this example:
git commit --amend -m "Clarify the change"
For a commit already used by other people, a follow-up commit is often easier to coordinate than rewritten history.
Move an unshared commit off the wrong branch
Assume the latest commit was made on main, belongs on a new feature branch, and the working tree is clean:
git status --short
git branch feature-name
git reset --hard HEAD~1
git switch feature-name
The branch preserves the current commit before main moves back. The reset manual documents what --hard replaces; do not run this sequence over uncommitted work you intend to keep.
The empty status output is a precondition to check, not something the first command enforces. Also confirm that the commit has not been shared before rewriting the branch.
If the commit is already on shared main, keep that history intact. Starting on main, one example is:
git branch recovery-shared
git switch -c feature-from-main HEAD~1
git cherry-pick recovery-shared
git switch main
git revert --no-edit recovery-shared
This example assumes exactly one ordinary commit at the tip needs moving. It creates the feature branch before applying the change and then makes a new reversal commit on main.
A merge commit, a longer sequence, or intervening dependent work needs a different plan. Inspect the graph instead of substituting a random parent number.
Undo an older shared commit with a new commit
Inspect the history, identify the unwanted commit, and use its actual object ID. A concrete test case with one later commit can use:
git log --oneline -5
git revert --no-edit HEAD~1
Here HEAD~1 must be the commit you deliberately selected. It is only an illustrative position in the history.
Revert records a new commit rather than erasing the old one. Later edits can conflict with the reversal; review the result and run the project’s relevant checks before sharing it.
Restore a single file without resetting the branch
After finding the wanted version in the file’s history:
git log --oneline -- path/to/file
git restore --source=HEAD~1 -- path/to/file
git diff -- path/to/file
git add path/to/file
git commit -m "Restore the previous file version"
Replace HEAD~1 with the commit you inspected when the desired version lives elsewhere. This copies that version into the working tree; it does not move the current branch back to that commit.
Keep a separate copy of the current file first if its uncommitted contents matter. The older git checkout COMMIT -- path/to/file form still exists, but restore makes the intended operation easier to name.
Match a remote branch only after preserving local work
For a deliberate reset to the remote’s main:
git fetch origin
git switch main
git branch backup-before-reset
git reset --hard origin/main
git clean -d -n
The backup branch preserves the previous committed tip. It does not save uncommitted changes, and the reset has already replaced tracked working-tree content before the clean preview runs.
The final command only previews untracked-file deletion. If that exact list is disposable, the destructive version is:
git clean -d -f
The clean documentation explains the preview, force flag, and ignored-file behavior. This example does not add -x, so it does not request deletion of ignored files.
I would keep the inspection and preservation steps even when the eventual fix is one command. Recovery is much easier when the target and the work worth keeping are both explicit.
Filed under Tools on
Last updated on