Delete commits from a branch in Git

3,552,220

Solution 1

Careful: git reset --hard WILL DELETE YOUR WORKING DIRECTORY CHANGES. Be sure to stash any local changes you want to keep before running this command.

Assuming you are sitting on that commit, then this command will wack it...

git reset --hard HEAD~1

The HEAD~1 means the commit before head.

Or, you could look at the output of git log, find the commit id of the commit you want to back up to, and then do this:

git reset --hard <sha1-commit-id>

If you already pushed it, you will need to do a force push to get rid of it...

git push origin HEAD --force

However, if others may have pulled it, then you would be better off starting a new branch. Because when they pull, it will just merge it into their work, and you will get it pushed back up again.

If you already pushed, it may be better to use git revert, to create a "mirror image" commit that will undo the changes. However, both commits will be in the log.


FYI -- git reset --hard HEAD is great if you want to get rid of WORK IN PROGRESS. It will reset you back to the most recent commit, and erase all the changes in your working tree and index.


Lastly, if you need to find a commit that you "deleted", it is typically present in git reflog unless you have garbage collected your repository.

Solution 2

If you have not yet pushed the commit anywhere, you can use git rebase -i to remove that commit. First, find out how far back that commit is (approximately). Then do:

git rebase -i HEAD~N

The ~N means rebase the last N commits (N must be a number, for example HEAD~10). Then, you can edit the file that Git presents to you to delete the offending commit. On saving that file, Git will then rewrite all the following commits as if the one you deleted didn't exist.

The Git Book has a good section on rebasing with pictures and examples.

Be careful with this though, because if you change something that you have pushed elsewhere, another approach will be needed unless you are planning to do a force push.

Solution 3

Another possibility is one of my personal favorite commands:

git rebase -i <commit>~1

This will start the rebase in interactive mode -i at the point just before the commit you want to whack. The editor will start up listing all of the commits since then. Delete the line containing the commit you want to obliterate and save the file. Rebase will do the rest of the work, deleting only that commit, and replaying all of the others back into the log.

Solution 4

I'm appending this answer because I don't see why anyone who has just tried to commit work would want to delete all that work because of some mistake using Git!

If you want to keep your work and just 'undo' that commit command (you caught before pushing to repo):

git reset --soft HEAD~1

Do not use the --hard flag unless you want to destroy your work in progress since the last commit.

Solution 5

Removing an entire commit

git rebase -p --onto SHA^ SHA

Obviously replace "SHA" with the reference you want to get rid of. The "^" in that command is literal.

http://sethrobertson.github.io/GitFixUm/fixup.html#change_deep

Share:
3,552,220
hap497
Author by

hap497

Updated on July 08, 2022

Comments

  • hap497
    hap497 almost 2 years

    I would like to know how to delete a commit.

    By delete, I mean it is as if I didn't make that commit, and when I do a push in the future, my changes will not push to the remote branch.

    I read git help, and I think the command I should use is git reset --hard HEAD. Is this correct?

    • Chris
      Chris about 9 years
      I think this is not a duplicate of Git undo last commit as it asks how to delete any commit from a branch. I also think non of the answers actually address this question. They all rewind the last commits, not cherry-pick and delete a single commit that may occurred a while ago.
    • MST
      MST about 9 years
      @Chris, the answer with git rebase -i HEAD~10 does address the question, as it does let you arbitrarily pick commits to delete. Git applies the commits in the range you specify one-by-one, ignoring commits you have removed from the log. I used this command today to get rid of the second and third most recent commits to my repo while keeping the top one. I agree that none of the other answers are satisfactory.
    • Chris
      Chris almost 9 years
      @MST yes, I should have said, non of the options in the accepted answer address this question, but you are absolutely right - that command seems to work
    • sergpank
      sergpank about 3 years
      I think git reset --soft HEAD~1 is exactly what you need. In such case you will undo commit and save your work. reset --hard will remove commit completely.
    • Amin Golmahalle
      Amin Golmahalle about 3 years
      command: git log | head -n 1 | git revert
    • questionto42standswithUkraine
      questionto42standswithUkraine over 2 years
      Luckily, I could just write an empty commit message and with that, the commit was not commited :), so that I did not need to delete it. TL/DR: I had by chance run the command git commit -a, thinking it was a short form of git commit --amend (which it is not) and was in a new empty commit message. I could just cancel the editor (using :wq in vim) with the empty message and git did not create the commit and instead return Aborting commit due to empty commit message.
  • Anonigan
    Anonigan almost 15 years
    HEAD~1 or just HEAD^. If you pushed, you should use git revert instead.
  • nuala
    nuala about 12 years
    Obviously you can also use HEAD~n to "go back" n commits from your head. Maybe from this point you can interpreted ... --hard HEAD also as HEAD~0 => deleting work in progress.
  • Chad
    Chad almost 12 years
    @beamrider9 That is what --hard means.
  • prathima krishna
    prathima krishna over 11 years
    thx, btw if you run into any issues (like empty commits) you can use git rebase --continue
  • Noah Sussman
    Noah Sussman over 11 years
    @beamrider9 imho git rebase is almost always the better way to delete commits (as described in Greg Hewgill's answer) -- not least because rebase does in fact include a big warning that you will be deleting stuff 4realz.
  • rogerdpack
    rogerdpack over 11 years
    maybe this should be modified to mention --soft ?
  • Steve Bennett
    Steve Bennett over 11 years
    Here's an example of why: you do a small piece of work on a development server that you commit. Then it turns out that that server doesn't have outgoing HTTPS access, so you can't push the commit anywhere. Easiest to just pretend it never happened, and redo the patch from your local machine.
  • Igbanam
    Igbanam over 11 years
    this doesn't delete changes from the commit tree though. The OP asked for an already made commit. If you reset --hard, and check the log --oneline --all, the commits still remain in the tree. How do we delete these commits from tree? Thanks.
  • Bukov
    Bukov about 11 years
    Note: If you happen to have any --no-ff merges in that last batch of commits, rebase will butcher them :( This is mentioned under -p on this page. The problem is, if you replace -i with -p, you no longer get that pop up with the choices for "edit this commit, sqush that one", etc etc. Anyone know the solution?
  • Will Nielsen
    Will Nielsen about 11 years
    Thanks for the thorough documentation here. The only thing I'd add is that rebase typically is used to deal with multiple branches rather than deleting a single commit in a single branch.
  • codeling
    codeling about 11 years
    @KarthikBose there would always be the reflog. even after git reset --hard HEAD~1 your previous latest commit would be available via reflog (until you expire it); see also here: gitready.com/intermediate/2009/02/09/…
  • Goldentoa11
    Goldentoa11 about 11 years
    Maybe I'm using git wrong, but one situation I'd like the --hard option for is when I've got multiple remote branches and I pushed to the wrong branch. Say I've got a master branch and a staging branch, I do work on a local branch, but then accidentally merge and push into master, and then realize I did the wrong thing. I'd then want to restore master's HEAD to the second most recent commit and want to remove all trace of that faulty push from master, as it's not supposed to be in master
  • UpAndAdam
    UpAndAdam almost 11 years
    you could just as easily do git commit --amend in this scenario which is way less confusing
  • mmell
    mmell almost 11 years
    Even easier: git rebase -i HEAD~1
  • Admin
    Admin almost 11 years
    use reset --soft to delete local commit WITHOUT reverting work in progress!
  • Darren Cook
    Darren Cook over 10 years
    Is this better than the "reset hard" answer as it won't delete the files, just the mistaken commit message? Because it appears to have deleted my files. If deleting the file is supposed to happen, please add that as a clear warning!
  • Pascal Cuoq
    Pascal Cuoq over 10 years
    The order in which answers are shown on StackOverflow is not fixed. Please do not refer to “All the commands above”. Make your own answer self-contained.
  • Alsciende
    Alsciende over 10 years
    Thanks. This answer should be ranked higher or included in the accepted answer. Deleting a commit != reverting a commit.
  • Costa Michailidis
    Costa Michailidis about 10 years
    That didn't work. When I git log, everything is still there, no matter why I do it just adds more commits. I wanna clean up the history.
  • Anonigan
    Anonigan about 10 years
    @Costa: What didn't work (i.e. which version did you use), and how did you git log?
  • Costa Michailidis
    Costa Michailidis about 10 years
    I've tried almost everything on this Q&A. (I tried git revert HEAD, most recently) My git log: tree = log --all --graph --format=format:'%C(bold blue)%h%C(reset) %C(dim black)%s%C(reset)%C(bold red)%d%C(reset) %C(green)by %an, %ar%C(reset)'
  • Anonigan
    Anonigan about 10 years
    @Costa: Note that with first version (using git reset --hard HEAD^) you "remove" commit only from current branch (actually move branch pointer), if there was some other branch this commit was on it would still be there. "Removing" commit with git reset just moves back branch pointer, making commit dangling and available for pruning... if not referenced by other ref (other branch, remote-tracking branch, or tag). Or did you use git revert HEAD?
  • Costa Michailidis
    Costa Michailidis about 10 years
    I just want to delete the commits (like as if they never existed). I went off on some weird coding adventure, with several new commits, and it all ended up being trash. How can I just erase those from my git log?
  • Costa Michailidis
    Costa Michailidis about 10 years
    Holy crap something magically did exactly what I wanted.... which one of those commands did it?!!?!
  • Admin
    Admin about 10 years
    This answer isn't entirely correct. git prune is actually one of the "porcelain" commands. Also, it is rare that you would want to completely clear out your reflog (one use case is to remove sensitive info from your repo, but like I said, that's a rare use case). More often than not, you'll want to keep old commits around in the reflog, in case you need to recover data. See Pro Git: 9.7 Git Internals - Maintenance and Data Recovery.
  • naught101
    naught101 almost 10 years
    @RandolphCarter: you will still lose any uncommitted changes though.
  • Charles Wood
    Charles Wood over 9 years
    Wowzers. git rebase -i HEAD~1 really cleaned the repo up a lot! It's hard to tell exactly what it did, but the whole thing looks a lot neater. A little alarming, actually.
  • Costa Michailidis
    Costa Michailidis over 9 years
    What if you have pushed it? (just me using the remote repo)
  • Greg Hewgill
    Greg Hewgill over 9 years
    @Costa you can use push -f to force the push and replace the remote branch with your local one. If it's just your own remote repo, no problem. The trouble starts if somebody else has fetched in the meantime.
  • bradw2k
    bradw2k over 9 years
    Glad I read the comments to learn that this answer doesn't actually answer the question, there should be NO leftovers in the repo "as if I didn't make that commit."
  • aldo
    aldo over 9 years
    I added and committed a data file that was too big for GitHub (yeah, it probably shouldn't be in the source repo anyway; Oh well). When I tried to push, GitHub refused because of the too-large file. All I wanted to do was undo this one commit, while saving a few other unrelated commits that followed. The git rebase -i HEAD~5 command was exactly what I needed to completely remove this commit from my local repo! Thanks!
  • Max Nanasy
    Max Nanasy over 9 years
    @Bukov The documentation says you can use both -i and -p, but if you do, "Editing commits and rewording their commit messages should work fine, but attempts to reorder commits tend to produce counterintuitive results." I'm not sure how well deleting commits would work, but you could try it and then do a reset --hard to before the rebase (using the reflog) if it doesn't work out properly.
  • Chris Middleton
    Chris Middleton about 9 years
    When a commit is empty, git rebase will display that line commented out (#). If you don't uncomment that line, git will delete the commit when rebasing. Deleting the empty commit is actually exactly what I was trying to do, but if you want to keep yours, un-comment out the line first.
  • Zaz
    Zaz about 9 years
    I think it's worth noting that the commit is not obliterated, merely removed from the list. If you mess up, you can get the commit back using the reflog.
  • Akshat Agarwal
    Akshat Agarwal almost 9 years
    You sure deserve an upvote because I have looked this up atleast 5 times in the last year
  • Eric Hepperle - CodeSlayer2010
    Eric Hepperle - CodeSlayer2010 almost 9 years
    Confirming that in Sept 2015 this worked for me git reset --hard <sha1-commit-id> to make the last commit "like it never even happend"
  • mckelvin
    mckelvin over 8 years
    Or git rebase -i 592d26e9131e0a5a9b6ada78ab1574688cbbf9b7^ while 592d26e9131e0a5a9b6ada78ab1574688cbbf9b7 is the id of an earliest commit you want to delete.
  • Steve Bennett
    Steve Bennett over 8 years
    Yes, but the OP was clear that that's not what they want.
  • Steve Bennett
    Steve Bennett over 8 years
    That's not what OP is asking for.
  • Lucas Huang
    Lucas Huang about 8 years
    Obviously, it's pushed to the repository based on the OP.
  • dumbledad
    dumbledad about 8 years
    When it deletes the commit does it also delete the changes (like --hard in the original post) or does it leave them intact but uncommitted (c.f. --soft)?
  • Greg Hewgill
    Greg Hewgill about 8 years
    @dumbledad: With rebase -i, the changes corresponding to the deleted commit are not preserved.
  • Leo
    Leo about 8 years
    Is deleting the line the same as d/drop?
  • Sheelpriy
    Sheelpriy about 8 years
    git push --force <origin> <branchName>. as without mentioning branch name it might change all file on remote.
  • Bob Meyers
    Bob Meyers over 7 years
    @Rob, one example is when you accidentally commit a file that contains a secret (e.g. a password) that should never be in source control. The local commit must be destroyed, not just undone, so it will never get pushed to the server.
  • xhienne
    xhienne over 7 years
    @LucasHuang No, it's not: "when I do a push in the future, my changes will not push to the remote branch"
  • 1800 INFORMATION
    1800 INFORMATION over 7 years
    @dragonmnl deleting or modifying pushed commits is something that I understand is not recommended
  • Gabe Halsmer
    Gabe Halsmer over 7 years
    This worked great! I did not want to undo everything, only a few folders in my last couple commits. HARD could have worked, but I would of had to save off all my changes that I wanted to keep and patch them in latter. SOFT removed the local commits. And "git reset HEAD -- ." was also necessary to remove staged changed. Then I could remove all the bad things manually, and everything else - my other changes - were left intact.
  • Armen Michaeli
    Armen Michaeli about 7 years
    I don't understand why everyone is recommending git reset --hard ... and then proceeds to explain how one should watch out for working directory changes etc. Well, why not use the more apt and less dangerous git reset [--soft] (i.e. soft or mixed reset) instead?
  • IliasT
    IliasT almost 7 years
    Dropping the commit through a rebase is a less aggressive solution to achieve the same goal. See my answer for more details.
  • mfaani
    mfaani almost 7 years
    Please correct me if I'm wrong: I always that HEAD~1 means 'Go to the previous commit'. But the 'Go to' is a result of the command. HEAD~1 just means 'previous commit'. The command reset --hard HEAD~1 means Go to <this previous commit>`
  • gahooa
    gahooa over 6 years
    HEAD is a reference to the currently checked out commit. HEAD^ references it's parent. HEAD^^ references it's grandparent. HEAD~N references it's Nth parent. If you look at git log you will see that HEAD~3 is the 4th entry down. And yes, these can be used on any git operation that requires a commit as an argument. A branch, by the way, is just another reference to a commit :)
  • vivex
    vivex over 6 years
    last step should be git push -f origin master there is no option --hard
  • Oleg Abrazhaev
    Oleg Abrazhaev over 6 years
    In the latest git version there is no more option d. You need just remove lines with commits from rebase to delete them.
  • bapors
    bapors over 6 years
    Thank you for this link! I was wondering, after running this, why do I still see the commit SHA in my git reflog?
  • Serge Roussak
    Serge Roussak about 6 years
    Why do we need the -p here?
  • raittes
    raittes almost 6 years
    -p, --preserve-merges Recreate merge commits instead of flattening the history by replaying commits a merge commit introduces. Merge conflict resolutions or manual amendments to merge commits are not preserved.
  • Jarek C
    Jarek C over 5 years
    I guess commit 0 is older than commit 1. Please could you tell me why first run through commit 3 (by cherry-pick) and then by commit 1? After checkout of b3d92cd (commit 0) I would expect cherry-pick commit 1, then commit 3. Thanks.
  • Shayan Salehian
    Shayan Salehian over 5 years
    drop keyword is not defined. To delete a commit just remove the whole line.
  • Jeff Huijsmans
    Jeff Huijsmans over 5 years
    @JarekC I think the top-most commit is the newest commit here, unless I'm seeing something wrong...
  • Adam Parkin
    Adam Parkin about 5 years
    For me drop was defined as a keyword, but doing a drop didn't seem to remove the commit from the history. Removing the line from the interactive rebase however did.
  • user373201
    user373201 about 5 years
    I had merged instead of rebasing and my pull request showed other changes then mine. running git rebase -i HEAD~1 cleaned it up. Thanks to mmell
  • Rubicksman
    Rubicksman about 5 years
    It says, "replace SHA with the reference you want to get rid of" but the line has SHA in there twice. Here is what I did. git rebase -p --onto 5ca8832c120^ 5ca8832c120 But nothing changed. Am I supposed to use the same SHA twice? If not, then which is the SHA for the commit to be removed and what is the other SHA supposed to be?
  • goofology
    goofology almost 5 years
    to be specific, this method removes ENTIRE commit, including files (not desired in my case)
  • goofology
    goofology almost 5 years
    @Rubicksman ^ must be escaped (^^) on windows (cmd window) - stackoverflow.com/questions/1955985/…
  • Dani
    Dani over 4 years
    if I have unpushed commits and uncommitted changes, will git reset --hard delete my commits?
  • gahooa
    gahooa over 4 years
    @DanielSpringer, git reset --hard <commit> will reset your HEAD to the specified commit, and discard any changes in your index. Any working tree files that are untracked and have not been added to git will remain. You can use git clean -df to remove them, though, exercise with great care.
  • Dani
    Dani over 4 years
    What if I don’t specify a commit? Will unpushed commits be lost?
  • Dani
    Dani over 4 years
    How can I dismiss uncommitted changes? The only way I know is git reset --hard
  • Farzad Yousefzadeh
    Farzad Yousefzadeh over 4 years
    First time ever I dared to use rebase and it worked smoothly.
  • dimpiax
    dimpiax over 4 years
    on mac: git rebase --onto SHA~ SHA
  • syedelec
    syedelec over 4 years
    -p [DEPRECATED: use --rebase-merges instead]
  • c0der512
    c0der512 over 4 years
    Unless you have already pushed the changes. In that case hard reset will not clean up your remote. In that case rebase is the good option
  • diekunstderfuge
    diekunstderfuge over 4 years
    This is exactly what I needed. Works great; thanks!
  • Alexis Wilke
    Alexis Wilke about 4 years
    That worked that is, I was able to remove a commit but then I just can't push the results so it's just completely useless. Maybe because I already pushed earlier?
  • Karan Bansal
    Karan Bansal almost 4 years
    stackoverflow.com/a/32318688/2694784 is better as it shows how to remove a commit which is not on the top.
  • leanne
    leanne almost 4 years
    I deleted the line as suggested in several places: it didn't do anything. Replacing the word pick with drop did delete the commit. Note: the instructions are in the remarked-out section in the bottom portion of the text editor's contents. Using git version 2.24.3 (Apple Git-128)
  • an4s911
    an4s911 almost 4 years
    I tried this and I got my latest commit removed but now when I push to the remote repository it says I have to pull before push. So I pulled and then pushed but when I pulled I again got the commit that I just removed because I pushed it before to remote. What should I do now?
  • Joshua Swain
    Joshua Swain over 3 years
    This is mostly right but kind of wrong. I just followed this process and had to tweak it a bit. Clarification: commit 0 is the newest commit, commit 4 is the oldest. Start by checking out commit 5, just before the commit that you don't want. Then cherry-pick commit 3, then cherry-pick commit 1, then do it for commit 0. Then checkout master and reset it to commit 5 and follow the rest of the steps.
  • camslice
    camslice about 3 years
    Good thorough and safe approach. Managing the changes on a separate branch means you can even do interactive rebasing on the repair branch and combine commits before merging back in to master. The only comment I have is that you can consolidate the first two steps: git checkout -b repair b3d92c5
  • utkarsh-k
    utkarsh-k about 3 years
    @JoshuaSwain As per my understanding of this answer, commit 4 is the latest one and commit 0 is the oldest one. One reason for that is - He is merging master with repair branch in the end so that the final tree of master looks as if commit 2 and commit 4 were not there. So far so good? Now before doing this merge he reset the master to commit 0 and then merging the two good commits from repair branch. If commit 4 was the oldest then he woudn't have reset master to b3d92c5 instead would have reset to 77b9b82
  • tk_
    tk_ about 3 years
    @utkarsh-k I added a small note to the first line to clarify your point. Feel free to improve my answer using the edit feature. Thanks :)
  • Cesar Varela
    Cesar Varela almost 3 years
    SO needs a button that says "this is actually the answer"
  • eho
    eho almost 3 years
    After rebasing, you will probably have to force push. Suggest doing git push --force-with-lease as this is a safer force push. Also often you can replace HEAD with just an @ (e.g., git rebase -i @~1)
  • leopinzon
    leopinzon over 2 years
    This question isn't about intelliJ, but about Git itself.
  • Wilan
    Wilan over 2 years
    git reset --soft HEAD~1 worked perfectly for me. Makes sure I don't lost to changes from that commit. Thank you for your clear answer.
  • Harshad Panmand
    Harshad Panmand about 2 years
    rebase will not work if you have stashed changes