Это перевод вчерашней заметки от Simon Willison

Я облажался, бездумно используя git (git checkout -- — не на том файле) и умудрился удалить код, который я только что написал… но он все еще был загружен в исполняемый процесс в докер-контейнере. Вот, как я восстановил код, используя https://pypi.python.org/pypi/pyrasite/ и https://pypi.python.org/pypi/uncompyle6


Подключите удаленный шелл к докеру


Установите GDB (это требует pyrasite)


apt-get update && apt-get install gdb

Установите pyrasite — это позволит подключить питоновкий шелл к запущенному процессу


pip install pyrasite

Установите uncompyle6, это позволит декомпилировать объекты в памяти обратно в питоновский код


pip install uncompyle6

Отыщите PID процесса, который исполняет ваш код


ps aux | grep python

Подключите интерактивный шелл используя pyrasite


pyrasite-shell <PID>

Итак, у нас есть интерактивный питоновский шелл! Импортируйте код, который необходимо восстановить


>>> from my_package import my_module

Определите, какие функции и классы мы восстанавливаем


>>> dir(my_module)
['MyClass', 'my_function']

Декомпилируйте функции в исходный код


>>> import uncompyle6
>>> import sys
>>> uncompyle6.main.uncompyle(
    2.7, my_module.my_function.func_code, sys.stdout
)
# uncompyle6 version 2.9.10
# Python bytecode 2.7
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
# [GCC 5.4.0 20160609]
# Embedded file name: /srv/my_package/my_module.py
function_body = "appears here"

Для классов, придется декомпилировать каждый метод по отдельности


>>> uncompyle6.main.uncompyle(
    2.7, my_module.MyClass.my_method.im_func.func_code, sys.stdout
)
# uncompyle6 version 2.9.10
# Python bytecode 2.7
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
# [GCC 5.4.0 20160609]
# Embedded file name: /srv/my_package/my_module.py
class_method_body = "appears here"

Вот он, ваш было почти утерянный код.

Поделиться с друзьями
-->

Комментарии (28)


  1. ReklatsMasters
    12.03.2017 17:45
    -24

    Проще положить исходники в dropbox. Хотя конечно, если дропбокс не успел синхронизировать файлы — придётся изворачиваться именно так. Да и CPU и fs дропбокс нагружает очень не слабо, если много папок.


  1. Apollo286
    12.03.2017 17:52
    +1

    А разве нельзя взять *.pyc файлы и декомпилировать те которые вам нужны?


    1. am-amotion-city
      12.03.2017 17:55
      +2

      Можно, конечно, если они есть. Там в самом начале описан юзкейс и я в него попадал сам: мне показалось, что пошаговая инструкция заслуживает того, чтобы попасть в закладки.


  1. Goodkat
    12.03.2017 20:10
    +15

    На git надейся, да сам не плошай — тут-то и спасёт локальная история изменений в IDE.


  1. cawakharkov
    12.03.2017 20:19
    +13

    Вывод — комитьте чаще.


    1. am-amotion-city
      12.03.2017 20:42
      +6

      Это, кстати, абсолютная истина: я взял за привычку коммитить чуть ли не каждый чих. Учитывая, насколько просто потом все причесать с git rebase, это — единственно верная стратегия вообще.


      1. vvzvlad
        14.03.2017 13:15

        А как причесать?


      1. sebres
        14.03.2017 14:23

        я взял за привычку коммитить чуть ли не каждый чих.

        +1


        причесать с git rebase

        Ну если полная история всех тех чихов изменений не нужна есть же commit --amend (сразу) или тот же "быстрый squash" (не знаю как по-русски его зовут):
        git reset --soft HEAD~3 && git commit — сошьет 3-и последних коммита в один.


        Если взять за привычку всегда работать в ветке work, то ее можно сливать (в тот же master) опять же одним коммитом:
        git checkout master && git merge --squash work && git commit ...
        Или чтоб остаться в ветке work:
        git reset --soft master && git commit ...


        Да много еще как можно...


        Тогда и git rebase нужен будет только чтобы ветки кидать туда сюда (для чего он собственно и делался)...


        1. am-amotion-city
          14.03.2017 16:07

          git reset --soft HEAD~3 && git commit

          Зачем это, когда есть --fixup?


          1.7.4.txt: * "git commit" learned --fixup and --squash options to help later invocation
          1.7.4.txt-   of the interactive rebase.

          . vvzvlad ? вот вам замечательно ответили.


          1. sebres
            14.03.2017 16:58

            Зачем это, когда есть --fixup

            Чем оно проще?
            Строго говоря fixup это (несколько странный* имхо) хелпер для git rebase -i --autostash --autosquash...


            Мне не нравится как минимум полное собрание всех месседжей от всех interim коммитов.
            Во вторых если я не хочу "интерактивно" (а это как правило так, ибо нужно тупо смять все в одно)?
            Ну и в третьих кто вам мешает оформить ваш любимый способ squash тоже как какой-нить алиас. ;)


            * теперь почему он странный: ну вот я привык работать в ветке w, имеем там 3-и interim коммита (относительно мастер ветки).
            Хочу слить все три сквашем до master и остаться в ветке w.
            Интуитивно я бы вызвал это как-нибудь так: git commit --fixup master или git commit --squash master (и все).
            А имеем то что имеем...


            Поэтому есть собственный алиас sq2 (aka squashto) который делает то что выше описал…
            git sq2 master
            или даже сложнее — слить только 2-а первых коммита и оставить последний отдельным…
            git sq2 master..w~1


            1. am-amotion-city
              14.03.2017 18:44

              Ну, может быть :)


              Вопрос привычки. Я не делаю squash в рабочих ветках вообще, поэтому и не очень в теме.


  1. am_devcorp
    12.03.2017 20:38
    +4

    Еще случай — если код был открыт в каком-нибудь пайчарме, то он скорее всего еще есть в его кэше, и его оттуда можно сравнительно легко вытащить

    Разумеется, эта фишка есть не только в пайчарме, а, скорее всего, во всех джетбрейнсовских редакторах


    1. staticlab
      12.03.2017 20:52
      +6

      Local history действительно есть во всех джетбрейнсовских IDE. Но ведь автор пользуется вимом. Для него есть как минимум два плагина истории. Шах и мат, Джетбрейнс!


    1. rkfg
      13.03.2017 00:47

      В неазслуженно регулярно забываемом Eclipse тоже есть. Меня однажды спасло, когда сделал git reset --hard не в том каталоге.


  1. celebrate
    12.03.2017 23:00
    +9

    Вообще любой файл, который еще не был закрыт, можно спасти:

    root@test:~# lsof 123
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    python  3193 root    3r   REG  252,1       15 1476 123
    root@test:~# cat 123
    Test test test
    root@test:~# rm -f 123
    root@test:~# cat 123
    cat: 123: No such file or directory
    root@test:~# ll /proc/3193/fd/
    total 0
    dr-x------ 2 root root  0 Mar 12 19:56 ./
    dr-xr-xr-x 9 root root  0 Mar 12 19:56 ../
    lrwx------ 1 root root 64 Mar 12 19:56 0 -> /dev/pts/10
    lrwx------ 1 root root 64 Mar 12 19:56 1 -> /dev/pts/10
    lrwx------ 1 root root 64 Mar 12 19:56 2 -> /dev/pts/10
    lr-x------ 1 root root 64 Mar 12 19:56 3 -> /root/123 (deleted)
    root@test:~# cat /proc/3193/fd/3
    Test test test
    root@test:~# cat /proc/3193/fd/3 > 456
    root@test:~# cat 456
    Test test test
    


    1. ghostinushanka
      12.03.2017 23:53
      +1

      Я заметку оригинального автора понял так что файл не удалён(разлинкован) был, а его контент был переписан контентом файла из репы и что единственное место в котором хранились данные из файла до перезаписи была память процесса в контейнере.

      А вот про айноды, хардлинки и что на самом деле «трёт rm» — это да, знать, ИМХО, должен каждый себя уважающий Линуксоид.


  1. delvin-fil
    13.03.2017 02:51
    -2

    Установите…
    ...Ubuntu.
    Без apt-get в тексте не обойтись никак?


    1. am-amotion-city
      13.03.2017 08:29
      +2

      Во-первых, убунту тут ни при чем. Этот дистрибутив — лишь один из многих, унаследовавших apt как систему управления пакетами.


      Во-вторых, я убежден, что в заметках такого типа (в отличие от руководства по написанию ToDo блокнота на очередном хипстерском движке) нелепо оговариваться насчет «apt-get — это установщик пакетов». Если человек вдруг про это не в курсе, ему лучше не дочитывать заметку до конца, целее будет.


      1. delvin-fil
        13.03.2017 08:46
        -6

        Ой ли? Не собираюсь ввязываться в холивары, но.
        Но еще тринадцать лет назад я не подозревал, что

        унаследовавших apt как систему управления пакетами

        Никак не хотел оскорбить!

        Пусть! Пусть будет(у жены установлена бубунта)!
        Тезисом не надо навязывать — это имел ввиду.


        1. am-amotion-city
          13.03.2017 09:30
          +5

          Я не смог распарсить ваш русский язык, видимо мой парсер грамматики нуждается в корректировке, но уловил нотки сомнения в моих словах.


          Даже Вика (sic!) знает, где и как родился apt (там можно сходить по ссылке Ubuntu и почитать, на базе какого дистрибутива один небезызвестный южноафриканец решил делать свой, почему, да как).


          1. delvin-fil
            13.03.2017 16:42

            Ха, «минусы» после вашего комментария!


  1. 3aicheg
    13.03.2017 04:54

    В некотором смысле извращение, наверное, но любую инфу, которая побывала на экране (в т. ч. то, что не писалось в файлы, типа просранного коммента), можно восстановить, если держать постоянно включенной программу, делающую снимки экрана раз в n секунд (TimeSnapper под винду, или вот, вроде, кроссплатформенное).


    1. delvin-fil
      13.03.2017 06:00
      -1

      Ну позвольте! Я же не сказал(зачем оправдываюсь?)

      В целом, ситуация обстоит так(ИМХО): Если вы не умеете пользоваться «установщиком» вашей системы — статья НЕ для вас.


  1. alemiks
    13.03.2017 10:57
    -3

    >Я облажался,
    облажался трижды:
    — бездумно использовал гит
    — не умеет пользоваться своей IDE/редактором (history)
    — не умеет пользоваться дропбоксом


    1. am-amotion-city
      13.03.2017 11:11
      +4

      Ну, гуру, которые никогда не ошибаются с гитом, мы, простые смертные, только завидуем.


      Дропбоксом вменяемые люди для кода под NDA не пользуются никогда. В компаниях, которые послеживают за новостями в IT, dropbox на рабочем месте запрещен в принципе.


      Вы не поняли, про что заметка, но это не страшно.


      1. alemiks
        14.03.2017 11:42

        Не понял про гуру гита, вы про кого? А также не увидел букв NDA в заметке. По каким признакам вы решили, что у автора код под NDA и дропбокс плохая идея? Кстати, про пункт использования IDE вы тактично умолчали почему-то )

        UPDATE: как бонус 600k невменяемых результатов из гугла https://www.google.ru/search?q=use%20dropbox%20as%20code%20repository


  1. mark_ablov
    17.03.2017 12:37

    Я бы всё же сначала бы дамп памяти сделал бы, а то одно неловкое движение завершит отлаживаемый процесс и адиос.


    1. am-amotion-city
      18.03.2017 14:40

      Ну да, ну да :)


      Перевод же ж.


      Я лично на шифт-принтскрин дамп памяти давно замаппил.