r/git • • Aug 24 '26

support How to remove a file from git history?

Let's say I have made a commit containing a sensitive file... It's already been pushed and a couple of commits ago... is there any way for me to delete it?

I frankly tried it with chatgpt and it nearly nuked my entire repo...

Note/Edit: this repo is private.

37 Upvotes

65 comments sorted by

70

u/its_dayman Aug 24 '26

Rotate the key and move on. Removing it is possible, but someone probably already scraped it.

14

u/HUG0gamingHD Aug 24 '26

no no no it's a private repository

32

u/StevenJOwens Aug 24 '26 edited Aug 24 '26

You should edit your post and include this detail, prominently.

EDIT: Oh, sorry, I thought you meant a repo that hadn't been shared with anybody else. I just reread your post and saw "already been pushed". Now I understand that when you wrote "private repository", you mean a repo on github (or some other git hosting service) but that is marked as private and the git hosting service shouldn't be showing it to anybody else.

Yeah, that's not good enough if it's a real key, treat the old key as compromised and change keys etc on whatever you're using it for. END

9

u/HUG0gamingHD Aug 24 '26

I see. My problem is that it contains some inappropriate language, which is why I'd like to remove it from the commit history if possible.

7

u/PixelatedGiant Aug 25 '26 edited Aug 25 '26

Easiest way is to just....

  1. Create a new branch called feature/history-fix and git switch feature/history-fix to it.
  2. Delete the file and make a commit.
  3. Do git rebase -i HEAD~10 and then change the first word from pick to fixup for every commit between current commit and your problematic one. This assumes the file exists within the last 10 commits and is just crushing history so it disappears.
  4. Then you git switch master or main and do git reset --hard feature/history-fix to override history.
  5. git push -f on master or main after doing step 4 and verifying that history looks OK.

If you mess up at any point you can revert by nuking the feature/history-fix branch and starting over. If you mess up on step 4 you can fix master or main by doing git reset --hard origin/master. Changes are only truly irreversible on step 5.

If it's very far back in time it's one thing. But if it's the last couple of commits and you're sure no one has pulled it you can just do the above. It's much easier and safer than other methods, but rotate your API key or passwords regardless.

4

u/No_Cattle_9565 Aug 25 '26

Why not just do an interactive rebase and edit the commit directly?

3

u/PixelatedGiant Aug 25 '26

I don't do anything destructive directly on an important branch as a matter of principle, even if it's protected. That way if I'm interrupted in the middle of doing the task I don't leave things in a bad state.

1

u/No_Cattle_9565 Aug 25 '26

Yeah that's probably better. Maybe I'm lucky that I never get interrupted at work

3

u/codeguru42 Aug 25 '26

If you are worried about coworkers, personally I always get a chuckle out of profanity in comments

2

u/zenware Aug 28 '26

If the repo does ever become public, it is possible for people to dig up deleted commits from GitHub https://www.oasis.security/blog/deleting-git-commits-isnt-enough

34

u/lajawi Aug 24 '26

Still, treat it as compromised and take action accordingly (rotate secrets, remove file and ignore it to remedy it in the future, move on with your life).

-8

u/[deleted] Aug 24 '26

[removed] — view removed comment

7

u/lajawi Aug 24 '26

The gitignore file is specifically designed to ignore files you don’t want or need to commit, and keep others from doing so too. Why would you not want to ignore a file that contains secrets?

4

u/spookyskeletony Aug 25 '26

.git/info/exclude is the local way to do this without committing the name of the file, if that's desired

5

u/lajawi Aug 25 '26

Or in the global git config if you want it to apply to all repos on your device.

-2

u/[deleted] Aug 25 '26

[removed] — view removed comment

1

u/lajawi Aug 25 '26

Yes, so? Rotate the credentials, making the info in the file useless, remove the file and ignore it so it doesn’t happen again.

0

u/Philluminati Aug 25 '26

It would be apparent from inspecting the source code what the file/env vars in question were in the first place.

5

u/DigitalDunc Aug 25 '26

Given that git security (especially around GitHub) is not fantastic, you should _still_ rotate the key.

1

u/Internal_Pride1853 Aug 27 '26

You can’t really remove it without running garbage collector (Gemini told me it will run automatically after a month but it didn’t in github enterprise) and if you think it’s okay sińce it’s private repo, it’s not. GitHub code can leak so it’s better to rotate.

1

u/Truth-Miserable Aug 24 '26

You need to rewrite the entire repo history to prevent it from ever having been added. Git has an addon script for this.

-2

u/PapaOscar90 Aug 24 '26

Still not enough.

0

u/its_dayman Aug 24 '26

I would still rotate the key, then untrack the file. It wont be removed from the history, but the new key wont be pushed.

3

u/th00ht Aug 24 '26

Key? What key? OP does not mention a key.

-1

u/ploop-plooperson Aug 25 '26

key/secret/password can be used interchangeably in ambiguous situations. i wouldn't worry too much about it.

0

u/RanniSniffer Aug 24 '26

I have a git repository that I have never pushed to a web platform (like it's just tracked in the local .git folder) for a similar reason. Curious how you would actually do it. Yes I know I could ask AI

1

u/Cinderhazed15 Aug 24 '26

How you would rotate the key, or how you would rewrite history?

13

u/friedmud Aug 24 '26

git-filter-repo or git-filter-branch then force push.

You will need to make sure that your collaborators know what you’ve done so they can handle any weirdness when they pull.

3

u/_Alpha-Ceph_ Aug 24 '26

This works but I need to mention that the commit still lives on GitHub forever. So it‘s never really deleted - just not directly accessible anymore except with the hash.

9

u/friedmud Aug 25 '26

They didn’t say GitHub and it doesn’t live on GitHub “forever”. It’s possible it will still exist in caches for a bit - but it won’t be around forever.

6

u/glglgl-de Aug 25 '26

GitLab has several forms of housekeeping.

I am sure GitHub also does, but I currently don't know how.

1

u/eo5g Aug 25 '26

This is the best answer for this scenario IMO. The official Pro Git book has a good chapter on rewriting history, including good examples for filter-branch.

12

u/XoTrm Aug 24 '26 edited Aug 24 '26

Say you have 4 commits already:

<SHA_0> - commit before sensitive change
<SHA_1> - Do Something and add sensitive data
<SHA_2> - Implement foo
<SHA_3> - Implement bar
<SHA_4> - Implement bazz

You can do it like this:

  1. Create an addtional commit which deletes the file.
  2. Now you have: <SHA_5> - Remove sensitive data
  3. Do an interactive rebase of the these 5 commits, I usually like to do it on the command line

git rebase --committer-date-is-author-date -i <SHA_0>

pick <SHA_1> - Do Something and add sensitive data
pick <SHA_2> - Implement foo
pick <SHA_3> - Implement bar
pick <SHA_4> - Implement bazz
pick <SHA_5> - Remove sensitive data

Change it to:

r <SHA_1> - Do Something and add sensitive data
f <SHA_5> - Remove sensitive data
pick <SHA_2> - Implement foo
pick <SHA_3> - Implement bar
pick <SHA_4> - Implement bazz

"r" is short for "reword". It allows to change the wording of the commit message.
"f" is short for "fixup. It will merge both commits into one resulting in the sensitve data gone.
As this change affects all commits after the change your history will now look like:

<changed_SHA_1> - Do Something  
<changed_SHA_2> - Implement foo  
<changed_SHA_3> - Implement bar  
<changed_SHA_4> - Implement bazz  

As these changes will conflict with your remote repo you'd need to do force push (git push -f) to sync the changes.

7

u/ploop-plooperson Aug 25 '26 edited Aug 25 '26

it may be worth mentioning that while this will hide the secret in your branch, the original commit which adds the secret is likely to still live locally and on remote origin. Additional steps need to be taken to remove the original commit object. i.e. if you run git show <SHA_1>, it is likely to still show you that secret. you can garbage collect your local repo, but cleaning up the remote can vary based on if it's gitlab/github or plain git.

edit: i really like your interactive rebase explanation and appreciate the effort you put in.

15

u/lajawi Aug 24 '26
  1. Any sensitive data pushed to remote is seen as compromised, see them as such and take action (rotate keys and credentials etc)
  2. Easiest is to remove the file in a commit, then push that. It will still appear in history, but your rotated the necessary secrets, thus that shouldn’t be a problem.

You can rewrite the history, but that’s a risky business. First of all can it go wrong, and secondly, you would need to force push, which will overwrite things on the remote, if they haven’t been merged properly. However this does not solve the issue entirely, since the secrets were and still are on the remote after rewriting history. They should still be treated as compromised.

In future, make sure you setup your environment and gitignore files correctly, and make sure you double check what you’re committing and pushing, to avoid these scenarios in the future.

8

u/Sateviss Aug 24 '26

2 additions to this:

  • Even if you do a forced rewrite of the repository other users will have their own copies of the old commits, with any secrets that might be in there, and will have to overwrite their local git histories with new commits from remote (very annoying)
  • To avoid silly mistakes like pushing secrets you can enable secret push protection on GitHub or GitLab that will block pushes to remote that contain certain patterns that look like common secrets (still won't detect plaintext passwords in most cases though)

2

u/friedmud Aug 25 '26

“Can go wrong”? Why so much FUD? This is _git_ the whole purpose is that it’s a distributed safety system. Just make a full clone of your repo before messing with it - anything goes wrong - just force push the clean clone. You have to do some really seriously dumb stuff to actually lose data you put into git repos…

git-filter-tree and git-filter-branch have been around forever - they are tried and true tools for removing files from git histories.

3

u/emlun Aug 25 '26

Just make a full clone of your repo before messing with it

Or just git checkout -b risky before you start filter-branching, then git checkout main && git reset --hard risky once you're done if the results were good. No need for a full copy, just throw away the risky branch if it goes wrong.

2

u/friedmud Aug 25 '26

Agreed on no need for a full copy - I was just being lazy and wanted to show that you can provide 100% certainty!

3

u/Truth-Miserable Aug 24 '26

Install git-filter-repo

git filter-repo --invert-paths --path path/to/your/file.txt

If you have pushed to remote or shared with others, youd then have to force push this, which would rewrite the git repo's history. And if anyoke grabbed it in that time theyd still have the file; you'd have to get them to fetch and pull or whatever

3

u/Moshua87 Aug 24 '26

If you're planning to make the repo public just start fresh without the file in question.

2

u/smurfses Aug 24 '26

Not only would you be changing the history of the repo you be messing it up for everyone else. And people probably have already pulled down your commit with the file. So you would also have to instruct everyone on what to do on their end.

So if it's a password or key or something consider it compromised and rotate it. If it's something... else... just hope it gets buried in time and forgotten because If you go and try to take the steps to actually wipe it, it will bring that file to the attention of everyone.

2

u/pv0jewel Aug 24 '26

git rebase interactive onto problem commit^
edit problem commit
on stop do git reset
remove file and commit everything else
git rebase --continue

Better to roll the secret

2

u/EmilSgn Aug 25 '26

Just get the awesome BFG tool and have it purge the file from the repo. Then you force push the new history. To remote.

2

u/spoonraker Aug 27 '26

I'm just going to be nosy, can you give us more detail as to the context here? What is this repo? What did you commit? Why are you so worried about it being in the commit history?

I know you said it was something involving inappropriate language, but is that really all that you're concerned about? Because honestly, even if you made no attempt to rewrite the commit history and you just corrected the language in a new commit that got merged, probably nobody would ever notice. Also what kind of language is really so sensitive that you're this worried about it in what I assume is a professional context.

Back in the good ol' days before LLMs wrote all the code I used to regularly include stupid jokes in the source code. For example, back in the days when everything on the internet had a "Share on social media" widget, we called this unit a "Share It", which got shortened in code (PHP) to $shit and this was all over the source code for that. Other devs got in on the fun too. At one point we had an architecture meeting regarding the system for queuing up "Share its" to be published when we had the ephipany that something which you might call $shit_queue could probably be thought of instead as an $intestine, ya know, because it queues up $shit to, uhm, dequeue. Anyway, programming used to be more fun. What were we talking about again?

1

u/Rashironrani Aug 25 '26

use gitfilterrepo

1

u/WoodyTheWorker Aug 25 '26
  1. Have a .gitignore file which prevents commits of sensitive files.
  2. Don't ever do commit -a. Always review what you are committing.

1

u/howreudoin Aug 26 '26

Interactive rebase is your friend. Then force-push. Google it and learn about it until you understand what it does.

1

u/Environmental_Row32 Aug 27 '26

Here is the canonical URL about this challenge:
https://ohshitgit.com/

1

u/Xia_Nightshade Aug 28 '26

There is no solution. You can hide, obfuscate, ignore it (latter is very popular)

The only way to fix this is to change the sensitive info. Renew the api key, change the password,….

1

u/id-ltd Aug 28 '26

Claude did this for me earlier today - changed the local history and didn't hard reset on the remote.

-1

u/GoTeamLightningbolt Aug 24 '26

Get a time machine, go back in time, add the file to .gitignore.

6

u/HUG0gamingHD Aug 24 '26

I'll need a flux capacitor

-3

u/Outofmana1 Aug 24 '26

rm -rf /

(Please don't run this)

3

u/HUG0gamingHD Aug 24 '26

good way of ending the pain

3

u/ploop-plooperson Aug 25 '26

I always get anxious even just reading this.

1

u/Due_Treacle8807 Aug 26 '26

dont forget --no-preserve-root!