Reset a whole range of commits, at once, in a single commit, while preserving your Git history
![Reset a whole range of commits, at once, in a single commit, while preserving your Git history](/content/images/size/w1200/2024/07/time_traveling_with_git.png)
Oh no! This shouldn't have been released! We were supposed to x, y, and z first!
But it's been merged, and pushed to main
. And you can't force push; you'd have to let everyone else know, so they can handle their local tree diverging from the remote... and nobody wants that.
Or perhaps you're on your own and find git reset --hard $yourCommit && git push -f
too risky. Maybe you don't want to lose what was done in between. Or have some strong principles regarding preserving git history. Unless you simply do not have the rights to force push to that branch. Anyway, what can we do?
Git revert
The simplest thing to do is:
git revert --no-commit $oldestCommit..$mostRecentCommit
git commit -m 'revert commits from $oldestCommit to $mostRecentCommit, included'
This creates a new commit, reverting all the changes from the commits in the specific range.
If you only want to revert the last n commits, it's even simpler:
git revert --no-commit HEAD~4.. #The same as HEAD~4..HEAD
git commit -m 'revert commits from $oldestCommit to $mostRecentCommit, included'
But that only works well until you hit a merge commit. Merge commits have two parents, so trying to revert one of those will fail miserably.
Time travel (git reset)
git reset --hard $oldCommit && git reset --keep @{1}
git commit -m 'revert commits from $previousHead, included, to $oldCommit'
Yes, you read that right. We are travelling back in the past, before resetting to a future that is now gone. How cool is that?
Comments ()