Я случайно отправил нежелательный файл ( filename.orig
при разрешении слияния) в свой репозиторий несколько коммитов назад, но я до сих пор не заметил этого. Я хочу полностью удалить файл из истории хранилища.
Можно ли переписать историю изменений так, чтобы filename.orig
она никогда не добавлялась в хранилище?
git
git-filter-branch
git-rewrite-history
git-rm
Грант Лимберг
источник
источник
Ответы:
Пожалуйста, не используйте этот рецепт, если ваша ситуация не соответствует описанной в вопросе. Этот рецепт предназначен для исправления неудачного слияния и преобразования ваших хороших коммитов в фиксированное слияние.
Хотя
filter-branch
будет делать то, что вы хотите, это довольно сложная команда, и я бы, вероятно, решил сделать это сgit rebase
. Это, вероятно, личное предпочтение.filter-branch
может сделать это одной, немного более сложной командой, тогда какrebase
решение выполняет эквивалентные логические операции по одному шагу за раз.Попробуйте следующий рецепт:
(Обратите внимание, что на самом деле вам не нужна временная ветвь, вы можете сделать это с помощью «отсоединенного HEAD», но вам нужно записать идентификатор фиксации, сгенерированный
git commit --amend
шагом, чтобы передатьgit rebase
команде вместо использования временной ветки имя.)источник
git rebase -i
будет быстрее и все так же легко? $ git rebase -i <sh1-of-merge> Пометить правильный как «edit» $ git rm somefile.orig $ git commit --amend $ git rebase --continue Однако по какой-то причине у меня все еще есть этот файл где-то последний раз, когда я сделал это. Вероятно, чего-то не хватает.git rebase -i
Это очень полезно, особенно когда вам нужно выполнить несколько операций rebase-y, но правильно описать правильно, когда вы на самом деле не указываете на чье-то плечо и видите, что они делают с их редактором. Я использую vim, но не все были бы довольны: «ggjcesquash <Esc> jddjp: wq» и такими инструкциями, как «Переместить верхнюю строку после текущей второй строки и изменить первое слово в строке четыре на« редактировать », теперь сохраните и бросить курить быстро кажется сложнее, чем реальные шаги. Вы обычно заканчиваете с некоторыми--amend
и--continue
действиями, а также.Введение: у вас есть 5 доступных решений
Оригинальный плакат гласит:
Есть много разных способов полностью удалить историю файла из git:
В случае с оригинальным постером, изменение коммита на самом деле не вариант, поскольку впоследствии он сделал несколько дополнительных коммитов, но для полноты картины я также объясню, как это сделать, для тех, кто хочет только изменить их предыдущий коммит.
Обратите внимание, что все эти решения включают изменение / переписывание истории / фиксаций одним способом другим, поэтому любой, у кого есть старые копии коммитов, должен будет выполнить дополнительную работу для повторной синхронизации своей истории с новой историей.
Решение 1: внесение поправок в комитеты
Если вы случайно внесли изменение (например, добавление файла) в свой предыдущий коммит и не хотите, чтобы история этого изменения больше существовала, вы можете просто изменить предыдущий коммит, чтобы удалить файл из него:
Решение 2. Жесткий сброс (возможно, плюс перебаз)
Как и в решении № 1, если вы просто хотите избавиться от своего предыдущего коммита, у вас также есть возможность просто сделать полный сброс его родителю:
Эта команда жестко сбросит вашу ветку к предыдущему 1- му родительскому коммиту.
Однако , если, подобно оригинальному постеру, вы сделали несколько коммитов после коммита, для которого вы хотите отменить изменение, вы все равно можете использовать жесткий сброс, чтобы изменить его, но для этого также необходимо использовать ребаз. Вот шаги, которые вы можете использовать, чтобы изменить коммит дальше в истории:
Решение 3: Неинтерактивная Rebase
Это будет работать, если вы просто хотите полностью удалить коммит из истории:
Решение 4: Интерактивные ребазы
Это решение позволит вам выполнить те же действия, что и решения № 2 и № 3, т. Е. Изменить или удалить коммиты дальше в истории, чем ваш непосредственно предыдущий коммит, так что какое решение вы выберете, зависит от вас. Интерактивные перебазировки не подходят для перебазирования сотен коммитов по соображениям производительности, поэтому я бы использовал неинтерактивные перебазировки или решение с ветвями фильтра (см. Ниже) в подобных ситуациях.
Чтобы начать интерактивную перебазировку, используйте следующее:
Это заставит git перемотать историю коммитов назад к родителю коммита, который вы хотите изменить или удалить. Затем он предоставит вам список перемотанных коммитов в обратном порядке в любом редакторе, который будет использовать git (по умолчанию это Vim):
Фиксация, которую вы хотите изменить или удалить, будет в верхней части этого списка. Чтобы удалить его, просто удалите его строку в списке. В противном случае замените «pick» на «edit» в 1- й строке, например так:
Далее введите
git rebase --continue
. Если вы решили полностью удалить коммит, то это все, что вам нужно сделать (кроме проверки, см. Последний шаг для этого решения). Если, с другой стороны, вы хотите изменить фиксацию, то git повторно применит фиксацию и затем приостановит перебазирование.На этом этапе вы можете удалить файл и изменить коммит, а затем продолжить перебазирование:
Вот и все. В качестве последнего шага, независимо от того, изменили ли вы фиксацию или удалили ее полностью, всегда полезно проверить, что в вашу ветку не было внесено никаких неожиданных изменений, перед тем как перебазировать ее с ее состоянием:
Решение 5: Фильтрация ветвей
Наконец, это решение лучше всего, если вы хотите полностью стереть все следы существования файла из истории, и ни одно из других решений не вполне соответствует задаче.
Это удалит
<file>
все коммиты, начиная с корневого коммита. Если вместо этого вы просто хотите переписать диапазон фиксацииHEAD~5..HEAD
, вы можете передать его в качестве дополнительного аргументаfilter-branch
, как указано в этом ответе :Опять же, после того,
filter-branch
как завершено, обычно хорошей идеей является проверка отсутствия других неожиданных изменений, если перед ветвью фильтровать ветвь с предыдущим состоянием.Альтернативный фильтр-ответвление: BFG Repo Cleaner
Я слышал, что инструмент BFG Repo Cleaner работает быстрее, чем
git filter-branch
, поэтому вы можете проверить это как вариант. Это даже упоминается официально в документации ветки фильтра как жизнеспособная альтернатива:Дополнительные ресурсы
источник
filter-branch
пересчет хешей? Если команда работает с репо, где большой файл должен быть отфильтрован, как они это делают, чтобы у всех было одинаковое состояние репо?Если вы ничего не сделали с тех пор, просто
git rm
файл иgit commit --amend
.Если у тебя есть
будет проходить каждое изменение от
merge-point
доHEAD
, удаляет filename.orig и переписывает изменение. Использование--ignore-unmatch
означает, что команда не завершится ошибкой, если по какой-либо причине имя файла.orig отсутствует в изменении. Это рекомендуемый способ из раздела Примеры в справочной странице git-filter-branch .Примечание для пользователей Windows: путь к файлу должен использовать косую черту
источник
git-filter-branch
кажется, дать первый.filter-branch
"
а не'
при использовании Windows, иначе вы получите бесполезную фразу «неверная редакция».Это лучший способ:
http://github.com/guides/completely-remove-a-file-from-all-revisions
Только убедитесь, что сначала сделали резервные копии файлов.
РЕДАКТИРОВАТЬ
Редакция Neon, к сожалению, была отклонена во время обзора.
Смотрите пост Neons ниже, он может содержать полезную информацию!
Например, чтобы удалить все
*.gz
файлы, случайно переданные в репозиторий git:Это все еще не работает для меня? (Я сейчас нахожусь на git версии 1.7.6.1)
Не уверен почему, так как у меня была только одна ветка master. В любом случае, я наконец-то получил чистое репозиторий git, запустив новый пустой и пустой репозиторий git, например
(да!)
Затем я клонирую это в новый каталог и перемещаю его в папку .git. например
(да! наконец-то прибрался!)
После проверки того, что все хорошо, то вы можете удалить
../large_dot_git
и../tmpdir
каталоги (возможно , через пару недель или месяц с этого времени, на всякий случай ...)источник
--prune-empty
в команду filter-branch.Переписывание истории Git требует изменения всех затронутых идентификаторов коммитов, поэтому каждый, кто работает над проектом, должен будет удалить свои старые копии репозитория и сделать новый клон после того, как вы очистите историю. Чем больше людей это доставляет неудобства, тем больше вам нужно веских оснований для этого - ваш лишний файл на самом деле не вызывает проблемы, но если вы работаете над проектом, вы можете также очистить историю Git, если хотите. к!
Чтобы сделать это как можно более простым, я бы порекомендовал использовать BFG Repo-Cleaner , более простую и быструю альтернативу,
git-filter-branch
специально разработанную для удаления файлов из истории Git. Одним из способов облегчения вашей жизни здесь является то, что он фактически обрабатывает все ссылки по умолчанию (все теги, ветви и т. Д.), Но это также в 10 - 50 раз быстрее.Вы должны внимательно выполнить следующие шаги: http://rtyley.github.com/bfg-repo-cleaner/#usage, но основной бит заключается в следующем: загрузите jar BFG (требуется Java 6 или выше) и выполните эту команду :
Вся ваша история репозитория будет отсканирована, и любой файл с именем
filename.orig
(которого нет в вашем последнем коммите ) будет удален. Это значительно проще, чемgit-filter-branch
сделать то же самое!Полное раскрытие: я являюсь автором BFG Repo-Cleaner.
источник
источник
Просто чтобы добавить это к решению Чарльза Бэйли, я просто использовал git rebase -i, чтобы удалить ненужные файлы из предыдущего коммита, и это сработало как чудо. Шаги:
источник
Простейший способ, который я нашел, был предложен
leontalbot
(в качестве комментария), который опубликовал Anoopjohn . Я думаю, что это стоит своего места в качестве ответа:(Я преобразовал его в сценарий Bash)
Все кредиты идут
Annopjohn
иleontalbot
указывают на это.НОТА
Помните, что сценарий не содержит проверок, поэтому убедитесь, что вы не делаете ошибок и что у вас есть резервная копия на случай, если что-то пойдет не так. Это сработало для меня, но может не сработать в вашей ситуации. Используйте его с осторожностью (перейдите по ссылке, если вы хотите узнать, что происходит).
источник
Определенно,
git filter-branch
это путь.К сожалению, этого будет недостаточно для полного удаления
filename.orig
из вашего репозитория, так как на него все еще могут ссылаться теги, записи reflog, пульты и так далее.Я также рекомендую удалить все эти ссылки, а затем вызвать сборщик мусора. Вы можете использовать
git forget-blob
скрипт с этого сайта, чтобы сделать все это за один шаг.git forget-blob filename.orig
источник
Если это последний коммит, который вы хотите очистить, я попытался использовать git версии 2.14.3 (Apple Git-98):
источник
git reflog expire --expire=now --all; git gc --prune=now
это очень плохая вещь. Если у вас нет свободного места на диске, позвольте git garbage собирать эти коммиты через несколько недельЭто то,
git filter-branch
для чего был разработан.источник
Вы также можете использовать:
git reset HEAD file/path
источник