Git Good #1: Rewriting History

by @jaasonw

May 23, 2022 • 5 min read

Welcome to part 1 out of ??? of my git series (super original title I know) covering slightly intermediate to advanced topics that you may or may not have been familiar with. I figured what better way to start this series than by covering some of what are possibly the most dangerous commands in git and when you might want to use them. This blog post will cover 2 methods to rewrite history.

WARNING: you almost NEVER want to rewrite history as it tends to end up being a great way to either shoot yourself in the foot, shoot someone else in the foot, or blow off the legs of everybody involved. If this is your own repository and you are the only contributor, then by all means, go off. If this is someone else’s repository then you should reconsider or instead consider using a git revert instead as it amends rather than rewrites history. However, if your intent is to erase commits from the commit log entirely then this guide is for you.

Scenario 1: You want to rewind to a specific commit, nuking all newer commits

What’s this? You accidentally directly pushed to the main branch and are now panicking because Karni might beat your ass the next time she sees you? Well there’s no need to fear because this is where dangerous git command # 1 comes into play.

git reset --hard

  1. Head over to Github and copy the SHA of the commit you want to rewind to

  2. Head over to your terminal and run git reset --hard [SHA]. This will rewind your local copy of the repository to the commit you want, discarding ALL modified changes. If you’d still like to keep the changes without committing them, just exclude the --hard

  3. If you tried to git push now, your changes would be rejected as they would rewrite history in the upstream copy

  4. To remedy this, simply run dangerous git command # 2: git push --force which should be pretty self explanatory in what it does, which is to force git to accept your changes whether it likes it or not

As you can see, our commits are now gone and your ass is now saved from Karni

Scenario 2: You want to remove a specific commit or multiple commits but keep the rest

Uh oh, you committed the wrong commit to the wrong branch and then committed more commits on top of that commit, Karni’s really gonna beat your ass now. Don’t worry, once again I got you covered with dangerous git command # 3

git rebase --interactive (or just git rebase -i)

Admittedly this command tends to be less dangerous, less easy to mess up, and actually legitimately useful for doing things like splitting a pull request with 3 features into 3 separate branches. Rebasing could honestly be a whole blog post on its own but I’ll be covering just 1 specific use case here

  1. Just like above, pick the commit you want to go back to and start picking from

  2. Head back over to your terminal and run git rebase -i [SHA], this will open a text editor, either nano or vim (personally I don’t know how to use vim so if you get vim then just press i to put it in notepad mode and use it like notepad)

  3. From here, you’ll see a list of commits past the commit you selected earlier, to remove a commit, either delete the line or replace pick with drop

  4. If you’re using vim it’s escape -> :wq to save and quit, if you’re using nano it’s ctrl + x

  5. From here you may or may not have to resolve any rebase conflicts which are just like merge conflicts so go ahead and get those resolved if applicable

  6. Once again, this rewrites history so you’ll have to use git push --force again and the commit in question should now be erased and your ass is once again saved from a beating
    Thanks for reading and once again please use caution when using these as they are as dangerous as they are powerful and you can easily lose your own or someone else's commits in the process or create a merge conflict problem for someone else when they suddenly can't push to main. Best advice I can give to minimizing this kind of damage is to only use these commands on branches/forks that only you work on and to never do this on main.

Edit 6/8/2022: Make use of newly added code block support

Read as TXT: /blog/480.txt