Введение: у вас есть 5 доступных решений
Оригинальный плакат гласит:
Я случайно отправил нежелательный файл ... в мой репозиторий несколько коммитов
назад ... Я хочу полностью удалить файл из истории хранилища.
Это
можно переписать историю изменений так, чтобы filename.orig
никогда не было
добавили в хранилище в первую очередь?
Есть много разных способов полностью удалить историю файла из
мерзавец:
- Внесение изменений.
- Хард ресет (возможно плюс ребаз).
- Неинтерактивный ребаз.
- Интерактивные перебазирования.
- Фильтрация веток.
В случае с оригинальным постером, изменение коммита на самом деле не вариант
сам по себе, так как он сделал несколько дополнительных коммитов впоследствии, но ради
полноты, я также объясню, как это сделать, для тех, кто оправдывает
хочет изменить свой предыдущий коммит.
Обратите внимание, что все эти решения включают изменение / переписывание истории / коммитов
так или иначе, так что любой со старыми копиями коммитов должен будет сделать
дополнительная работа по повторной синхронизации их истории с новой историей.
Решение 1: внесение поправок в комитеты
Если вы случайно внесли изменение (например, добавление файла) в свой предыдущий
совершить, и вы не хотите, чтобы история этого изменения больше существовала, тогда
Вы можете просто изменить предыдущий коммит, чтобы удалить файл из него:
git rm <file>
git commit --amend --no-edit
Решение 2. Жесткий сброс (возможно, плюс перебаз)
Как и решение № 1, если вы просто хотите избавиться от предыдущего коммита, то вы
также есть возможность просто сделать полный сброс к своему родителю:
git reset --hard HEAD^
Эта команда жестко переустановит вашу ветку к предыдущему 1 st parent
совершить.
Однако , если, как и в оригинальном постере, вы сделали несколько коммитов после
Если вы хотите отменить изменения, вы все равно можете использовать полную перезагрузку
изменить его, но для этого также необходимо использовать rebase. Вот шаги, которые
Вы можете использовать, чтобы изменить коммит дальше в истории:
# Create a new branch at the commit you want to amend
git checkout -b temp <commit>
# Amend the commit
git rm <file>
git commit --amend --no-edit
# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --preserve-merges --onto temp <old-commit> master
# Verify your changes
git diff master@{1}
Решение 3: Неинтерактивная Rebase
Это будет работать, если вы просто хотите полностью удалить коммит из истории:
# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp <parent-commit>
# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --preserve-merges --onto temp <commit-to-remove> master
# Or use `-p` insteda of the longer `--preserve-merges`
git rebase -p --onto temp <commit-to-remove> master
# Verify your changes
git diff master@{1}
Решение 4: Интерактивные ребазы
Это решение позволит вам выполнить те же задачи, что и решения № 2 и
# 3, то есть изменить или удалить коммиты дальше в истории, чем ваш немедленно
предыдущий коммит, так что какое решение вы выберете, зависит от вас.
Интерактивные перебазировки не подходят для перебазирования сотен коммитов, для
из соображений производительности, поэтому я бы использовал неинтерактивные перебазировки или ветку фильтра
решение (см. ниже) в подобных ситуациях.
Чтобы начать интерактивную перебазировку, используйте следующее:
git rebase --interactive <commit-to-amend-or-remove>~
# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~
Это заставит git перемотать историю коммитов назад к родителю
совершить, что вы хотите изменить или удалить. Затем он представит вам список
перемотка фиксирует в обратном порядке в любом редакторе git установлен (это
Vim по умолчанию):
pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)
Фиксация, которую вы хотите изменить или удалить, будет в верхней части этого списка.
Чтобы удалить его, просто удалите его строку в списке. В противном случае замените «выбор» на
«edit» в строке 1 st , например:
edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
Далее введите git rebase --continue
. Если вы решили полностью удалить коммит,
то, что это все, что вам нужно сделать (кроме проверки, см. последний шаг для
это решение). Если, с другой стороны, вы хотите изменить коммит, то git
повторно применяет фиксацию, а затем приостанавливает перебазирование.
Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
На этом этапе вы можете удалить файл и изменить коммит, а затем продолжить
перебазироваться:
git rm <file>
git commit --amend --no-edit
git rebase --continue
Вот и все. В качестве последнего шага, изменили ли вы коммит или удалили его
полностью, это всегда хорошая идея, чтобы убедиться, что никаких других неожиданных измененийбыли добавлены в вашу ветку путем изменения ее состояния до переделки:
git diff master@{1}
Решение 5: Фильтрация ветвей
Наконец, это решение лучше, если вы хотите полностью стереть все следы
существование файла из истории, и ни одно из других решений не до
задание.
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'
Это удалит <file>
из всех коммитов, начиная с корневого коммита. Если
вместо этого вы просто хотите переписать диапазон фиксации HEAD~5..HEAD
, тогда вы можете
передать это в качестве дополнительного аргумента filter-branch
, как указано в
этот ответ :
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD
Опять же, после завершения filter-branch
обычно неплохо проверить
что нет других неожиданных изменений, если ваша ветка
предыдущее состояние перед операцией фильтрации:
git diff master@{1}
Альтернатива фильтра-ответвления: BFG Repo Cleaner
Я слышал, что инструмент BFG Repo Cleaner работает быстрее, чем git filter-branch
, поэтому вы можете проверить это как вариант. Официально упоминается в документации ветки фильтра в качестве приемлемой альтернативы:
git-filter-branch позволяет вам делать сложные переписанные сценарии оболочки
вашей истории Git, но вам, вероятно, не нужна эта гибкость, если
вы просто удаляете ненужные данные , например, большие файлы или пароли.
Для этих операций вы можете рассмотреть BFG
Repo-Cleaner , основанный на JVM
альтернатива git-filter-branch, как минимум, в 10-50 раз быстрее для
эти варианты использования, и с совершенно разными характеристиками:
Любая конкретная версия файла очищается ровно один раз . BFG, в отличие от git-filter-branch, не дает вам возможности обрабатывать
файл по-разному в зависимости от того, где или когда он был зафиксирован в вашем
история. Это ограничение дает основное преимущество в производительности
BFG, и хорошо подходит для очистки плохих данных - вы не
все равно где плохие данные, вы просто хотите, чтобы они исчезли .
По умолчанию BFG использует все преимущества многоядерных машин, параллельно очищая деревья файлов коммитов. git-filter-branch очищает
фиксирует последовательно (то есть однопоточным образом), хотя равно
можно написать фильтры, которые включают в себя свой собственный параллелизм, в
скрипты, выполняемые против каждого коммита.
Опции команды очень
более ограничивающий, чем ветка git-filter, и посвященный только
задачи удаления нежелательных данных, например: --strip-blobs-bigger-than 1M
.
Дополнительные ресурсы
- Pro Git & sect; 6.4 Инструменты Git - История переписывания .
- git-filter-branch (1) Страница руководства .
- git-commit (1) Страница руководства .
- git-reset (1) Страница руководства .
- git-rebase (1) Страница руководства .
- Очиститель репо BFG (см. Также этот ответ от самого создателя ).