I have a merge commit on a Git repository that I want to delete.
How to really delete a commit from git?
I mean DELETE a commit that has no commits after it. I just do not want it clogging the history (and occuping disk space).
Please do not answer with anything like "git -i rebase" as you can not use rebase to delete a commit with no child commits.
0 <-this is now HEAD and master
|
| this is a different merge between the same branches, master and hotfix-1
| /
0 0 <-THIS is the commit I want to DELETE (incorrect merge)
|\ /|
| X |
|/ \|
0 0
| |
| |
| |
| 0
| |
| |
| |
0 0 <- this is start of branch hotfix-1
| /
| /
|/
0
|
EDIT:
Please do not answer with anything like "git reset --hard HEAD~1" as that does not delete the commit for merge commits:
user@host /dir/subdir (master)
$ git checkout b605a0dd5e12e65081a2d8ffe7c905617b210605
Note: checking out 'b605a0dd5e12e65081a2d8ffe7c905617b210605'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at b605a0d... Merge branch 'hotfix-1'
user@host /dir/subdir ((b605a0d...))
$ git reset --hard HEAD~1 ## TRYING TO DELETE COMMIT
HEAD is now at 65e8158 Some commit message
user@host /dir/subdir ((Some tag))
$ git checkout b605a0dd5e12e65081a2d8ffe7c905617b210605
Previous HEAD position was 65e8158... Some commit message
HEAD is now at b605a0d... Merge branch 'hotfix-1'
user@host /dir/subdir ((b605a0d...)) ## COMMIT STILL THERE
$
If the commit has nothing referencing it, e.g. branches or tags, then the commit is unreachable and effectively removed from the history. It will be eventually garbage collected and physically removed from the repository database.
You can run force a garbage collection run by running git gc --prune=now, so that should get rid of the unreachable objects.
Note that you generally do not need to do this as the unreachable commits are not sent anywhere, and only exist temporarily in your repository. Keeping unreachable commits around will help you to restore commits in case something went wrong and branch pointers went missing. So unless you actually have memory issues, I personally wouldn’t recommend you to prune your repository.
As poke correctly informed you (your dismissive response notwithstanding) a commit with nothing referencing it can be garbage-collected, and there is no "more direct" command to delete the commit than gc.
The problem, of course, is that something probably is still referencing that commit. That "something" is the ref log.
The vanity of insisting on removing all traces of a mistake is a waste of effort. The problem (such as it is) will go away on its own over time (because the reflog will expire and then gc will catch up with the commit), and in the mean time a single merge commit is not even remotely likely to occupy significant disk space.
That doesn't mean it's impossible, but it comes at a cost. You can either
(A) Wipe out your reflogs and then run gc. Of course you'll have to make sure that any reflog that could point at the offending commit is discarded. That's at least the HEAD reflog and the reflog for the branch on which the merge occurred. You'll likely lose useful reflog history in the process.
or
(B) Create a fresh clone. Assuming you fixed the merge before pushing, then the merge commit shouldn't be present on origin. Any fresh clone would then not contain the commit. (They also will not have any of your reflog history, so this really is equivalent to (A).)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With