Git удалить файл из всех коммитов
Позже я обнаружил, что в коммит по ошибке был добавлен файл.
Как я могу удалить файл из последней фиксации?
Я думаю, что другие ответы здесь неверны, потому что это вопрос перемещения ошибочно зафиксированных файлов обратно в промежуточную область из предыдущей фиксации без отмены внесенных в них изменений. Это можно сделать, как предложил Паритош Сингх:
Затем сбросьте ненужные файлы, чтобы исключить их из фиксации:
Если по какой-либо причине (как это было в моем случае) у вас возникнут проблемы с сбросом всех файлов из последней фиксации - как в git reset --soft HEAD^ - и ваш случай соответствует следующим условиям, вы можете сделать, как я объясню ниже.
- файл, который вы пытаетесь удалить, уже существовал в репозитории перед последней фиксацией
- вы можете отменить все изменения в файле с момента предыдущей фиксации ( HEAD
Затем вы можете отменить все изменения с момента предыдущей фиксации (HEAD
2), сохранить файл, обработать его ( git add filename ) и затем запустить git commit --amend --no-edit . Это приведет к фиксации «новых изменений» - фактически повторная фиксация файла до последней фиксации, как это было до последней фиксации.
Другой подход, который мы можем сделать, - это:
- Удалить файл
- Сделайте новую фиксацию с удаленным файлом
- Сделайте интерактивное перебазирование и раздавите оба коммитов
- От себя
Вы можете просто использовать эту команду:
Я скопировал текущие файлы в другую папку, а затем избавился от всех неопубликованных изменений:
Затем скопируйте вещи обратно. Зафиксировать, нажать.
Если вы еще не отправили свои изменения в git
Он сбросит все изменения и вернется к одной фиксации.
Если это последняя сделанная вами фиксация и вы хотите удалить файл из локального и удаленного репозитория, попробуйте следующее:
Сбросить ненужный файл
Это сработало для меня, чтобы удалить файл из репозитория битового ведра, который я сначала отправил в ветвь.
Если вы используете GitHub и еще не отправили коммит, GitHub Desktop легко решает эту проблему:
Если вам больше не нужен этот файл, вы можете сделать
Это отменит последнюю фиксацию в локальных репозиториях и переместит все обратно в рабочую область, как перед выполнением фиксации. Затем просто используйте любой инструмент Git UI как обычно (например, TortoiseGit, Git UI, Git Extensions . ), чтобы деактивировать файлы, которые мы не хотим фиксировать, а затем повторите фиксацию.
На самом деле, я думаю, что более быстрый и простой способ - использовать интерактивный режим git rebase.
4, как бы далеко вы ни зашли)
А затем вместо «выбрать» используйте «редактировать». Я не осознавал, насколько мощным является «редактирование».
Надеюсь, вы найдете это полезным.
git reset --soft HEAD^ отменяет вашу фиксацию, и когда вы набираете git status , он говорит вам, что делать:
Была такая же проблема, когда у меня есть изменения в локальной ветке, где я хотел вернуть только один файл. Для меня сработало -
( feature / target_branch ниже - это место, где у меня есть все мои изменения, включая те, которые я хотел отменить для определенного файла)
( feature / staging - это моя временная промежуточная ветка, в которую я буду нажимать все желаемые изменения, за исключением изменения этого одного файла)
Создайте локальную ветвь из моей origin / feature / target_branch - назовите ее feature / staging .
Моя рабочая локальная ветка feature / target_branch была объединена с ветвью feature / staging .
Отметьте функция / постановка , затем git reset --soft ORIG_HEAD (теперь все изменения из функции / постановки будут поэтапно, но не зафиксированы.)
Неустановил файл, который я ранее зарегистрировал, с ненужными изменениями
Изменена ветвь восходящего потока для feature / staging на origin / feature / target_branch .
Фиксировал остальные поэтапные изменения и отправил вверх по течению на мой удаленный origin / feature / target_branch
Если вы хотите удалить файлы из предыдущих коммитов, используйте фильтры
Если вы видите эту ошибку:
Невозможно создать новую резервную копию. Предыдущая резервная копия уже существует в refs / original / Принудительно перезаписать резервную копию с помощью -f
Просто удалите резервные копии ссылок на вашем локальном репо
Что-то, что сработало для меня, но все же думаю, что должно быть лучшее решение:
Просто оставьте изменение, которое вы хотите отменить, в другом коммите, проверьте другие
Выполните последовательность следующих команд:
Просто хотел дополнить верхний ответ, так как мне пришлось запустить дополнительную команду:
Использование git GUI может упростить удаление файла из предыдущей фиксации.
Предполагая, что это не общая ветка, и вы не против перезапись истории, затем запустите:
Вы можете отменить отметку файла, который был ошибочно зафиксирован, и затем нажать «Зафиксировать».
Файл удаляется из фиксации, но будет сохранен на диске . Поэтому, если вы сняли отметку с файла после его ошибочного добавления, он отобразится в вашем списке неотслеживаемых файлов (и если вы сняли отметку с файла после его ошибочного изменения, он будет отображаться в ваших изменениях, не включенных в список фиксации).
Оставит вам локальный файл по-прежнему. Если вам тоже не нужен файл локально, вы можете пропустить параметр --cached.
Если вся работа выполняется в вашей локальной ветке, вам нужно сохранить файл в более позднем коммите, и, как и при наличии чистой истории, я думаю, что более простой способ сделать это может быть:
Вы можете просто попробовать.
И создайте новую фиксацию.
Однако есть замечательная программа "gitkraken". что упрощает работу с git.
Следующее приведет к деактивации только того файла, который вы намеревались, что и просил OP.
Вы увидите что-то вроде следующего .
Изменения, которые необходимо зафиксировать: (используйте "git reset HEAD . ", чтобы отключить сцену)
изменено: / путь / к / файлу
Изменения, не запланированные для фиксации: (используйте «git add . », чтобы обновить то, что будет зафиксировано) (используйте «git checkout - . », чтобы отменить изменения в рабочем каталоге)
изменено: / путь / к / файлу
- «Изменения, которые необходимо зафиксировать» - это предыдущая версия файла перед фиксацией. Это будет выглядеть как удаление, если файл никогда не существовал. Если вы зафиксируете это изменение, будет ревизия, которая вернет изменение в файл в вашей ветке.
- «Изменения, не предназначенные для фиксации» - это внесенное вами изменение и текущее состояние файла.
На этом этапе вы можете сделать с файлом все, что захотите, например выполнить сброс до другой версии.
Когда вы будете готовы совершить:
Или (если у вас есть другие изменения, которые вы пока не хотите фиксировать)
Я объясню вам на примере.
Пусть A, B, C - 3 последовательных коммита. Фиксация B содержит файл, который не должен быть зафиксирован.
1.В начале забыл добавить в .gitignore папку target/ в которой хранятся скомпилированные *.jar *.class и прочие файлы. 2.позже через несколько коммитов обнаружил что папка .git весит 12+ мегабайт, по размеру предполагаю что это забытый мной jar файл (кода у меня
15 килобайт, все .class файлы
14 килобайт) 3.нашел этот файл руками он весит 12 МБ и лежит в папке
Прошел несколько вопросов на русском и английском stackoverflow + google пробовал следующее:
- git filter-branch --index-filter 'git rm --cached --ignore-unmatch FILENAME' --prune-empty -- --all
- git filter-branch --index-filter 'git rm --cached --ignore-unmatch FILENAME' HEAD
- git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch FILENAME' --prune-empty --tag-name-filter cat -- --all
Вместо FILENAME пробовал подставлять вот это:
- target/gs-rest-service-0.1.0.jar
- gs-rest-service-0.1.0.jar
- target/
- *.jar
В итоге у меня 2 вопроса: -Как выяснить что это весит 12МБ в папке .git и как это удалить?
вот ссылка на мо проект на github, можно скачать как zip-архив или клонировать:
(да я пытаюсь написать Rest-бэкэнд на Spring Boot'e для крестиков-ноликов)
вы можете посмотреть содержимое каталога target (во всех коммитах):
или информацию о конкретном файле target/gs-rest-service-0.1.0.jar :
удалить файл во всех коммитах можно, например, так:
p.s. если репозиторий был склонирован ещё куда-то/кем-то, то там/тому надо будет принудительно переключиться на отправленную вами переписанную историю:
или просто заново склонировать репозиторий в пустой каталог.
после того, как вы перезаписали историю, объект типа blob, содержащий удалённый файл, стал «осиротевшим». чтобы удалить его, надо воспользоваться командой gc (gargabe collection):
как показывает вывод команды $ du -sb .git (выполненной до и после $ git gc ), занимаемый каталогом .git объём изменился на 242997 байт (13254649-13011652). вероятно, именно столько занимал удалённый файл (в сжатом виде).
после того, как вы перезаписали свою локальную историю, удалённый файл (пока) не стал «осиротевшим» — на него есть ссылки из (пока не переписанной) истории подключенного репозитория (который на github-е находится). после того, как вы перепишете историю и на github-е, команда
должна будет удалить объект типа blob, содержащий этот «осиротевший» файл.
дополнение
полную очистку и упаковку всех объектов, чтобы добиться минимального размера каталога .git , можно выполнить примерно так:
ваш репозиторий (т.е., содержимое каталога .git ), после удаления того большого файла, и полной переупаковки, стал занимать у меня 187165 байт.
Удаление файлов с конфиденциальной информацией из Git-репозитория ( изображение большого размера )
Минимизация ущерба
Итак, вы случайно закоммитили файл с конфиденциальной информацией. Назовём этот файл .env . Сразу после того, как это случилось, надо задать себе пару вопросов:
- Отправлен ли коммит в удалённый репозиторий?
- Является ли удалённый репозиторий общедоступным?
▍Коммит пока не отправлен в удалённый репозиторий
Файлы останутся в рабочей копии репозитория, вы сможете внести в проект необходимые изменения.
Если же вы хотите сохранить коммит и вам нужно просто удалить из него определённые файлы, тогда поступите так:
Параметр --amend можно использовать только для работы с самым свежим коммитом. Если вы, после неудачного коммита, добавили ещё несколько, воспользуйтесь такой командой:
▍Коммит отправлен в удалённый репозиторий
Если вы уже отправили коммит в удалённый репозиторий, то, в первую очередь, вам нужно знать о том, чем отличаются публичные и приватные репозитории.
Если ваш репозиторий является приватным, и при этом он не доступен ботам или людям, которым вы не доверяете, вы можете просто внести поправки в последний коммит, воспользовавшись парой вышеприведённых команд.
Если вы отправили в репозиторий, после проблемного коммита, и другие коммиты, это не помешает вам убрать файлы с конфиденциальными данными из истории Git, воспользовавшись командой git filter-branch или инструментом BFG Repo-Cleaner.
Вот пример использования git filter-branch :
Но, делая это, учитывайте два важных аспекта подобных изменений, вносимых в репозиторий:
- Вы меняете историю Git. Если на текущее состояние репозитория полагаются другие люди, если от этого состояния зависят какие-то ветки того же репозитория, его форки, открытые PR, то это нарушит их работу. В подобных случаях относитесь к репозиторию как к общедоступному и постарайтесь не вносить изменения в его историю.
- Вам нужно будет очистить кеш. Вам понадобится обратиться в службу поддержки платформы, на которой хранится ваш репозиторий, и попросить очистить его кеш. Несмотря на то, что вы исправили проблемный коммит или переписали историю репозитория, старый коммит, содержащий конфиденциальные данные, останется в кеше. Для того чтобы к нему обратиться, нужно будет знать его ID, но к нему можно будет получить доступ до тех пор, пока кеш не очистят.
Нужно ли создавать новые секретные ключи в том случае, если их актуальные версии попали в публичный репозиторий?
Если кратко ответить на вопрос, вынесенный в заголовок, то — нужно. Если ваш репозиторий общедоступен, или если вы, по любой причине, полагаете, что он — не место для хранения секретных данных, вам необходимо будет счесть попавшие в него конфиденциальные данные скомпрометированными.
Даже если вы удалили эти данные из репозитория, вы ничего не сможете сделать с ботами и с форками репозитория. Как же поступить?
- Деактивируйте все ключи или пароли. Это надо сделать в первую очередь. После того, как вы деактивируете ключи, конфиденциальные сведения, ушедшие в общий доступ, оказываются бесполезными.
- Настройте файл .gitignore . Сделайте в .gitignore записи о файлах с конфиденциальной информацией для того чтобы Git не отслеживал бы состояние этих файлов.
- Подготовьте коммит, в котором нет файлов с конфиденциальной информацией.
- Отправьте изменения в репозиторий, снабдите коммит пояснениями о возникшей ситуации. Не пытайтесь скрыть ошибку. Все программисты, работающие над проектом, включая вас, по достоинству оценят наличие в репозитории коммита с разъяснениями ситуации и с описанием того, что именно было исправлено с помощью данного коммита.
Рекомендации по хранению конфиденциальных файлов в проектах, в которых для контроля версий применяется Git
Для того чтобы не допустить утечек конфиденциальной информации стоит придерживаться следующих рекомендаций.
▍Храните секретные данные в файле .env (или в другом подобном файле)
Ключи к API и другие подобные сведения стоит хранить в единственном файле .env . При таком подходе, если Git не отслеживает состояние файла .env , вы, добавив в этот файл новый ключ, не отправите его случайно в репозиторий.
Ещё одно преимущество такого подхода заключается в том, что так у вас будет доступ ко всем ключам через глобальную переменную process .
▍Используйте, если это возможно, ключи API
Скомпрометированные ключи API легко деактивировать, такие ключи легко создать заново. Если это возможно — используйте именно их, а не нечто вроде логинов и паролей.
▍Храните ключи API, пользуясь средствами вашего инструмента для сборки проектов
Ключи API обычно нужны при сборке приложений. Инструменты для сборки проектов, вроде Netlify, позволяют держать ключи в защищённых хранилищах. Такие ключи автоматически внедряются в приложение с использованием глобальной переменной process .
Управление переменными окружения
▍Добавьте запись о файле .env в файл .gitignore
Сделайте так, чтобы Git не отслеживал бы файлы, содержащие конфиденциальную информацию.
▍Подготовьте шаблонный файл .env.template
Наличие подобного шаблонного файла помогает тем, кто работает над проектом, добавлять в проект ключи API, избавляя их от необходимости чтения документации.
▍Не меняйте историю Git в удалённых репозиториях
Постарайтесь строго придерживаться этого правила. Если вы следовали вышеприведённым рекомендациям, то историю Git вам менять и не потребуется.
Итоги
Надеюсь, мой материал поможет вам в безопасной работе с конфиденциальными данными.
А вам случалось отправлять в общедоступный репозиторий что-то такое, что туда попадать не должно?
На коммите 4 я случайно добавил свой файл credentials.json и подтолкнул к репо.
На коммите 5 я удалил файл, сделал коммит и отправил это изменение в репозиторий.
В настоящее время файл не отображается в последнем коммите. Но если пользователь проверяет историю коммитов, он может перейти к коммиту 4 и проверить содержимое моего файла.
Как я могу навсегда удалить файл из истории коммитов, чтобы он выглядел так, будто файл никогда не был добавлен в репозиторий.
Примечание. -
я уже попробовал ниже команду: -
Не выдает никакой ошибки, но файл не удаляется из истории.
На самом деле файл находится в папке / src. Но странно то, что когда я даю команду ниже (включая полный путь):
полный путь / src / Credentials.json находится за пределами хранилища.
Это потому, что я уже удалил свой файл в коммите 5? Что я могу сделать в этом сценарии?
Является ли создание нового репо с нуля единственным вариантом?
3 ответа
Предполагая, что никто не клонировал хранилище, вы можете использовать git rebase -i , чтобы переписать историю и удалить файл.
Используйте git rebase -i <commit-hash-of-commit-3> . Откроется редактор со списком коммитов, начиная с коммита-4. Вы можете удалить коммит (удалив строку и сохранив файл), отредактировать его и т. Д.
Выберите «редактировать» для коммита-4. Сохраните файл. Вы вернетесь к оболочке с файлами, добавленными в git 'index', но еще не зафиксированными.
Теперь вы можете git rm credentials.json удалить файл и git commit --amend изменить коммит. ( обновляется )
Наконец git rebase --continue чтобы закончить. Вы вернетесь к оболочке, и файл больше не будет частью репозитория.
Если позже вы добавили коммит, который зависит от файла Credentials.json, вы можете получить ошибку во время фазы продолжения. Затем Git останавливается на проблемном коммите, и вы снова можете использовать команды git (сброс / добавление), чтобы изменить коммит и продолжить.
Я бы рекомендовал прочитать страницу справки GitHubs:
Вы можете использовать BFG Repo-Cleaner
bfg --delete-files Credentials.json my-repo.git
Вы можете использовать git filter-branch :
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all
(где путь, например, src/Credentials.json , Это тоже может вам помочь)
Стоит отметить, что если у кого-то уже есть копия репо, вы должны удалить ее и там! (или вы заставляете переклонировать / вытащить репо)
Не нужно создавать новый репо. git filter-branch работает.
Не используйте полный путь в git filter-branch , используйте относительный путь src/Credentials.json .
Кстати, bfg гораздо проще использовать для новичка. ( bfg принимает имя файла без пути.)
Читайте также: