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


Я хотел бы поместить проект Git на GitHub, но он содержит определенные файлы с конфиденциальными данными (имена пользователей и пароли, например /config/deploy.РБ для Капистрано).

Я знаю, что могу добавить эти имена файлов в .gitignore, но это не удалит их историю в Git.

Я также не хочу начинать все сначала, удалив /.каталог git.

есть ли способ удалить все следы конкретного файла в вашем Git история?

10 288

10 ответов:

для всех практических целей первый то, что вы должны беспокоиться о ИЗМЕНЕНИЕ ПАРОЛЕЙ! из вашего вопроса неясно, является ли ваш репозиторий git полностью локальным или у вас есть удаленный репозиторий в другом месте; если он удален и не защищен от других, у вас есть проблема. Если кто-то клонировал этот репозиторий до того, как вы это исправите, у них будет копия ваших паролей на их локальной машине, и вы не сможете заставить их чтобы обновить до вашей "исправленной" версии, когда она ушла из истории. Единственная безопасная вещь, которую вы можете сделать, это изменить свой пароль на что-то другое везде, где вы его использовали.


С этим из пути, вот как это исправить. GitHub ответил именно на этот вопрос в качестве FAQ:

Примечание для пользователей 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 и другие, клонировал этот удаленный репозиторий, теперь вы находитесь в ситуации, когда вы переписываете историю. Когда другие пытаются снять ваши последние изменения после этого, они получат сообщение о том, что изменения не могут быть применены, потому что это не быстрая перемотка вперед.

чтобы исправить это, им придется либо удалить свой существующий репозиторий и повторно клонировать его, либо следовать инструкциям в разделе "Восстановление из восходящей РЕБАЗЫ" в git-rebase man-страницы.


в будущем, если вы случайно совершить некоторые изменения с конфиденциальной информацией, но вы заметите до нажав на удаленный репозиторий, есть несколько более простых исправлений. Если вы в последний раз фиксируете добавление конфиденциальной информации, вы можете просто удалить конфиденциальную информацию, а затем запустить:

git commit -a --amend

это изменит предыдущую фиксацию с любыми новыми изменениями, которые вы сделали, включая полное удаление файлов, выполненное с помощью git rm. Если изменения находятся дальше в истории, но все еще не перенесены в удаленный репозиторий, вы можете выполнить интерактивную перебазировку:

git rebase -i origin/master

это открывает редактор с фиксациями, которые вы сделали с момента вашего последнего общего предка с удаленным репозиторием. Измените "pick "на" edit " в любых строках, представляющих фиксацию с конфиденциальной информацией, а также сохраните и завершите работу. Git пройдет через изменения и оставит вас в том месте, где вы можете:

$EDITOR file-to-fix
git commit -a --amend
git rebase --continue

для каждого изменения с конфиденциальная информация. В конце концов, вы вернетесь на свою ветку, и вы можете безопасно продвигать новые изменения.

изменение паролей-хорошая идея, но для процесса удаления пароля из истории вашего РЕПО я рекомендую BFG Repo-Cleaner, более быстрая и простая альтернатива 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, данные будут скомпрометированы, даже если вы заставите оттолкнуть его через секунду потому что:

чтобы проверить это, я создал РЕПО: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

Если вы удалить репозиторий однако коммиты исчезают даже из API сразу и дают 404, например https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 это работает, даже если вы воссоздаете другой репозиторий с тем же именем.

поэтому мой рекомендуемый курс действий:

  • изменить учетные данные

  • если этого недостаточно (например, голые фото):

    • удалить репозиторий
    • обратитесь в службу поддержки

чтобы быть ясным: принятый ответ правильный. Попробуй сначала. Однако это может быть излишне сложным для некоторых случаев использования, особенно если вы сталкиваетесь с неприятными ошибками, такими как "fatal: bad revision --prune-empty", или действительно не заботитесь об истории вашего РЕПО.

альтернативой было:

  1. cd в базовую ветвь проекта
  2. удалить чувствительный код / файл
  3. rm-rf .ГИТ/ # удалить все мерзавец информация от ваш код
  4. перейдите в github и удалите свой репозиторий
  5. следуйте этому руководству, чтобы переместить свой код в новый репозиторий, как обычно - 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

убедитесь, что путь правильный иначе это не сработает

надеюсь, это поможет

использовать filter-branch:

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. Вы можете получить дополнительную информацию здесь

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

он исчезнет из всех коммитов в вашей истории, reflog, теги и так далее

я сталкиваюсь с одной и той же проблемой время от времени, и каждый раз, когда мне приходится возвращаться к этому сообщению и другим, именно поэтому я автоматизировал процесс.

кредиты для участников из Stack Overflow, которые позволили мне собрать это вместе

мне пришлось сделать это несколько раз на сегодняшний день. Обратите внимание, что это работает только на 1 файл за раз.

  1. получить список всех коммитов, которые изменили файл. Тот, кто внизу будет первым совершать:

    git log --pretty=oneline --branches -- pathToFile

  2. чтобы удалить файл из истории используйте первый commit 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 list