214

I entered a curseword in my code and I pushed the code on the master branch. I pushed a few more times after that so people do not pull the bad stuff, but I can still find the curseword in the commits history.

I don't want to add the file to .gitignore because we need that file.

Is there a way to delete the commit from history?

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Serban Stoenescu
  • 3,136
  • 3
  • 22
  • 41
  • 3
    So here is a major suggestion: Always check your commits one-by-one before pushing them. ALWAYS. – ckruczek Jun 17 '15 at 13:40
  • possible duplicate of [Remove sensitive files and their commits from Git history](http://stackoverflow.com/questions/872565/remove-sensitive-files-and-their-commits-from-git-history) – Andrew C Jun 17 '15 at 15:13
  • 6
    It's so funny because it actually happened to me too but I didn't notice until it was too late and two weeks after the commit the team leader came to me and sit down to talk to me. xD – Ariel Dec 29 '19 at 18:54
  • Find the steps in this [answer](https://stackoverflow.com/a/71269693/7417998). – Suresh Nov 03 '22 at 13:35

4 Answers4

213

Once you push to the repo, you really don't want to go about changing history. However, if you are absolutely sure that nobody has pulled/fetched from the repo since your offending commit, you have 2 options.

If you want to remove the "bad" commit altogether (and every commit that came after that), do a git reset --hard ABC (assuming ABC is the hash of the "bad" commit's elder sibling — the one you want to see as the new head commit of that branch). Then do a git push --force (or git push -f).

If you just want to edit that commit, and preserve the commits that came after it, do a git rebase -i ABC~. This will launch your editor, showing the list of your commits, starting with the offending one. Change the flag from "pick" to "e", save the file and close the editor. Then make the necessary changes to the files, and do a git commit -a --amend, then do git rebase --continue. Follow it all up with a git push -f.

I want to repeat, these options are only available to you if nobody has done a pull or fetch that contains your offending commit. If they have, doing these steps will just make matters worse.

KiriSakow
  • 957
  • 1
  • 12
  • 22
David Deutsch
  • 17,443
  • 4
  • 47
  • 54
  • 1
    Just exposed my private email in a newly created repository by mistake. Phew, that saved my nerves, thank you. – Liebster Kamerad May 11 '20 at 12:38
  • 3
    if ```git rebase --continue``` or ```git push -f``` is giving you an error; check: https://stackoverflow.com/questions/30471557/git-push-master-fatal-you-are-not-currently-on-a-branch/30471627 Also helpful: https://www.clock.co.uk/insight/deleting-a-git-commit – Sagar Patel Jun 05 '20 at 01:21
  • This worked for me, but the caveat is that all the committed/non-committed changes will be lost **locally** as well. – zyy Feb 23 '23 at 06:55
  • You can also use the `--force-with-lease` flag instead of `--force`, so you can make sure you are not overwriting other people's work – K D Aug 30 '23 at 07:31
97

If it's only on your local PC (or noone checked out your changes):

  1. Use:
    git log
    

to find the commit you want to remove. Copy hash (the long sqeuence like: e8348ebe553102018c...).

  1. Use:
    git rebase -i [hash]~
    
    : for example
    git rebase -i e8348~
    

Just remove the commit you don't need and save the file.

Interactive git rebase can let you also fix the broken commit - there is no need to remove it.

If you pushed changes to the server or someone already got your changes - never change history - it'd cause serious problems for your team.

Alexar
  • 1,858
  • 5
  • 24
  • 34
Maciej Oziębły
  • 1,769
  • 15
  • 14
  • 7
    Can you elaborate on what serious problem it would cause? Is it guaranteed to happen? – Steven Zhou Mar 12 '20 at 19:07
  • 1
    Sorry but "never" is not true. Our large organization has to use filter-branch to trim a bloated repo. – Sridhar Sarnobat Jun 23 '20 at 05:38
  • Force pushing to a shared branch might remove someone else his work. Even if it didnt, if someone branched from it, he would then need to deal with the multiple versions of the history, be sure to pick the right one and be careful not to integrate both copies. I dont think its as big a sin as a lot of people seem to think, but when force pushing make sure its a short lived branch only you write to and make sure people are unlikely to have checked out the old history or know how to deal with this. – Fictional Dec 30 '20 at 13:11
  • 3
    I would like to make one correction to the answer. Instead of copying the hash which you want to remove, you should copy the one step parent hash of the hash which you want to remove, only then you can drop the hash which you want to remove. – Vijender Kumar Feb 22 '21 at 10:21
  • If using TortoiseGit, the answers here are helpful: https://stackoverflow.com/questions/12528854/how-to-perform-rebase-squash-using-tortoisegit – Venryx Aug 17 '21 at 13:55
  • Doesn't this answer only work if you have not pushed? If that is the case then I like to be more explicit. Clone the repo again and use a manual merge program of your choice (winmerge) to merge your local copy int the newly cloned copy. Commit all that in one commit, with no curse words, and push. – NDEthos Sep 03 '21 at 04:44
93

This works for me:

  1. git log to find the commit you want to remove and copy its hash
  2. git rebase -i <commit_hash>~ which opens your text editor
  3. in text editor, switch from pick to drop for your particular commit
Ray Foss
  • 3,649
  • 3
  • 30
  • 31
NutCracker
  • 11,485
  • 4
  • 44
  • 68
  • 16
    Using explicit drop is a little safer than just deleting the line... Making this better than the accepted answer. https://stackoverflow.com/questions/35846154/git-rebase-interactive-drop-vs-deleting-the-commit-line – Ray Foss Mar 31 '20 at 17:57
  • 4
    This seems right for only local commits without push.. – Timo Aug 12 '20 at 18:02
  • this works fine for a push, if nobody has pulled the offending commit locally – Alex Sep 17 '20 at 18:36
  • 3
    could you elaborate on trailing tilde's significance please? – random-forest-cat Nov 10 '21 at 23:01
  • @lfender6445 without the tilde it would only work for the latest commit – NutCracker Nov 11 '21 at 06:43
  • 2
    @Timo In terms of command execution, this solution is right even in case the local commits have been pushed, for which the push will have to be forced (push -f). However, chances are that the team's workflow discourages this actions because it can cause trouble to the team. – thanos.a Jun 03 '22 at 07:47
  • 2
    I had to go one commit hash before the commit I wanted to drop to be able to view the commit in the vim editor. – apinanyogaratnam Jul 04 '22 at 23:47
5

I was working with a team recently and found out that git has solution for this

all on this link

https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository

which is using git-filter-repo and BFG Repo-Cleaner

here is a cool video for exactly that

https://www.youtube.com/watch?v=z8tIOYg_oho

Ali Miskeen
  • 280
  • 4
  • 9
  • this is what was asked, thanks – PythoNic Aug 25 '22 at 10:13
  • Instead of providing links to documentation could you provide an example of how to do it? Links are not future-prof and with a clear explanation it would be easier to understand. – vicegax May 17 '23 at 09:09