Это перевод вчерашней заметки от 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)
Apollo286
12.03.2017 17:52+1А разве нельзя взять *.pyc файлы и декомпилировать те которые вам нужны?
am-amotion-city
12.03.2017 17:55+2Можно, конечно, если они есть. Там в самом начале описан юзкейс и я в него попадал сам: мне показалось, что пошаговая инструкция заслуживает того, чтобы попасть в закладки.
Goodkat
12.03.2017 20:10+15На git надейся, да сам не плошай — тут-то и спасёт локальная история изменений в IDE.
cawakharkov
12.03.2017 20:19+13Вывод — комитьте чаще.
am-amotion-city
12.03.2017 20:42+6Это, кстати, абсолютная истина: я взял за привычку коммитить чуть ли не каждый чих. Учитывая, насколько просто потом все причесать с
git rebase
, это — единственно верная стратегия вообще.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 нужен будет только чтобы ветки кидать туда сюда (для чего он собственно и делался)...
am-amotion-city
14.03.2017 16:07git 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 ? вот вам замечательно ответили.
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
(akasquashto
) который делает то что выше описал…
git sq2 master
или даже сложнее — слить только 2-а первых коммита и оставить последний отдельным…
git sq2 master..w~1
am-amotion-city
14.03.2017 18:44Ну, может быть :)
Вопрос привычки. Я не делаю
squash
в рабочих ветках вообще, поэтому и не очень в теме.
am_devcorp
12.03.2017 20:38+4Еще случай — если код был открыт в каком-нибудь пайчарме, то он скорее всего еще есть в его кэше, и его оттуда можно сравнительно легко вытащить
Разумеется, эта фишка есть не только в пайчарме, а, скорее всего, во всех джетбрейнсовских редакторахstaticlab
12.03.2017 20:52+6Local history действительно есть во всех джетбрейнсовских IDE. Но ведь автор пользуется вимом. Для него есть как минимум два плагина истории. Шах и мат, Джетбрейнс!
rkfg
13.03.2017 00:47В неазслуженно регулярно забываемом Eclipse тоже есть. Меня однажды спасло, когда сделал git reset --hard не в том каталоге.
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
ghostinushanka
12.03.2017 23:53+1Я заметку оригинального автора понял так что файл не удалён(разлинкован) был, а его контент был переписан контентом файла из репы и что единственное место в котором хранились данные из файла до перезаписи была память процесса в контейнере.
А вот про айноды, хардлинки и что на самом деле «трёт rm» — это да, знать, ИМХО, должен каждый себя уважающий Линуксоид.
delvin-fil
13.03.2017 02:51-2Установите…
...Ubuntu.
Без apt-get в тексте не обойтись никак?am-amotion-city
13.03.2017 08:29+2Во-первых, убунту тут ни при чем. Этот дистрибутив — лишь один из многих, унаследовавших
apt
как систему управления пакетами.
Во-вторых, я убежден, что в заметках такого типа (в отличие от руководства по написанию ToDo блокнота на очередном хипстерском движке) нелепо оговариваться насчет «
apt-get
— это установщик пакетов». Если человек вдруг про это не в курсе, ему лучше не дочитывать заметку до конца, целее будет.delvin-fil
13.03.2017 08:46-6Ой ли? Не собираюсь ввязываться в холивары, но.
Но еще тринадцать лет назад я не подозревал, что
унаследовавших apt как систему управления пакетами
Никак не хотел оскорбить!
Пусть! Пусть будет(у жены установлена бубунта)!
Тезисом не надо навязывать — это имел ввиду.am-amotion-city
13.03.2017 09:30+5Я не смог распарсить ваш русский язык, видимо мой парсер грамматики нуждается в корректировке, но уловил нотки сомнения в моих словах.
Даже Вика (sic!) знает, где и как родился
apt
(там можно сходить по ссылкеUbuntu
и почитать, на базе какого дистрибутива один небезызвестный южноафриканец решил делать свой, почему, да как).
3aicheg
13.03.2017 04:54В некотором смысле извращение, наверное, но любую инфу, которая побывала на экране (в т. ч. то, что не писалось в файлы, типа просранного коммента), можно восстановить, если держать постоянно включенной программу, делающую снимки экрана раз в n секунд (TimeSnapper под винду, или вот, вроде, кроссплатформенное).
delvin-fil
13.03.2017 06:00-1Ну позвольте! Я же не сказал(зачем оправдываюсь?)
В целом, ситуация обстоит так(ИМХО): Если вы не умеете пользоваться «установщиком» вашей системы — статья НЕ для вас.
alemiks
13.03.2017 10:57-3>Я облажался,
облажался трижды:
— бездумно использовал гит
— не умеет пользоваться своей IDE/редактором (history)
— не умеет пользоваться дропбоксомam-amotion-city
13.03.2017 11:11+4Ну, гуру, которые никогда не ошибаются с гитом, мы, простые смертные, только завидуем.
Дропбоксом вменяемые люди для кода под NDA не пользуются никогда. В компаниях, которые послеживают за новостями в IT, dropbox на рабочем месте запрещен в принципе.
Вы не поняли, про что заметка, но это не страшно.
alemiks
14.03.2017 11:42Не понял про гуру гита, вы про кого? А также не увидел букв NDA в заметке. По каким признакам вы решили, что у автора код под NDA и дропбокс плохая идея? Кстати, про пункт использования IDE вы тактично умолчали почему-то )
UPDATE: как бонус 600k невменяемых результатов из гугла https://www.google.ru/search?q=use%20dropbox%20as%20code%20repository
mark_ablov
17.03.2017 12:37Я бы всё же сначала бы дамп памяти сделал бы, а то одно неловкое движение завершит отлаживаемый процесс и адиос.
am-amotion-city
18.03.2017 14:40Ну да, ну да :)
Перевод же ж.
Я лично на шифт-принтскрин дамп памяти давно замаппил.
ReklatsMasters
Проще положить исходники в dropbox. Хотя конечно, если дропбокс не успел синхронизировать файлы — придётся изворачиваться именно так. Да и CPU и fs дропбокс нагружает очень не слабо, если много папок.