DEV Community

Cover image for Time Traveling Through Your Repo: Git Reset vs. Revert
David Ochiel
David Ochiel

Posted on

Time Traveling Through Your Repo: Git Reset vs. Revert

Once upon a commit, in the mystical realm of version control... jokes aside πŸ˜…. Wassup fellow git adventurers! Today we'll be embarking on a journey through the mysterious realms of version control. We'll dive deep into the git universe to understand the mysterious powers of two commands: reset and revert. Buckle up, because this ride might get a bit bumpy, but fear not, for I shall guide you through with wit and wisdom!

The Maverick Reset

Ah, the mighty git reset, a command so potent, it can make your HEAD spin. But wait! What is this enigmatic "HEAD" in the realm of git?

  • It's like the captain's chair of your spaceship. It points to the current position within your repository. Picture it as the guiding compass of your git repository, pointing to the very tip of your current branch. It's the nucleus around which your commits orbit, determining what snapshot of your project you're currently viewing or altering.
  • If you are on the master branch, HEAD will point to the latest commit on that branch. So when you hear about "resetting HEAD," it's like repositioning captain git's chair to a different point in space-time, perhaps to a previous commit or even a different branch altogether.

Back to our friend reset. Imagine you're in a time machine, and you want to teleport back to a previous commit. Well, git reset is your DeLorean, ready to whisk you away to the past. But beware, fellow time travelers, for with great power comes great responsibility! Git reset without caution can lead to catastrophic consequences. One wrong move, and poof! Your commits vanish into the digital abyss faster than you can say "commitment issues." So, before you hit that reset button, remember to backup your work.

Assuming the following is your commit history, let's talk about the responsibilities you'll have, going the maverick way:

C1 - C2 - C3 - C4 - C5
Enter fullscreen mode Exit fullscreen mode

Types of Reset

  • Soft Reset: It's akin to a cautious peek into the time-traveling toolbox of coding. You move HEAD to a previous commit, but your changes stay staged, as if hitting the pause button on your code's journey through time. From the commit history above, say you want go back to C2. Running git reset --soft <hash-for-C2> or git reset --soft HEAD~3 will uncommit the changes from C3 to C5, but will keep them staged. To get the hash for your commit, run git log then copy the desired hash. In HEAD~3, 3 is the number of steps it takes to get to C2. Hopefully your "head" is not spinning though. Pick the convention that suits you. Let's look at an example.

Suppose you have the following in your working environment.

.gitignore
app1.py
app2.py
Enter fullscreen mode Exit fullscreen mode

You then decided to commit the two apps.

git add app1.py app2.py
git commit -m "feat: add apps"
Enter fullscreen mode Exit fullscreen mode

Then later realized that you forgot to add the .gitignore file (meaning it is still unstaged), you can do the following.

# HEAD will get the very last commit
git reset --soft HEAD
git add .gitignore
git commit -m "feat: add apps and gitignore"
Enter fullscreen mode Exit fullscreen mode
  • Mixed Reset: Feeling a bit indecisive? This reset moves HEAD and resets the index to a previous commit, leaving your changes unstaged. Running git reset <hash-for-C2> will keep the changes from C3 to C5 unstaged. With the files in the example above, after committing the two apps, run git reset HEAD. Both the three files will then be unstaged, including the two that were initially committed.

NOTE that with mixed reset, you do not have to include the --mixed flag.

  • Hard Reset: Ready to go all-in? Brace yourself, because this reset moves HEAD and resets both the index and working directory to a previous commit. It's like a cosmic eraser, wiping away your changes without mercy. Use with caution! To achieve it, run git reset --hard <hash-commit-C2>. This will do away with all the changes after C2 from your repository.

Let's take a look at an example by adding some files to the previous working tree. Assuming you committed the three files, then added one file. The new file (README.md) will be in an untracked status. Run git add . or git add README.md, according to your preference, to add it to your staging area then commit the changes, say, git commit -m "docs: add readme" Let's assume the hash for this commit will be 212w544. Your current working tree should now be as follows:

.gitignore
app1.py
app2.py
README.md
Enter fullscreen mode Exit fullscreen mode

Now by running git reset --hard <commit-hash-before-212w544> the commit 212w544 will be discarded together with it's file (README.md). Your working tree should now be as follows:

.gitignore
app1.py
app2.py
Enter fullscreen mode Exit fullscreen mode

Ready to rewrite history?

  • After traversing the depths of time with your hard reset, it's now the moment to rewrite history. To discard the contents in your remote repository like github, gitea, or gitlab, run git push <remote-name> <branch-name> --force.
  • This command will overwrite the history in the remote repository with the changes from your local repository, effectively discarding the unwanted changes.

CAUTION!!!

  • In case you were working on a project with collaborators, this can potentially cause issues for those who have pulled the changes. Make sure to communicate with your team before force pushing to avoid conflicts.
  • Ensure you have a backup of the remote repository in case you need to revert the changes.

The Renegade Revert

Now, let's talk about git revert - the rebel with a cause, the anti-hero of version control. Unlike reset, which rewrites history like a stealthy ninja, revert takes a different approach. It acknowledges the past but refuses to let it define the future. Basically it's used to undo changes introduced by a specific commit, creating a new commit that reflects the reversal. It maintains a clear and linear history by documenting the reversal as a new commit.

Here is how it works

Suppose the following is your commit history:

C1 - C2 - C3 - C4 - C5
Enter fullscreen mode Exit fullscreen mode

We want to undo the changes introduced by commit C2. Check the hash for your commit by running git log, then do the following:

git revert <hash-for-C2>
Enter fullscreen mode Exit fullscreen mode

If you use the HEAD convention, it will be:

git revert HEAD~3
Enter fullscreen mode Exit fullscreen mode

If there are conflicts during the revert process, resolve them manually. Git will guide you through the conflict resolution process.

After juggling with conflicts like a clumsy magician (sorry, what I mean is, after resolving all the conflicts), run git revert --continue to continue with the revert process. This will finally create a new revert commit, C6, that undoes the changes introduced in C2, leading to the following history:

C1 - C2 - C3 - C4 - C5 - C6
Enter fullscreen mode Exit fullscreen mode

Revert a revert

  • Some times you can find yourself in a git time loop, reverting a revert, undoing an undo.
  • This often happens when you revert a commit only to realize it was a mistake, disrupting the fabric of your code continuum. But wait! Is that a glimmer of hope on the horizon? Yes, it's the git time machine offering you a chance to set things right.
  • All you gotta do is git log to find the hash for the revert commit, in our case it will be the hash for C6.
  • After getting the hash, run git revert <hash-for-C6>, which will create a new revert commit, C7, that undoes the undone changes introduced in C2, leading to the following history:
C1 - C2 - C3 - C4 - C5 - C6 - C7
Enter fullscreen mode Exit fullscreen mode

The contents of the above history will be like when it started, as below:

C1 - C2 - C3 - C4 - C5
Enter fullscreen mode Exit fullscreen mode

When you are done with your revert(s), if need be, git push the changes to your remote repository.

Choose Your Destiny

Your mission, should you choose to accept any of these methods, is to rewrite history without causing a paradox. If any of your projects vanish or get tangled in a time loop, the keyboards responsible for this article will disavow any knowledge of your actions. This article will never self-destruct... well, unless a glitch in the space-time continuum intervenes. Good luck git adventurers. Some of you might get the humor after traveling "back to the future" πŸ˜…. Essentially though you can:

  • use git reset when you want to rewind the HEAD or branch pointer, and you're okay with discarding changes.
  • use git revert when you want to undo changes in a public branch without rewriting history.

So, which path will you choose? Whichever path you take, experiment, explore, but always tread carefully. Until next time, cheerio 😁.

Top comments (0)