Как исправлять ошибки в Git, не оставляя улик

Posted on Feb 10, 2025

Кто не сталкивался с коммитами вроде ‘Remove debug log’, ‘Fix’ или ‘фикс фикса’? Такие коммиты как грязные носки под кроватью: их не видно, пока не придёт ревьюер с пристальным взглядом или, что еще хуже, потенциальный работодатель, решивший посмотреть на ваш github.

К счастью, Git предлагает два супер-инструмента для того, чтобы история коммитов выглядела так, будто ты всегда знаешь, что делаешь: git commit –fixup и git rebase –autosquash.

⚠️ Важно! Не вздумайте применять rebase в main или stable-ветках, если не хотите, чтобы ваши коллеги не сделали вам больно. Эти штуки нужны для приведения feature-ветки в божеский вид перед слиянием.

Использование fixup и autosquash

Что делает fixup?

Команда git commit –fixup говорит Git: “Я накосячил, но давай сделаем вид, что этого никогда не было”. Она автоматически помечает коммит как исправление указанного коммита, чтобы позже их можно было объединить.

Как работает autosquash?

Команда git rebase -i –autosquash делает всю грязную работу: находит fixup-коммиты и запихивает их обратно в родительский коммит, словно ничего и не происходило.


Практический пример

Шаг 1. Делаем коммиты (как обычно, неидеально)

Представьте, что вы работаете в своей фича-ветке mvp-server и коммитите две новые фичи:

$ git add main.go
$ git commit -m "feat: listen port 8080"
[mvp-server dc4efa9] feat: listen port 8080
 1 file changed, 1 insertion(+)

$ git add main.go
$ git commit -m "feat: added handlers"
[mvp-server ab604f9] feat: added handlers
 1 file changed, 1 insertion(+), 1 deletion(-)

Шаг 2. Ой… нашлась ошибка в первом коммите

Оказывается, в коммите с feat: listen port 8080 была опечатка, и теперь сервер запускается не на 8080, а на 808 порту. Не беда, просто делаем fixup. Но для начала надо найти тот коммит, который будем фиксить. В нашем случае это будет dc4efa9

$ git log --oneline
ab604f9 (HEAD -> mvp-server) feat: added handlers
dc4efa9 feat: listen port 8080
df9f0ae (main) mvp

$ git add main.go
$ git commit --fixup dc4efa9
[mvp-server 62e7318] fixup! feat: listen port 8080

Git сам добавляет fixup! перед сообщением, как бы говоря: “Да-да, я понял, ты хотел исправить, но давай замнем эту тему”.

Если же настроен git hook для добавления в начало сообщения ID-таска, то можно воспользоваться –no-verify , чтобы временно отключить хуки. В противном случае придется при ребейзе руками прописывать pick для fixup-коммита.

$ git commit --no-verify --fixup <commit_hash>

Шаг 3. Проверяем, что нас ждёт

$ git log --oneline
62e7318 (HEAD -> mvp-server) fixup! feat: listen port 8080
ab604f9 feat: added handlers
dc4efa9 feat: listen port 8080
df9f0ae (main) mvp

Шаг 4. Применяем rebase и делаем вид, что всё было идеально с самого начала

Важно, что надо передать в ребейз хеш последнего коммита, который вы хотите сохранить как есть, а не первого, который вы хотите поменять. В нашем случае это будет df9f0ae , так как git будет менять как раз dc4efa9 feat: listen port 8080 .

$ git rebase -i --autosquash df9f0ae

Редактор откроет вот такую картину:

pick dc4efa9 feat: listen port 8080
fixup 62e7318 fixup! feat: listen port 8080
pick ab604f9 feat: added handlers

Просто сохраняем, выходим и наслаждаемся магией.

Шаг 5. Проверяем, что история коммитов идеальна

$ git log --oneline
a72151f (HEAD -> mvp-server) feat: added handlers
0441501 feat: listen port 8080
df9f0ae (main) mvp

Как будто всё было идеально с самого начала, а будущий работодатель уже шлет тебе оффер ибо таких красивых коммитов он еще в жизни не видел и не важно, что код не работает.