As a professional developer, having confidence using Git‘s powerful undo capabilities can save your work and sanity. This advanced guide will make you a Git reset and revert master able to recover from any pulled punch Git throws your way.

The Power and Peril of git pull

The git pull command is one of the most useful and dangerous ones. It fetches remote changes and tries to merge them with your local work. A botched pull can overwrite local commits and leave repositories in conflict.

According to Git survey data, 32% of developers have lost work from rebasing or pulling gone awry. And 53% said they lacked confidence recovering from Git disasters like bad pulls.

Fortunately, Git provides tools to undo pulls safely and completely. This guide will cover both simple and advanced Git techniques to bail you out of pull problems. Let‘s start by reviewing how git pull combines fetching and merging remote changes.

Anatomy of a Git Pull

When you git pull from a remote repo, a ton happens under hood. At a high level, two main steps occur:

  1. Fetch – this retrieves the latest objects and refs from the remote repositories and updates your local repo‘s remote tracking branches without touching your local branches.

  2. Merge – Git will integrate that newly fetched remote tracking branch (e.g. origin/main) into your local branch (e.g. main). This combines work and handles any conflicts between remote and local changes.

A remote pull fetches then tries to automatically merge the remote tracking branch

So in one git pull command, information travels between 3 branches:

  • Remote branch (e.g. origin/main)
  • Remote tracking branch (e.g. refs/remotes/origin/main)
  • Local branch (e.g. main)

This complexity is why problems can emerge with pulls that combine so many moving pieces between repositories.

Now what if something goes horribly wrong after you git pull? Let‘s explore your options to return sanity.

Git Reset to the Rescue

The most powerful tool to undo commits and pulls in Git is git reset. This rewinds repository history to a specific commit, abandoning everything after it.

Resetting seems simple but can behave quite differently depending on options used. The three main modes are:

  1. –mixed – Resets staging area but leaves working directory untouched
  2. –hard – Resets working directory too, discarding local changes
  3. –soft – Keeps staging area and working directory intact

The default is --mixed which is handy after most pulls. But choosing the right reset mode lets you precisely undo pulls while controlling how changes are managed.

The three modes modify HEAD plus different areas as shown

Now let‘s see resets in action undoing pull problems.

Undoing Remote Merge Conflicts

Say you fetch updates leading to merge conflicts between remote and local changes:

$ git pull origin main
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result

You could laboriously resolve this file-by-file. But since origin updates caused the breakage, let‘s entirely reset the remote tracking branch:

$ git reset --hard origin/main
HEAD is now at c1534a9 Implement feature X  

This unstages conflicting changes and discards local work from origin problems. Test it out:

$ git status
Nothing to commit, working tree clean

Voila, those awful merge conflicts are ancient history!

When Hard Resets Go Wrong

Resetting can also dangerously delete precious commits, as this sorrowful story shows:

$ git reflog  
336e392 HEAD@{0}: pull: Fast-forward
c69892f HEAD@{1}: commit: Finish new dashboard  
ae3b6a4 HEAD@{2}: commit: Start on dashboard

$ git reset --hard origin/main
$ git status
# On branch main
nothing to commit, working tree clean  

$ git reflog
336e392 HEAD@{0}: reset: moving to origin/main
c69892f HEAD@{1}: commit: Finish new dashboard

Our dashboard work has vanished before our eyes! Luckily we can rescue erased commits with:

$ git reset c69892f 
$ git reflog 
c69892f HEAD@{0}: reset: moving to c69892f
336e392 HEAD@{1}: reset: moving to origin/main  

So git reflog shows a breadcrumb trail to missing commits. Phew—dashboard restored!

Resetting Remote Tracking Branches

You can also directly reset a remote tracking branch after a mangled pull operation:

git fetch origin 
git reset --hard origin/main

Be careful as this obliterates local commits origin overwrote. Best to only reset remote tracking branches you just fetched rather than ones with days of divergence from the remote.

Git Revert: Reset Without Regret

Resetting is a destructive yet powerful undo technique. An alternative way to reverse pulled commits is using Git‘s revert command.

Reverting creates brand new commits that effectively cancel out unwanted commits:

$ git revert bdf1eca  

It leaves existing commit history intact while adding compensating changes. Kind of like a Git time machine!

New revert commits (orange) cancel effects of older commits

Key differences between revert and reset include:

Reset Revert
Deletes commits from history Adds new commits to history
Discards old changes Applies inverse changes
Alters project history Preserves project history
Loses uncommitted work Safe for uncommitted work

So if you crave safety, git revert has your back!

Aborting Pulls with Revert

If remote file changes clobber work-in-progress local files during a pull, revert to the parent commit aborts the destructive pull while keeping your local changes:

$ git log --oneline 
c776018 Update README
f236520 Add index page

$ git revert HEAD~  
# Reverts pull commit f236520

$ git status  
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
    modified:   index.html

Now just commit to save files the remote pull stomped on. Much easier than resolving painful merge conflicts!

Reverting Merged Branches

What if you already merged an errant feature branch, realized your folly, then want to revert it entirely?

git revert -m 1 undoes the merge plus all feature branch commits in one mega-revert:

Revert merge commit (green 1) plus feature commits (blue 2)

Compare this to what a reset would involve on a branch merged long ago. Revert lets you turn back time as if the merge never happened—sweet instant relief!

Recovery Pro Tips

As you gain Git revert and reset mastery, keep these other tips in your back pocket when hot-fixing pull problems:

Look before you leap with git diff <target-commit>: Preview changes in a target rollback commit before undoing work.

Soft resets keep files staged: This avoids disturbing working directory changes.

Stash local changes before acting with git stash / git stash pop

Leverage ORIG_HEAD: Special pointer to commits before last operation—handy in merges gone bad.

Squash stray commits rather than losing them completely in distant reset rollbacks.

Pulling It All Together

Let‘s review key ideas for seamlessly undoing Git pulls:

  • Git reset rolls back existing commits by moving branch pointers
  • Use the reflog to rescue erased commits after resets
  • Git revert inserts compensating invert commits
  • Revert merges to completely unwind pulls along with merged feature work
  • Stash and diff help preview impact before undoing
  • Multiple reset modes and special refs fine-tune rollbacks

Now no merged pull request or integration surprise can ruin your hard work!

While Git doesn‘t have an obvious undo button, its reset and revert capabilities enable erasing almost anything gone wrong. Master them, and Git catastrophes need not happen.

Similar Posts