Глиф Учебники

Как убрать пароль из истории Git

Справочник · Git · 2 минуты чтения

Первым делом смените пароль, токен или ключ — в том сервисе, от которого он. Даже если коммит провисел на сервере минуту, его могли скопировать: открытые репозитории постоянно просматривают программы, которые ищут секреты. Чистка истории убирает следы, но не отменяет утечку. Старый секрет считайте раскрытым.

Как убрать секрет из истории

Способ зависит от того, где коммит с секретом: последний и ещё не отправлен, один из нескольких неотправленных или уже на сервере.

Последний коммит, ещё не отправленпересоберите его

Уберите секрет из файла (или файл из индекса) и пересоберите последний коммит:

Bash
git rm --cached .env
echo ".env" >> .gitignore
git add .gitignore
git commit --amend --no-edit

Если секрет был строкой в обычном файле — исправьте файл, git add файл и git commit --amend --no-edit. Коммит с секретом заменится новым, и на сервер он не попадёт.

Дальше: «Что остаётся на сервере»

Один из нескольких неотправленныхперепишите их через rebase

Перепишите неотправленные коммиты интерактивным rebase:

  1. Выполните git rebase -i HEAD~3 (3 — сколько последних коммитов просмотреть).
  2. В открывшемся списке замените pick на edit у коммита с секретом, сохраните и закройте.
  3. Git остановится на этом коммите: уберите секрет, как в ветке выше, и сделайте git commit --amend --no-edit.
  4. Продолжите: git rebase --continue.

Дальше: «Что остаётся на сервере»

Уже на сервере или глубоко в историиперепишите всю историю

Git-проект рекомендует для этого отдельную программу git filter-repo вместо старой встроенной git filter-branch. В Ubuntu и Debian она ставится пакетом (sudo apt install git-filter-repo), для других систем — способы на странице проекта.

Работайте в свежем клоне — filter-repo по умолчанию отказывается переписывать репозиторий, который не похож на свежий клон:

Bash
git clone https://github.com/ivan/todo.git todo-clean
cd todo-clean

Дальше — одно из двух: заменить сам пароль или удалить файл целиком.

Заменить пароль во всех версиях файлов

Создайте файл ../passwords.txt (вне репозитория) и запишите в него пароль отдельной строкой. Затем:

Bash
git filter-repo --replace-text ../passwords.txt

Каждое вхождение заменится на ***REMOVED***. Своя замена записывается так: пароль==>ЗАМЕНА. Когда всё готово, удалите сам файл passwords.txt — в нём тот же пароль.

Удалить файл целиком из всей истории

Bash
git filter-repo --invert-paths --path config/secret.ini

Отправьте новую историю

После переписывания filter-repo нарочно отключает связь с сервером (origin), чтобы старая и новая история случайно не смешались. Верните её и отправьте новую историю принудительно:

Bash
git remote add origin https://github.com/ivan/todo.git
git push --force --all
git push --force --tags

Переписанная история заменяет старую на сервере: у всех коммитов после изменённого — новые хеши. Всем участникам нужно склонировать репозиторий заново. Если кто-то отправит свою старую копию, секрет вернётся на сервер. Защищённые ветки хостинг может не дать перезаписать — это снимается в настройках репозитория.

Что остаётся на сервере

Поэтому главное — смена секрета, а чистка истории — уборка за ним.

Как не допустить снова