Программирование с ИИ
ENRU
Д

Git — сценарии спасения

что набрать, когда всё сломалось

Что это

Не курс по git, а список ситуаций. Все команды прогнаны в настоящем репозитории, вывод настоящий. Основное про git — в статье 5.1.

Каждый день

git status            # что изменено прямо сейчас
git diff              # что именно изменено, построчно
git diff --staged     # что уйдёт в коммит
git add .             # взять всё изменённое
git commit -m "..."   # зафиксировать
git log --oneline     # история коротким списком

Перед тем как просить ИИ о крупной правке, стоит сделать коммит. Это одна команда, и она превращает любую неудачу в «откатиться и попробовать иначе».

Я испортил файл и хочу вернуть как было

$ git diff --stat
 app.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git restore app.py      # вернуть один файл
$ cat app.py
третья версия

Вернуть всё к последнему коммиту:

git restore .

Я удалил файл

$ rm app.py
$ git restore app.py
$ ls
app.py

Пока файл был в последнем коммите, он возвращается.

Я закоммитил не то

Коммит ещё не отправлен — отменить коммит, правки оставить:

$ git reset --soft HEAD~1
$ git status --short
M  app.py

Изменения на месте, коммита нет. Можно поправить и закоммитить заново.

Коммит уже отправлен — не переписывать историю, а добавить обратный:

$ git revert --no-edit HEAD
[main fba3f8d] Revert "третья версия"
 1 file changed, 1 insertion(+), 1 deletion(-)

$ cat app.py
вторая версия

revert создаёт новый коммит, который отменяет старый. История остаётся правдивой, и ни у кого ничего не ломается.

Надо срочно отложить правки

$ echo "черновик" >> app.py
$ git stash          # спрятать и вернуться к чистому состоянию
$ cat app.py
вторая версия

$ git stash pop      # достать обратно
$ cat app.py
вторая версия
черновик

Удобно, когда ИИ наработал половину, а срочно понадобилось проверить что-то другое.

Я закоммитил секрет

$ git rm --cached .env
$ echo ".env" >> .gitignore
$ git add .gitignore && git commit -m "убрал .env из репозитория"
$ git ls-files
.gitignore
app.py

Из рабочей копии и из будущих коммитов .env ушёл. Но:

$ git log --oneline --all -- .env
1badd12 убрал .env из репозитория
5f9507b добавил .env

Файл по-прежнему в истории, и ключ из неё достаётся одной командой. Поэтому порядок действий такой: сначала сменить ключ, а потом уже чистить репозиторий. Если репозиторий публичный — считать ключ скомпрометированным с момента отправки (статья 5.7).

Когда сломалось — а раньше работало

git log --oneline              # найти подозрительный коммит
git show <хеш>                 # посмотреть, что в нём изменилось
git restore --source=<хеш> <файл>   # взять версию файла из коммита

Если коммитов много и непонятно, какой виноват, — есть git bisect, который делит историю пополам (приём из статьи 4.4, только автоматический).

Ветки

git switch -c опыт     # новая ветка от текущего места
git switch main        # вернуться
git merge опыт         # влить сделанное
git branch -d опыт     # удалить ветку

Для работы с ИИ ветка полезна в одном конкретном случае: крупная переделка, про которую заранее неясно, доживёт ли она до конца. В ветке её можно бросить, не убирая за собой.

Я сделал reset --hard и потерял коммит

Коммит, который «пропал» после reset, ещё не удалён. Git помнит, где стоял HEAD каждый раз:

$ git reset --hard HEAD~1
$ cat app.py
первая версия
$ git reflog
a4d85e7 HEAD@{0}: reset: moving to HEAD~1
c03070e HEAD@{1}: commit: вторая версия
a4d85e7 HEAD@{2}: commit (initial): первая версия
$ git reset --hard HEAD@{1}
$ cat app.py
вторая версия

reflog — последняя линия обороны: он хранит записи несколько недель. Но спасает только закоммиченное. Незакоммиченные правки после reset --hard не вернуть ничем — ещё один довод коммитить перед каждой задачей для ИИ.

Чего делать не надо

git push --force в общую ветку. Переписывает историю у всех.

git reset --hard без понимания. Выбрасывает и коммиты, и правки.

Коммит «всё подряд» раз в неделю. Такой коммит невозможно откатить частично — а именно это и нужно, когда ИИ сломал одно из двадцати изменений.

Коммит с непрочитанным диффом. git diff перед коммитом — тридцать секунд, которые ловят случайно оставленный отладочный вывод и забытый ключ.