Удалите конфиденциальные файлы и их коммиты из истории Git.
-
22-08-2019 - |
Вопрос
Я хотел бы разместить проект Git на GitHub, но он содержит определенные файлы с конфиденциальными данными (имена пользователей и пароли, например /config/deploy.rb для capistrano).
Я знаю, что могу добавить эти имена файлов в .gitignore, но это не приведет к удалению их истории в Git.
Я также не хочу начинать заново, удаляя каталог /.git.
Есть ли способ удалить все следы определенного файла в вашей истории Git?
Решение
Для всех практических целей первый единственное, о чем тебе следует беспокоиться, это МЕНЯЕМ ПАРОЛИ! Из вашего вопроса неясно, является ли ваш репозиторий git полностью локальным или у вас уже есть удаленный репозиторий где-то еще;если он удален и не защищен от других, у вас есть проблема.Если кто-то клонировал этот репозиторий до того, как вы это исправите, у него будет копия ваших паролей на его локальном компьютере, и вы не сможете заставить его обновить вашу «исправленную» версию, удалив ее из истории.Единственное безопасное, что вы можете сделать, — это сменить пароль на другой везде, где вы его использовали.
Разобравшись с этим, вот как это исправить. GitHub ответил именно на этот вопрос в разделе часто задаваемых вопросов.:
Примечание для пользователей Windows:используйте в этой команде двойные кавычки ("") вместо одинарных
git filter-branch --index-filter \
'git update-index --remove filename' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force
Имейте в виду, что как только вы отправите этот код в удаленный репозиторий, например GitHub, а другие клонируют этот удаленный репозиторий, вы окажетесь в ситуации, когда вы переписываете историю.Когда после этого другие попытаются извлечь ваши последние изменения, они получат сообщение о том, что изменения не могут быть применены, поскольку это не быстрая перемотка вперед.
Чтобы это исправить, им придется либо удалить существующий репозиторий и повторно клонировать его, либо следовать инструкциям в разделе «ВОССТАНОВЛЕНИЕ ИЗ UpSTREAM REBASE» в Справочная страница git-rebase.
В будущем, если вы случайно внесете некоторые изменения с конфиденциальной информацией, но заметите до при отправке в удаленный репозиторий есть несколько более простых исправлений.Если последний коммит добавляет конфиденциальную информацию, вы можете просто удалить конфиденциальную информацию, а затем запустить:
git commit -a --amend
Это дополнит предыдущий коммит любыми новыми изменениями, которые вы внесли, включая полное удаление файлов, выполненное с помощью git rm
.Если изменения остались в истории, но еще не перенесены в удаленный репозиторий, вы можете выполнить интерактивное перебазирование:
git rebase -i origin/master
Откроется редактор с коммитами, которые вы сделали с момента вашего последнего общего предка с удаленным репозиторием.Измените «выбрать» на «редактировать» во всех строках, представляющих фиксацию с конфиденциальной информацией, сохраните и закройте.Git просмотрит изменения и оставит вас на месте, где вы сможете:
$EDITOR file-to-fix
git commit -a --amend
git rebase --continue
Для каждого изменения с конфиденциальной информацией.В конце концов вы вернетесь в свою ветку и сможете безопасно вносить новые изменения.
Другие советы
Изменение паролей — хорошая идея, но для процесса удаления паролей из истории вашего репо я рекомендую BFG Репо-очиститель, более быстрая и простая альтернатива git-filter-branch
явно предназначен для удаления личных данных из репозиториев Git.
Создать private.txt
файл со списком паролей и т. д., которые вы хотите удалить (по одной записи в строке), а затем выполните следующую команду:
$ java -jar bfg.jar --replace-text private.txt my-repo.git
Все файлы меньше порогового размера (по умолчанию 1 МБ) в истории вашего репозитория будут сканироваться, и любая соответствующая строка (которой нет в вашем последний commit) будет заменен строкой «***REMOVED***».Затем вы можете использовать git gc
чтобы очистить мертвые данные:
$ git gc --prune=now --aggressive
BFG обычно в 10-50 раз быстрее, чем бегущий git-filter-branch
а варианты упрощены и адаптированы для этих двух распространенных случаев использования:
- Удаление Сумасшедшие большие файлы
- Удаление Пароли, учетные данные & другой Частные данные
Полное раскрытие:Я автор BFG Repo-Cleaner.
Я рекомендую этот сценарий Дэвида Андерхилла произвел на меня впечатление.
Он добавляет эти команды в дополнение к ветке фильтра natacado, чтобы навести порядок, который он оставляет после себя:
rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
Полный сценарий (все заслуга Дэвида Андерхилла)
#!/bin/bash
set -o errexit
# Author: David Underhill
# Script to permanently delete files/folders from your git repository. To use
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2
if [ $# -eq 0 ]; then
exit 0
fi
# make sure we're at the root of git repo
if [ ! -d .git ]; then
echo "Error: must run this script from the root of a git repository"
exit 1
fi
# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter \
"git rm -rf --cached --ignore-unmatch $files" HEAD
# remove the temporary history git-filter-branch
# otherwise leaves behind for a long time
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune
Последние две команды могут работать лучше, если их изменить на следующие:
git reflog expire --expire=now --all && \
git gc --aggressive --prune=now
Если вы отправили сообщение на GitHub, принудительной отправки недостаточно, удалите репозиторий или обратитесь в службу поддержки.
Даже если вы принудительно нажмете одну секунду после этого, этого будет недостаточно, как описано ниже.
Единственные действительные варианты действий:
что привело к утечке сменных учетных данных, таких как пароль?
- да:немедленно измените свои пароли и рассмотрите возможность использования большего количества ключей OAuth и API!
нет (голые фото):
Вас волнует, будут ли уничтожены все проблемы в репозитории?
- нет:удалить репозиторий
да:
- Контактная поддержка
- если утечка очень критична для вас, настолько, что вы готовы немного отложить репозиторий, чтобы снизить вероятность утечки, сделать это приватным пока вы ждете, пока служба поддержки GitHub ответит вам
Принудительного нажатия секундой позже недостаточно, потому что:
GitHub долгое время сохраняет висящие коммиты.
Однако сотрудники GitHub имеют право удалить такие висячие коммиты, если вы свяжетесь с ними.
Я испытал это на собственном опыте, когда загрузил все электронные письма о коммитах GitHub в репозиторий они попросили меня снять его, что я и сделал, и они сделали
gc
.Запросы на включение, содержащие данные однако придется удалить:Из-за этого данные репо оставались доступными в течение одного года после первоначального удаления.Висячие коммиты можно увидеть одним из следующих способов:
- веб-интерфейс фиксации: https://github.com/cirosantilli/test-dangling/commit/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (Машина обратного пути)
- API: https://api.github.com/repos/cirosantilli/test-dangling/commits/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (Машина обратного пути)
Один из удобных способов получить исходный код в этом коммите — использовать метод загрузки zip, который может принимать любую ссылку, например: https://github.com/cirosantilli/myrepo/archive/SHA.zip
Получить недостающие SHA можно одним из следующих способов:
- список событий API с
type": "PushEvent"
.Например.мой: https://api.github.com/users/cirosantilli/events/public (Машина обратного пути) - иногда удобнее, просматривая SHA запросов на включение, которые пытались удалить контент.
- список событий API с
Есть такие скраперы http://ghtorrent.org/ и https://www.githubarchive.org/ которые регулярно объединяют данные GitHub и хранят их в другом месте.
Я не смог выяснить, очищают ли они фактические различия коммитов, и это маловероятно, потому что будет слишком много данных, но это технически возможно, и у АНБ и его друзей, вероятно, есть фильтры для архивирования только того, что связано с людьми или коммитами, представляющими интерес.
Однако, если вы удалите репозиторий вместо того, чтобы просто принудительно отправить его, коммиты немедленно исчезнут даже из API и выдадут 404, например. https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 Это работает, даже если вы воссоздаете другой репозиторий с тем же именем.
Чтобы проверить это, я создал репо: https://github.com/cirosantilli/test-dangling и сделал:
git init
git remote add origin git@github.com:cirosantilli/test-dangling.git
touch a
git add .
git commit -m 0
git push
touch b
git add .
git commit -m 1
git push
touch c
git rm b
git add .
git commit --amend --no-edit
git push -f
Смотрите также: Как удалить висячий коммит с GitHub?
Чтобы внести ясность:Принятый ответ правильный.Попробуйте сначала.Однако в некоторых случаях использования это может оказаться излишне сложным, особенно если вы столкнулись с неприятными ошибками, такими как «фатальная:плохая ревизия --prune-empty», или вас действительно не волнует история вашего репозитория.
Альтернативой может быть:
- перейдите в базовую ветку проекта
- Удалите конфиденциальный код/файл
- rm -rf .git/ # Удалить всю информацию GIT из вашего кода
- Перейдите на github и удалите свой репозиторий.
- Следуйте этому руководству, чтобы перенести свой код в новый репозиторий, как обычно:https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
Это, конечно, удалит все ветки истории коммитов и проблемы как из вашего репозитория github, так и из вашего локального репозитория git.Если это неприемлемо, вам придется использовать альтернативный подход.
Назовите это ядерным вариантом.
Вот мое решение в Windows
git filter-branch --tree-filter "rm -f 'filedir/filename'" HEAD
git push --force
Убедитесь, что путь правильный, иначе он не сработает
Я надеюсь, что это помогает
Использовать фильтр-ветвь:
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *file_path_relative_to_git_repo*' --prune-empty --tag-name-filter cat -- --all
git push origin *branch_name* -f
Вы можете использовать git forget-blob
.
Использование довольно простое git forget-blob file-to-forget
.Вы можете получить дополнительную информацию здесь
Он исчезнет из всех коммитов в вашей истории, релогов, тегов и т. д.
Время от времени я сталкиваюсь с одной и той же проблемой, и каждый раз мне приходится возвращаться к этому посту и другим, поэтому я автоматизировал процесс.
Благодарность участникам Stack Overflow, которые позволили мне собрать это воедино.
На сегодняшний день мне пришлось сделать это несколько раз.Обратите внимание, что это работает только с одним файлом одновременно.
Получите список всех коммитов, которые изменили файл.Тот, что внизу, будет первым коммитом:
git log --pretty=oneline --branches -- pathToFile
Чтобы удалить файл из истории, используйте первый коммит sha1 и путь к файлу из предыдущей команды и заполните их в этой команде:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..
Итак, это выглядит примерно так:
git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore
Удалите кеш отслеживаемого файла из git и добавьте этот файл в
.gitignore
список
В моем проекте Android у меня было admob_keys.xml как отдельный XML-файл в приложение/src/main/res/values/ папка.Чтобы удалить этот конфиденциальный файл, я использовал приведенный ниже сценарий, и он сработал отлично.
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch app/src/main/res/values/admob_keys.xml' \
--prune-empty --tag-name-filter cat -- --all