I Already Committed Something I Should Not Have
The awkward sequel. The file is already in the repository, you have now added it to .gitignore, and nothing has changed — because Git keeps tracking what it already tracks.
What to do next depends entirely on what the file is. If it contains a password, the first step is not a Git command at all.
If it was a secret: rotate first
A password, API key or token that reached a repository must be treated as exposed. Change it. Revoke the key, issue a new token, reset the password — whatever that particular credential requires.
Do that before touching Git, and do it even if the repository is private and only you have ever seen it. Removing a file from a repository does not un-share a secret; it only stops it being shared again. If the repository was pushed to GitHub, assume the credential is compromised and act accordingly.
This is the single most useful habit in this chapter, and it is a habit about credentials rather than about Git.
Stop tracking it, keep it on disk
Now the Git part. One command tells Git to forget a file without deleting it:
git rm --cached .env git status
The --cached is the important half: it removes the file from Git's records and leaves it in your folder. Without it, plain git rm deletes the file from both, which is a different command for a different intention.
Status now shows the file as deleted (from Git's point of view) and, if your ignore rule is in place, no longer offers it as untracked. Commit the removal along with the rule:
git add .gitignore git commit -m "Stop tracking the local environment file"
Do both in one commit. Removing the file without adding the ignore rule means your next git add . puts it straight back.
What this does and does not do
From this commit onward, the file is not part of the project. Every earlier commit still contains it, exactly as it was, because nothing has rewritten the past.
git log --oneline -- .env
That command lists every commit that touched the file, and they are all still there. Anyone with a copy of the repository can read its contents at any of those commits. On a public repository, assume somebody has.
On Sandpiper this is not hypothetical. notes/private/members.csv — the club's phone list, with twenty members' numbers in it — went in with the very first git add . in week one. Nothing about that file was ever meant to leave your laptop. You tell the members it was briefly on your machine's copy, stop tracking it, ignore the whole folder, and commit both together.
Removing it from history is a bigger job
It is possible to rewrite every past commit so that a file was never there. It requires a specialized tool, it changes the hash of every commit from that point on, and it demands coordination with everyone who has a copy — because their history and yours will no longer agree.
That is a real technique with a real place, and it is a chapter of the deep dive. For a beginner the honest sequence is the one above: rotate, stop tracking, ignore, commit — and if the repository is public and shared, ask someone experienced before attempting a rewrite.
The huge file case
Same procedure, different cost. A three-hundred-megabyte video committed by accident makes every future copy of the repository carry it forever, because clones bring the whole history.
git rm --cached takes it out from here onward, and the history keeps it. If the repository has never been shared, the fastest honest fix is often to start it again with a good .gitignore — which sounds drastic and is frequently the right call in week one.
The prevention is the same either way: read what git status lists before running git add ..
- "
git rmdeletes my file."git rm --cachedremoves it from Git and leaves it on disk. Plaingit rmdeletes it from both — same command, one flag, very different outcome. - "Adding it to
.gitignoreremoves it now." Ignore rules apply to files Git is not already tracking. This is the most surprising behaviour in the chapter and the reason this page exists. - "It is gone once I commit the removal." It is gone from the current state. Every earlier commit still contains it, and anyone with the repository can read it there.
- "The repository is private, so a committed password is fine." Private today is not private forever, and the credential is now in a place it was never meant to be. Rotate it.
- Rotating first is the difference between an inconvenience and a genuine security incident, and it is the one habit from this page worth carrying into every job you ever have.
- Understanding that a removal does not rewrite history is what makes "never commit the secret in the first place" land as a rule rather than as scolding.
- The same procedure covers the enormous-file case, which is the other way a repository becomes permanently unpleasant to work with.
Knowledge Check
You committed a file containing an API key. What is the first step?
- Rotate the credential, because removing the file does not un-share it
- Run
git rm --cachedimmediately, before anyone can clone the repository - Delete the repository from GitHub and create a fresh one with the same name
- Add the file to
.gitignore, which stops it appearing in any future commit
What does the --cached flag change about git rm?
- It removes the file from Git's records and leaves it sitting on your disk
- It removes the file from the current commit but keeps it in earlier ones
- It removes the file only from the staging area, leaving the repository intact
- It removes the file everywhere but keeps a cached copy for later recovery
After you commit the removal, who can still read the file's old contents?
- Anyone with a copy of the repository, simply by looking at the earlier commits
- Nobody, because committing the removal erases the file from the whole history
- Only you, because the old contents stay in your local copy and are never shared
- Only the person who originally committed the file, since it is tied to its author
Why must the removal and the ignore rule go into the same commit?
- Because without the rule, your next
git add .puts the file straight back - Because Git rejects a removal commit that does not include an ignore rule
- Because separate commits would rewrite the history and change every hash
- Because the ignore rule only takes effect on files removed in the same commit
You got correct