Как я восстановил папку после `rm -rf app/` с помощью Docker и Git

Катастрофа с 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

  1. Найти контейнер:Я проверил список всех контейнеров, включая остановленные, с помощью команды:

    docker ps -a

    В выводе я нашёл контейнер с именем telegram-bot. Его ID был 94572a371663.

  2. Скопировать папку:Используя ID контейнера, я выполнил:

    docker cp 94572a371663:/app ./

    Эта команда скопировала папку /app из контейнера в локальную папку ./ на моей машине. Документация по docker cp (https://docs.docker.com/engine/reference/commandline/cp/) помогла убедиться, что я указал правильный путь. По хорошему, чтобы потом не переименовывать папку нужно было указать папку получателя как docker cp 94572a371663:/app ./app_docker

  3. Проверка файлов:Я зашёл в ./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

  1. Найти нужный коммит:Я просмотрел историю коммитов с помощью:

    git log --oneline

    Эта команда показала краткий список коммитов (https://git-scm.com/docs/git-log). Для точности я также использовал:

    git log -- app/

    Это позволило увидеть только коммиты, где изменялась папка app/. Я нашёл хэш коммита d1ebea6, где папка ещё существовала.

  2. Восстановить папку:Я выполнил:

    git checkout d1ebea6 -- app/

    Эта команда восстановила папку app/ из указанного коммита, не затрагивая другие файлы (https://git-scm.com/docs/git-checkout).

  3. Сверка восстановленных данных:
    Чтобы убедиться, что файлы из 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
12470login-checkКак я восстановил папку после `rm -rf app/` с помощью Docker и Git

Добавить комментарий