Undoing A Bad Commit
For our local LabVIEW User Group we have a Slack channel. Someone on there recently asked for some advice about undoing a commit in Git. They were working on a project in LV2019 and someone had accidentally opened it in LV2020, made some changes, and then pushed them to the shared remote repository. So how do you fix this? How do you undo a Git commit?
There are several answers and it all really depends on 2 variables.
- Are there any good commits (ie. changes that you want to keep) after your bad commit(s)?
- Have you published your bad commit(s)?
Undoing the most recent commit(s)
If you haven’t made any good commits after the bad one(s) and you haven’t published it yet, then the solution easy. git reset --hard HEAD^1
will undo the last commit and reset everything to the previous commit. If you need to go back further just substitute the commit ID for HEAD^1
. When you do that you will lose everything between where you are and where you reset back to. This article talks more about git reset
.
If you haven’t made any good commits after your bad commit(s) and have already pushed your changes, then you have a decision to make: Do you want to preserve the history of the remote or not? If you care about the history, skip to the next section. If you don’t care about preserving history (if the remote is private and only you have access, or you can otherwise be sure that no one has checked out your bad commit yet) then you can simply do git reset --hard HEAD^1
followed by git push --force
. The --force
tells git that it is ok to overwrite the existing history on the remote with your new history. Be sure you want to do this.
When doing a git push --force
, you may get a permissions error from the server. This is because GitLab and GitHub have the idea of protected branches. When a branch is marked as protected the server won’t let you rewrite history even with --force
. In that case, you will have to log into Gitlab and unprotect the branch, do your push --force
and then re-enable protection on that branch.
When the bad commit is not the last commit
Sometimes you don’t catch the bad commit until after you or someone else has made some good commits based on it. In those cases, you want to preserve that history and all the changes you made since the bad commit and just eliminate the changes from that bad commit. In that case, what you want to do is use the revert command: git revert badcommitID
. What this does is create a patch that undoes the changes from your bad commit and then applies that patch to your current working directory to create a new commit. Because it is adding a new commit, it is not changing your history so therefore it is completely safe to git push
afterwards with no --force
needed.
One thing to note with git revert is that it can generate conflicts that you will need to manually resolve. In that case just use git mergetool
to resolve the conflicts. When using the tool, the base is the commit you want to revert, theirs is the commit before the revert and yours is your current working copy. After you resolve the conflict git revert --continue
will finish the revert
. If you forget the commands, git status
will provide some hints. If none of the good commits touch the same files as your bad commit, then there will be no conflicts and you are ok. Git will work its magic on its own and all you’ll have to do is edit the commit message, if you care to do so.
Avoiding LV Version Problems
I should talk a little about preventing the cause of the bad commit in this particular case, which was opening something in the wrong LabVIEW version. I recommend against having multiple versions of LV on the same computer. I highly recommend using Virtual Machines on either a per-project or per LV version basis (preferably per project). This makes it a lot more unlikely to open something in the wrong LV version. It also fixes a whole host of other problems as well. If you are going to have multiple LV versions installed on the same machine, I recommend this tool that I built.