Removing a commit from a branch is similar to removing an item from a slice in Golang. You need to select the ranges you want to keep then append the latter to the former.
Go to the branch you want to work on.
git checkout {branch}
View the commits on the current branch. Identify the commit you want to remove.
git lolc
If it's the latest (or near-latest) commit, you can simply rollback and re-apply any later changes. Let's pretend it's the second-to-last commit, and the last commit we want to re-apply was a PR.
git rollback 2
git nuke # If you want to nuke the changes you rolled-back from the local branch.
git push --force {branch}
At this point, the remote HEAD and local HEAD have been rolled-back.
Now, does your PR branch contain the commit you just tried to remove?
git checkout {pr-branch}
git cherry-pit {commit}
git push --force {pr-branch}
Then select the "merge" button in the GitHub interface.
Already merged? Bummer. Do you still have the branch locally?
git checkout {merge-into-branch}
git merge --ff {pr-branch}
git push --force {merge-into-branch}
Now, anyone who has already pulled the bad commit into their repo will need to do a little work to clean-up. The commits on master/main are no longer fast-forward and that's gonna mess things up.
NOTE: If your "main" branch is
main
ormaster
, go ahead and use the right name for the branch in the explanation below.
We're going to delete and re-fetch your local main
branch.
Check out any other branch. It doesn't matter — you're just moving out of the way. (You can even create a new branch from the current one, just to get out of the way: git checkout -b new-branch
.)
git checkout <any other branch>
git branch -D main
Fetch the available branches from the remote.
git fetch --all
git fetch {remote} --all
Create a new local branch from the upstream branch.
git checkout {remote}/main
git checkout -b main
And if you have a different upstream remote that you need to sync-up with, go ahead and force-push there as well.
git push -f origin master