You Just Pushed Sensitive Data to GitHub. Now What?
It happens to the best of us. You’re in the zone, committing code, and you push a batch of changes. A moment later, a sinking feeling hits. You realize your latest commit includes a file that shouldn’t be public. Maybe it’s a configuration file with API keys, a large log file, or a draft document full of private notes. The file is now sitting in your GitHub repository for anyone to see.
This scenario is one of the most common reasons developers need to delete files from GitHub. But it’s not the only one. Perhaps you’re cleaning up an old project, removing deprecated code, or simply trying to keep your repository lean and organized. Whatever your reason, knowing how to properly delete files is a fundamental Git and GitHub skill.
Deleting a file from GitHub isn’t as simple as hitting a delete key on your local machine. Because Git tracks history, you need to understand the implications of your actions. Do you want to remove the file from the current version but keep its history? Or do you need to obliterate it from the repository’s entire history, which is a more complex operation? This guide will walk you through every method, from the simple web interface to advanced command-line techniques for scrubbing sensitive data.
Understanding the Git Mindset: Deletion Isn’t Erasure
Before you delete anything, it’s crucial to understand how Git works. Unlike a typical file system, Git is a version control system designed to keep history. When you “delete” a file in a commit, you aren’t erasing it from existence. You are creating a new commit that records the absence of that file. The previous commits that contained the file remain intact in your repository’s history.
This is usually fine for cleaning up code. However, if you’ve accidentally committed a password or private key, this standard deletion is insufficient. Anyone cloning your repository could still check out an old commit and retrieve the secret. For true removal, you need to rewrite history using tools like git filter-repo or the BFG Repo-Cleaner, which we’ll cover later.
Let’s start with the simplest and most common methods.
Method 1: Deleting a Single File via GitHub.com
The GitHub web interface is perfect for quick, one-off file deletions, especially if you’re not deep in a local development workflow. It’s straightforward and requires no command-line knowledge.
Navigate to your repository on GitHub.com and browse to the file you want to delete. In the top-right corner of the file content view, you’ll see a small trash can icon. Clicking it will prompt you to confirm the deletion.
Here’s the critical part: GitHub will ask you to commit this change. You must provide a commit message explaining why you’re deleting the file. A good commit message like “Remove config.yml containing legacy keys” is better than just “Delete file.” You can also commit directly to your main branch or create a new branch and start a pull request, which is the safer practice for team projects.
This method creates a standard commit that removes the file from the current branch (the “tip” of history). The file will still exist in any commit made before this deletion.
Method 2: Deleting Multiple Files or Directories on GitHub.com
What if you need to delete an entire folder or several scattered files? You can use the repository’s file browser in a slightly different way. While browsing your repo, check the boxes next to the files or directories you wish to remove. A “Delete” button will appear at the top of the file list.
After selecting your files, click “Delete.” Just like with a single file, you’ll be taken to a commit screen. This allows you to batch the deletion of multiple items into a single, coherent commit with a descriptive message. This is an efficient way to clean up without making a mess of your commit history.
Taking Control: Deleting Files Using Git Commands
For developers working locally, the command line offers more power and precision. This is the standard workflow for making changes as part of your normal development process.
First, ensure your local repository is up to date. Run git pull origin main (or your branch name) to fetch the latest changes from GitHub.
To delete a file, you use the git rm command. The basic syntax is git rm filename.txt. This command stages the file for deletion. It also removes the file from your working directory. If you want to remove the file from Git’s tracking but keep a copy on your local disk (perhaps you’ll add it to .gitignore later), use git rm –cached filename.txt.
Once the deletion is staged, you commit the change: git commit -m “Remove outdated documentation draft.” Finally, you push the commit to GitHub: git push origin main.
This command-line flow gives you full control and integrates seamlessly with other Git operations like branching and merging.
Handling Directories and Complex Deletions
Deleting a directory requires the -r (recursive) flag. The command git rm -r directory-name/ will stage the deletion of the entire folder and all its contents. Always double-check the path before running this, as it’s easy to remove more than intended.
For more complex clean-ups, you can combine git rm with other commands. For example, you can delete all files with a certain extension: git rm *.log. Or, you can use find to locate and delete specific files, piping the result to git rm. This approach is powerful but should be used with caution. It’s often safer to delete files individually or in small batches when using wildcards.
The Nuclear Option: Removing a File from Git History Entirely
As discussed, standard deletion commits don’t remove data from old commits. If you’ve committed a secret, you must rewrite history to purge the file. Warning: This is a destructive operation that changes commit SHAs. Anyone else collaborating on the repository will have major issues pulling your changes. It should only be done on private repos or with full team coordination.
The modern, recommended tool for this is git filter-repo. It’s faster and safer than the older git filter-branch. First, you need to install it, as it’s not bundled with standard Git.
Once installed, you can run a command to strip a file from all history. A basic command looks like this: git filter-repo –path sensitive-file.txt –invert-paths. This tells Git to rewrite the repository’s history, excluding any commits that touched sensitive-file.txt.
After running filter-repo, your local history is changed. To update GitHub, you must force push: git push origin main –force. This overwrites the remote history. Immediately after, instruct all other collaborators to reclone the repository, as their local history will be incompatible.
For very large repositories or to remove many files, consider the BFG Repo-Cleaner, a simpler, faster alternative written in Java that handles the most common use cases.
What About GitHub’s Secret Scanning?
If you push a commit that contains a known secret pattern (like an AWS key or Slack token), GitHub may automatically flag it and alert you via email or the repository’s security tab. They might even proactively revoke the key if it’s from a partnered service. This is a great safety net, but it’s not a reason to be careless. Always treat secret removal as an emergency procedure.
The best practice is to prevent secrets from being committed in the first place. Use a .gitignore file to exclude configuration files, and use environment variables or secret management tools for all keys and passwords.
Common Pitfalls and How to Avoid Them
Even with the right method, things can go wrong. Here are frequent issues and their solutions.
You deleted a file locally but didn’t use git rm. Git now sees the file as “missing” and will list it under “Changes not staged for commit.” To stage the deletion properly, you can simply run git rm on the already-missing file, or use git add -A which will stage all changes, including deletions.
You accidentally deleted the wrong file. Don’t panic. If you haven’t committed yet, you can undo the staging with git restore –staged filename.txt. If the file was also removed from your disk, you can restore it from Git: git checkout — filename.txt. This command fetches the last committed version of the file back to your working directory.
You committed a deletion but haven’t pushed it. You can undo the commit while keeping the changes staged using git reset –soft HEAD~1. To completely discard the commit and the deletion, use git reset –hard HEAD~1. Be very careful with –hard, as it will irreversibly erase your uncommitted work too.
You’ve already pushed the deletion to GitHub. Now you need to revert it. Create a new commit that restores the file. You can do this with git revert HEAD, which will create a new commit that undoes the changes of the previous one. If the deletion was several commits ago, find its hash using git log and run git revert COMMIT_HASH.
Best Practices for Repository Hygiene
Deleting files reactively is less ideal than maintaining a clean repository proactively.
Use a comprehensive .gitignore file tailored to your project’s language and tools from the very beginning. GitHub offers official .gitignore templates for most frameworks.
Review your changes with git status and git diff before every commit. This simple habit catches accidental additions.
For team projects, protect your main branch. Require pull requests and reviews before merging. This gives another set of eyes a chance to spot files that shouldn’t be included.
Consider using pre-commit hooks or GitHub Actions that scan for secrets or large files before a push is allowed. Tools like Talisman or git-secrets can be integrated into your workflow.
Your Action Plan for a Cleaner GitHub Repository
Start by auditing your current repositories. Look for large files using GitHub’s interface or a command like git ls-files | xargs wc -l. Identify old log files, build artifacts, or forgotten asset folders that are bloating your repo.
For non-sensitive cleanup, use the GitHub web interface for simplicity or batch deletions with clear commit messages. Integrate file removal into your standard local git workflow for changes made during development.
Treat any committed secret as a critical security incident. Use git filter-repo to purge it from history, force push, and communicate immediately with collaborators. Then, rotate the exposed secret immediately—deleting it from Git is only half the fix.
Finally, implement preventative measures. Solidify your .gitignore, educate your team on what not to commit, and consider automated guards. A clean repository is easier to work with, faster to clone, and more secure. Mastering file deletion is not just about fixing mistakes; it’s a key part of professional repository management.