Удалить конфиденциальные файлы и их коммиты из истории Git - PullRequest
311 голосов
/ 16 мая 2009

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

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

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

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

Ответы [ 11 ]

394 голосов
/ 16 мая 2009

В практических целях первое , о котором вы должны беспокоиться, это ИЗМЕНЕНИЕ ПАРОЛЕЙ! Из вашего вопроса не ясно, является ли ваш репозиторий 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

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

79 голосов
/ 02 февраля 2013

Изменение ваших паролей - хорошая идея, но для процесса удаления паролей из истории вашего репо я рекомендую BFG Repo-Cleaner , более быструю и простую альтернативу git-filter-branch, явно предназначенную для удаления личные данные из репозитория Git.

Создайте private.txt файл со списком паролей и т. Д., Который вы хотите удалить (по одной записи в строке), а затем выполните эту команду:

$ java -jar bfg.jar  --replace-text private.txt  my-repo.git

Все файлы с пороговым размером (по умолчанию 1 МБ) в истории вашего репо будут отсканированы, и любая подходящая строка (которой нет в вашем последнем коммите) будет заменена строкой "* ** REMOVED ***». Затем вы можете использовать git gc для удаления мертвых данных:

$ git gc --prune=now --aggressive

BFG обычно в 10-50 раз быстрее, чем работает git-filter-branch, и варианты упрощены и адаптированы к этим двум распространенным сценариям использования:

  • Удаление Сумасшедшие большие файлы
  • Удаление Пароли, учетные данные и другие Личные данные

Полное раскрытие: я являюсь автором репо-уборщика BFG.

18 голосов
/ 22 ноября 2011

Я рекомендую этот сценарий Дэвида Андерхилла, который для меня сработал.

Он добавляет эти команды в дополнение к ветке-фильтру 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
14 голосов

Если вы нажали на 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 Это работает, даже если вы воссоздаете другой репозиторий с тем же именем.

Итак, мой рекомендуемый курс действий:

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

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

    • есть ли у вас ценные данные о проблеме?

      • нет: удалить репозиторий
      • да: обратитесь в службу поддержки
9 голосов
/ 26 января 2015

Чтобы быть ясным: принятый ответ правильный. Попробуй сначала. Однако это может быть излишне сложно для некоторых случаев использования, особенно если вы сталкиваетесь с неприятными ошибками, такими как «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. Если это неприемлемо, вам придется использовать альтернативный подход.

Назовите это ядерным вариантом.

7 голосов
/ 02 декабря 2016

Вот мое решение в windows

git filter-branch --tree-filter "rm -f" filedir / filename '"HEAD

git push --force

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

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

6 голосов
/ 17 сентября 2017

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

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
5 голосов
/ 23 января 2017

Вы можете использовать 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, которые позволили мне собрать это вместе

3 голосов
/ 21 марта 2017

Я должен был сделать это несколько раз на сегодняшний день. Обратите внимание, что это работает только для 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>..

3 голосов
/ 27 апреля 2014

Итак, это выглядит примерно так:

git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore

Удалить кеш для отслеживаемого файла из git и добавить этот файл в .gitignore список

...