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

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

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

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

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

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-50x быстрее, чем работает git-filter-branch и варианты упрощены и портняжничаны вокруг этих 2 общих использовани-случаев:

  • удаление Сумасшедшие Большие Файлы
  • удаление пароли, Верительные грамоты и другие личные данные

полное раскрытие информации: я автор РЕПО-очистителя BFG.


рекомендую этот скрипт Дэвид Андерхилл, работал как шарм для меня.

Он добавляет эти команды в дополнение к фильтр-ветви 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 .Git / # удалить всю информацию git из ваш код
  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

убедитесь, что путь правильный иначе не получится!--1-->

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


использовать фильтр-филиала:

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