Thursday, 1 May 2025

How to Undo a Git Squash and Restore Previous Commits (Even After Push)

Squashing commits in Git is a powerful technique that allows developers to clean up their commit history before merging changes into the main branch. However, there are times when you might squash too aggressively or realize that you need the original commits separated again. If you find yourself in this situation, don’t worry! Git provides several methods to undo a squash and restore your previous commits. In this comprehensive guide, we will explore various strategies to achieve this, complete with examples, visuals, and best practices.

What Is Git Squashing?

Squashing commits is the process of combining multiple commits into a single commit. This is often done to create a cleaner commit history before merging changes into the main branch. Squashing is typically performed using interactive rebase.

Example of Squashing Commits

Suppose you have the following commits in your branch:

abc1234  Commit 1 - Add user model
def5678  Commit 2 - Add email validation
ghi9012  Commit 3 - Fix typo in validation

To squash these commits, you would run:

git rebase -i HEAD~3

This command opens an editor where you can choose to pick the first commit and squash the subsequent commits. After squashing, your commit history might look like this:

xyz3456  Commit SQUASHED - Add user model with validation

Now, what if you realize you need those original three commits back? Let’s explore how to undo a Git squash.

Example Scenario

Let’s say you have squashed the commits as shown above, and now you want to restore the original commits. Here’s how you can do it.

Method 1: Undo Squash Using git reflog

The git reflog command records every update to your branch, even if history is rewritten (as in a squash). This makes it a powerful tool for recovering lost commits.

Steps to Use git reflog

  1. View the reflog: Run the following command to see the history of your branch:

    git reflog
    

    Example output might look like this:

    xyz3456 HEAD@{0}: rebase -i (squash): squash 3 commits
    ghi9012 HEAD@{1}: rebase -i (start): checkout HEAD~3
    def5678 HEAD@{2}: commit: Add email validation
    abc1234 HEAD@{3}: commit: Add user model
    
  2. Reset to the pre-squash state: Identify the commit you want to reset to (in this case, HEAD@{1}) and run:

    git reset --hard HEAD@{1}
    

    Now your history is restored to just before the squash, and all individual commits are back in place.

Visual Representation of git reflog

Git Reflog Example
Figure 1: Visual representation of the reflog showing commit history.


Method 2: Create a Temporary Backup Before Reset

If you’re unsure about resetting, it’s always a good idea to create a backup branch before making changes:

git branch backup-before-undo

This way, you can safely run your git reset --hard HEAD@{1} without losing any work.

Why git pull Won’t Undo a Squash

One common mistake developers make is trying to use git pull in hopes of reverting the squash. However, this approach will not work for the following reasons:

Limitations of git pull

  • Local Squash: If the squash happened locally and hasn’t been pushed yet, git pull won’t help.
  • Already Pushed: If you’ve already pushed the squash to the remote, the remote now reflects the squashed history.

Why git pull Doesn’t Work

The git pull command merges or rebases your remote history with your local history. It does not discard or undo your squash. If your local branch has diverged, it may fail or create a confusing merge commit.

If You’ve Already Pushed the Squash (Remote Squash)

If you’ve squashed and pushed to the remote but now want to restore the old commits (which are no longer in the remote history), here are your options:

Option A: Reset to a Backup Branch (If You Had One)

If you created a backup branch before squashing, you can easily recover:

git checkout -b recover-from-backup backup-before-undo
`` Push the backup branch to the remote:

```bash
git push origin recover-from-backup

You can then either merge this branch into your main branch or force-push it to overwrite the squashed version.

Option B: Force-Push Old History from Reflog

If you didn’t back up but still see the old commits in reflog, you can reset to a previous state:

git reset --hard HEAD@{2}
git push --force

This command will replace the squashed commit on the remote with the original commits.

Warning: This action rewrites remote history and can affect your teammates, so use it with caution.


Pro Tip: Avoid Needing to Undo

To prevent the need to undo a squash in the first place, always create a branch or tag before squashing:

git branch before-squash

This gives you an easy restore point if you need to revert changes later.


Summary: How to Undo a Git Squash

Here’s a quick reference table summarizing the scenarios and solutions:

Scenario Solution
Local squash, not pushed git refloggit reset --hard HEAD@{n}
Pushed squash, no backup git refloggit resetgit push --force
Pushed squash, backup exists Checkout backup branch and push
Don't want to lose changes Backup branch before reset

Final Example Commands

Here’s a concise list of commands to help you undo a Git squash:

git reflog                         # Find pre-squash commit
git reset --hard HEAD@{1}         # Reset back to the desired commit
git push --force                  # (If you previously pushed the squash)

For further reading, check out these related topics:

Labels:

0 Comments:

Post a Comment

Note: only a member of this blog may post a comment.

<< Home