CLI AI

Удалить пароль из истории git

2026-06-01

Чтобы удалить пароль из истории git, нужно переписать коммиты, которые его содержат, командой git filter-repo --invert-paths --path <file>, а затем вычистить reflog и запустить сборку мусора, чтобы старые коммиты пропали и из .git. Делайте это только после ротации ключа — утёкший секрет считается скомпрометированным в момент коммита, независимо от того, почистите вы историю или нет. .gitignore и git rm --cached никак не влияют на уже существующие коммиты.

1. Убедиться, что секрет всё ещё в истории

clai
$ clai проверь, остался ли этот ключ где-нибудь в истории репозитория→ git log --all --oneline -S 'sk-live-abc123secret'0fb8c94 stop tracking .env4c1d9ff add app and env

-S ищет коммиты, где число вхождений строки изменилось — то есть где секрет появился и где исчез. Поиск идёт по всей истории всех веток, а не по рабочему дереву.

2. Убедиться, что удаление из индекса не помогло

clai
$ clai достань файл .env из того коммита, где он был добавлен→ git show 4c1d9ff:.envAPI_KEY=sk-live-abc123secret

Вот и вся проблема в одной команде. .env удалён из рабочего дерева, добавлен в .gitignore, git rm --cached уже выполнен — а секрет достаётся одной командой любому, у кого есть клон. Коммит по-прежнему хранит всё содержимое.

3. Посмотреть, в каких коммитах фигурирует путь

clai
$ clai покажи все коммиты, где упоминается файл .env→ git log --all --oneline -- .env0fb8c94 stop tracking .env4c1d9ff add app and env

Это список того, что придётся переписать. Два коммита — и вы легко отделаетесь. Двести, разбросанные по веткам, — и сначала придётся согласовать план со всей командой.

4. Сначала ротация, потом чистка

Секрет, попавший в git, нужно считать утёкшим — без исключений. Репозиторий мог быть склонирован, форкнут, проиндексирован ботом или закеширован CI ещё до того, как вы заметили ошибку. Отзовите ключ и выпустите новый до того, как займётесь историей: чистая история с действующим украденным ключом хуже грязной истории с уже отозванным.

5. Переписать историю правильным инструментом

clai
$ clai удали файл .env из всей истории репозитория→ git filter-repo --invert-paths --path .env⚠ DANGER — rewrites all history, every commit hash changes

git filter-repo — то, что рекомендует сам проект git. git filter-branch объявлен устаревшим: он на порядки медленнее и при неаккуратном использовании способен тихо испортить репозиторий. Альтернатива — BFG Repo-Cleaner: быстрее на больших репозиториях и умеет заменять строку на ***REMOVED***, не удаляя файл целиком.

6. Подчистить то, что осталось локально

clai
$ clai удали старые ссылки и запусти сборку мусора агрессивно→ git reflog expire --expire=now --all && git gc --prune=now --aggressive

После переписывания старые коммиты остаются достижимыми через reflog — то есть секрет всё ещё лежит в .git. Эта команда убирает их окончательно. На стороне GitHub или GitLab придётся отдельно попросить поддержку почистить кеш, а форки за вас никто не почистит.

Грабли

  • Переписанная история ломает клоны у всей команды. После force-push каждому придётся переклонировать или сделать git rebase --onto. Предупредите заранее, иначе кто-нибудь запушит старую историю обратно.
  • Форки и пул-реквесты остаются. На GitHub коммит из закрытого PR может быть доступен по прямой ссылке даже после чистки основного репозитория. Ещё один аргумент в пользу ротации ключа.
  • git filter-branch устарел. Сам git при запуске печатает предупреждение и советует filter-repo. Половина статей в выдаче об этом ещё не знает.

Похожие вопросы

Достаточно ли добавить файл в .gitignore? Нет. .gitignore влияет только на новые файлы. Уже закоммиченное остаётся в истории целиком.

Как не допустить этого впредь? Хук pre-commit со сканером секретов: gitleaks, detect-secrets или trufflehog. Они ловят ключ до коммита, а не после публикации.

Что делать, если секрет уже на GitHub? Отозвать ключ немедленно, потом почистить историю, потом попросить поддержку GitHub убрать кешированные представления. Порядок именно такой.

Читайте также

CliAI помечает git filter-repo как DANGER и требует подтверждения вводом, прежде чем тронуть хоть один коммит. Установка одной строкой.