For the sake of simplicity, I’ll consider the case where you want to delete your latest commit. The command for this, locally, is git reset --soft HEAD~
. If you want to delete older commits, you can use something like git rebase -i [commit ID right before the one you want to delete]
(see more details there).
The problem I’ll focus on here is how to push your changes, now that you’ve removed something that was already pushed (and possibly added another commit on top). The command is trivial, it’s git push -f origin master
(replace origin and master with the remote and branch names). But you may face a bunch of errors when trying to run it.
The first error I got was:
git@gitlab.com: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
I’m on Windows, and apparently Git is unable to use my SSH key, despite it being loaded in pageant (and as a matter of fact, usable when I push with SourceTree). The solution to this is to add the path to plink.exe
in the GIT_SSH
environment variable. You can set it permanently via the usual UI (or via Rapid Environment Editor), or you can set it temporarily, like I did, via the command line using set GIT_SSH=C:\PATH\TO\plink.exe
. NB: don’t use quotes, or you’ll get something like error: cannot spawn "C:\PATH\TO\plink.exe": Invalid argument - error: cannot spawn "C:\PATH\TO\plink.exe": Permission denied
. If you happen to have spaces in this path, maybe escaping them (slash-space “\ “) will work. Or just use the GUI. Or move plink to a folder without spaces.
If you’re on another OS, you might find a more appropriate fix for you in this thread.
The second error I got was remote: GitLab: You are not allowed to force push code to a protected branch on this project.
I had never protected a branch, but I quickly realized that Gitlab protects the master branch by default. You can unprotect it in Settings → Repository → Protected Branches (and once you’re done, maybe you’ll want to protect it back) (source).
And that’s all the trouble I had, git push -f origin master
(or just git push -f
if you just have one repo and one branch) should work now.
Update (2025-07-15): orphan branch strategy
This one isn’t to delete just one or a few latest commits, but rather to wipe a whole branch and keep only one last, new commit.
git checkout --orphan newmain
git add -A
git commit -m "First commit"
git branch -D master
git branch -m master
git push -f origin master
For an explanation of these steps, in case it’s not obvious enough, see my comment below the post.
Note that at least half of the steps can be done from SourceTree, notably the force push at the end (something which I hadn’t noticed when initially writing this post), there’s a checkbox kind of hidden at the bottom of the push dialog. Way more convenient than messing around with plink and GIT_SSH, IMO.
Bonus: to wipe all history and put all the code in a unique commit. Assuming you’re using branch “master” and want to empty it.
First, make sure the currently loaded code is the one you want to keep. Then:
git checkout –orphan main
git add -A
git commit -m “First commit”
git branch -D master
git branch -m master
Then force push as described above.
In case you need details, these commands create a new empty branch named “main”, then add all files to it, then commit with message “First commit”, then delete the master branch, then rename “main” to “master”.