Катастрофа с rm -rf
Работая над проектом, я случайно выполнил команду rm -rf app/ и удалил папку с исходным кодом. Паника наступила мгновенно: проект ещё не был отправлен в удалённый репозиторий, и я испугался, что потерял все последние изменения файлов. К счастью, у меня были два спасительных варианта: ранее собранный Docker-контейнер и локальные Git-коммиты. В этой статье я расскажу, как я восстановил папку app/ сначала из контейнера, а затем из Git для сверки, и поделюсь командами, которые помогли мне. Если вы попали в похожую ситуацию, это руководство для вас!
Шаг 1: Осознание проблемы
После выполнения rm -rf app/ я понял, что папка с кодом моего Telegram-бота исчезла и локальные файлы пропали. PyCharm в локальной истории показал, что папки была удалена, но к сожалению он такое откатить не может. Значит нужно вытаскивать файлы от туда, где они были до момента удаления, а это:
- Docker-контейнер, который я недавно собирал и запускал с помощью
make local-build. К счастью, я не успел выполнить очистку (make clean), так что контейнер и образ были на месте. - Локальный Git-репозиторий с несколькими коммитами, где папка
app/ещё существовала.
Я решил попробовать оба способа восстановления, чтобы вернуть файлы и убедиться в их целостности.
Шаг 2: Восстановление из Docker-контейнера
Мой Dockerfile копирует папку app/ в контейнер с помощью следующих строк:
WORKDIR /app
...
COPY . .Это означает, что файлы должны быть внутри контейнера и я решил извлечь их с помощью команды docker cp.
Шаги восстановления из Docker
Найти контейнер:Я проверил список всех контейнеров, включая остановленные, с помощью команды:
docker ps -aВ выводе я нашёл контейнер с именем
telegram-bot. Его ID был94572a371663.Скопировать папку:Используя ID контейнера, я выполнил:
docker cp 94572a371663:/app ./Эта команда скопировала папку
/appиз контейнера в локальную папку./на моей машине. Документация поdocker cp(https://docs.docker.com/engine/reference/commandline/cp/) помогла убедиться, что я указал правильный путь. По хорошему, чтобы потом не переименовывать папку нужно было указать папку получателя какdocker cp 94572a371663:/app ./app_dockerПроверка файлов:Я зашёл в
./appи убедился, что файлы на месте:ls app/
Важное замечание
Контейнер был доступен только потому, что я не выполнил make clean, который удаляет контейнеры, образы и volumes. Моя команда make clean выглядит так:
clean:
@echo "🧹 Полная очистка (контейнеры, volumes, образы) ..."
$(COMPOSE_LOCAL) down -v --rmi all
$(COMPOSE_PROD) down -v --rmi all
docker system prune -fЕсли бы я её запустил, образ и контейнер могли исчезнуть, и восстановление через Docker стало бы невозможным. Совет: перед очисткой сохраняйте образы с помощью docker save -o backup.tar <image_name>.
Шаг 3: Восстановление из Git для сверки
Чтобы быть уверенным, что восстановленные из Docker файлы правильные, я решил проверить их с помощью локального Git-репозитория. К счастью, я делал коммиты, и папка app/ была в одном из них.
Шаги восстановления из Git
Найти нужный коммит:Я просмотрел историю коммитов с помощью:
git log --onelineЭта команда показала краткий список коммитов (https://git-scm.com/docs/git-log). Для точности я также использовал:
git log -- app/Это позволило увидеть только коммиты, где изменялась папка
app/. Я нашёл хэш коммитаd1ebea6, где папка ещё существовала.Восстановить папку:Я выполнил:
git checkout d1ebea6 -- app/Эта команда восстановила папку
app/из указанного коммита, не затрагивая другие файлы (https://git-scm.com/docs/git-checkout).Сверка восстановленных данных:
Чтобы убедиться, что файлы из Docker (app_docker) и Git (app) идентичны, я использовал командуdiffдля сравнения папок:diff -r app_docker appКак работает
diff?
Командаdiff -r(рекурсивное сравнение) сравнивает все файлы в двух папках, включая их содержимое. Если файлы идентичны,diffне выводит ничего — это значит, что папки совпадают. Если есть различия,diffпокажет, в каких файлах и строках они находятся.Пример использования
diff:
Допустим, у вас есть два файла:app_docker/main.pyиapp/main.py. Выполняем:diff app_docker/main.py app_git/main.pyЕсли файлы различаются, вывод будет выглядеть примерно так:
2c2 < print("Hello from Docker") --- > print("Hello from Git")Это означает, что строка 2 в
app_docker/main.pyотличается от строки 2 вapp_git/main.py. В моём случаеdiff -r app_docker appне вывел ничего, что подтвердило: файлы идентичны.Альтернативный формат вывода:
Для более читаемого результата я попробовал:diff -u app_docker/main.py app/main.pyОпция
-u(unified diff) показывает различия с контекстом, включая несколько строк до и после изменений. Пример вывода:--- app_docker/main.py 2025-06-17 11:00:00 +++ app/main.py 2025-06-17 11:00:00 @@ -1,3 +1,3 @@ # Main bot script -print("Hello from Docker") +print("Hello from Git") bot.run()Дополнительная проверка:
Для большей уверенности я проверил хэши файлов с помощьюsha256sum:sha256sum app_docker/main.py sha256sum app/main.pyЕсли хэши совпадают (например,
a1b2c3...), файлы идентичны. Это полезно для бинарных файлов или еслиdiffкажется сложным. В моём случае хэши подтвердили совпадение.Что делать, если есть различия?
Еслиdiffпоказал различия, откройте файлы в текстовом редакторе или используйте графические инструменты, такие как Meld (meld app_docker app), чтобы визуально сравнить файлы и решить, какая версия правильная. В моём случае различий не было, так что я продолжил работу с восстановленной папкой.
Важное замечание
Git оказался проще, так как не зависел от состояния контейнеров. Регулярные коммиты спасли ситуацию. Совет: делайте git add . и git commit после каждого значимого изменения, даже если не планируете пушить сразу.
Шаг 4: уроки и выводы
Восстановление через Docker сработало, потому что контейнер был на месте. Git оказался надёжным для сверки и, возможно, был бы единственным, если бы я почистил контейнер. Оба метода требуют, чтобы данные были сохранены заранее: образы в Docker или коммиты в Git. Если бы я выполнил make clean или не делал коммиты, восстановление могло бы стать невозможным.
Мой совет: проверяйте команды перед выполнением и не спешите с очисткой. Если вы, как и я, иногда делаете make clean, думая, что код не обновляется в контейнере, убедитесь, что у вас есть резервные копии или коммиты.
Заключение
Случайное удаление папки app/ с помощью rm -rf — это стресс, но восстановить данные можно, если у вас есть Docker-контейнер или локальные Git-коммиты. Я использовал docker cp для извлечения файлов из контейнера и git checkout для восстановления из коммита, а затем сверил результаты. Надеюсь, мой опыт поможет вам избежать паники и вернуть потерянные файлы. Делитесь своими историями в комментариях!
Как можно отблагодарить:
- Оформить удобную для вас подписку на Boosty.to
- Разово поддержать через DonationAlerts
