>git commit -m "WIP" — три слова, после которых начинается настоящий ад.

Приветствую. Такая технология как Git в представлении не нуждается. Все знают add, commit, push — это как азбука. Но что делать, когда что-то пошло не так? Ошибочный коммит прокатился по ветке? Надо срочно переключиться, но незавершенные правки мешают? Нужно перенести только одно исправление из другой ветки?

Знакомая ситауция? Тогда давайте разберем 5 команд, которые выходят за рамки базового workflow и реально спасают репутацию (и ваши нервные клетки): revert, stash, cherry-pick, reset --soft и bisect. Перейдем от теории к практике.

❯ Теория (минимум, чтобы понимать «почему»)

Git хранит историю как цепочку коммитов(своеобразных контрольных точек). Каждый коммит — это снимок(snapshots) состояния ваших файлов на момент создания + ссылка на родителя(ей). Ветки — это просто подвижные указатели на конкретные коммиты в этой цепочке.

 Хранение данных виде снимков
Хранение данных виде снимков


В Git есть три основных состояния, в которых могут находиться ваши файлы: modified, staged и committed

modified означает, что вы изменили файл, но ещё не закоммичен в базе данных.

staged означает, что вы отметили изменённый файл в его текущей версии для добавления в снимок следующего коммита.

committed означает, что данные надёжно хранятся в вашей локальной базе данных.

Схема перехода состояний файлов в Git
Схема перехода состояний файлов в Git

Staging area часто именуется как Git Index или просто индекс.

Основная ответственность за чистоту истории и корректность кода лежит на разработчике. Однако Git предоставляет достаточно способов для управления историей и рабочим состоянием, когда что-то идет не по плану. Эти инструменты позволяют:

  1. Отменять изменения, уже попавшие в историю.

  2. Временно убирать незавершенную работу.

  3. Точечно переносить изменения между ветками.

  4. Аккуратно переписывать последние коммиты.

  5. Автоматически искать источник проблемы.

Хорошо, мы поняли, что Git — это не только линейное добавление коммитов. А с помощью каких конкретно команд достигается это гибкость в управлении во время кризисных ситуациях? Познакомимся с сегодняшними героями:

5 Спасательных Команд

❯ git revert : Мягкая отмена

  • Проблема: Вы закоммитили и запушили ошибочный код. Просто удалить коммит из истории (reset) на удаленном сервере — плохая практика (ломает историю для коллег). Нужно отменить изменения, но сохранить факт ошибки и исправления.

  • Решение: git revert создает новый коммит, который является инверсией (противоположностью) изменений указанного коммита. Он не стирает старый плохой коммит, а аккуратно «откатывает» его эффект.

    Допустим, наш злосчастный коммит имеет хеш zxc123 
    git revert zxc123
    
    # Git откроет редактор для сообщения нового коммита-отмены 
    # (можно оставить по умолчанию).
    
    # Пушим исправление-отмену
    git push origin main  

    Польза: История остается целостной. Коллеги видят и ошибку, и ваше исправление. Идеально для исправления уже опубликованных ошибок в main/master.

❯ git stash: Мастер переключения контекста

  • Проблема: Вы активно работаете над фичей в ветке feature/login, но срочно нужно починить баг в main. Делать коммит с полуготовым кодом (WIP: Something...) — некрасиво и может сломать сборку. Нужно временно убрать текущие изменения.

  • Решение: git stash берет все изменения в рабочей директории и индексе (те, что были бы добавлены git add), упаковывает их в специальное хранилище («stash») и возвращает рабочую директорию к состоянию последнего коммита. Чисто!

#В ветке feature/login с незавершенными изменениями:

git stash  # Сохраняем изменения в stash. Рабочая директория чиста!

git checkout main   # Переключаемся на main для срочного багфикса

#Чиним баг в main, коммитим, пушим...

git checkout feature/login  # Возвращаемся к своей фиче

git stash pop  # Возвращаются последние застэшенные изменения обратно в рабочую директорию (и удаляются из stash)

#Или:
git stash apply  # Применить изменения, но оставить копию в stash

Польза: Мгновенно освобождает рабочее состояние для срочных задач без создания мусорных коммитов. pop/apply — и вы точно там, где остановились.

❯ git cherry-pick : Точечный перенос

  • Проблема: Вы починили критический баг в ветке hotfix/v1.1 (коммит dev456). Этот фикс срочно нужен и в ветке develop, но переносить всю ветку hotfix (merge) пока нельзя или не нужно. Нужно взять только этот один коммит с исправлением.

  • Решение: git cherry-pick «переносит» изменения из указанного коммита (созданного где-то в другом месте истории) и применяет их как новый коммит в текущей ветке.

    git checkout develop # Переходим в ветку, куда нужен фикс
    
    git cherry-pick dev456 # Git попытается применить изменения из коммита dev456
    
    #Возможны конфликты! Их нужно разрешить, как при мерже.
    
    git add .    # После разрешения конфликтов добавляем файлы
    
    git cherry-pick --continue  # Завершаем применение (создается новый коммит в develop)
    
    git push origin develop

Польза: Позволяет делиться конкретными исправлениями между ветками без полного слияния, поддерживая изоляцию функциональности. Осторожно: злоупотребление может запутать историю.

❯ git reset --soft HEAD~1: Вежливый ребейз последнего коммита

  • Проблема: Вы сделали коммит (commit A), но сразу поняли, что:

Забыли добавить файл.
Сообщение коммита написано криво.
Небольшая ошибка в коде, которую стыдно коммитить отдельно.
Хотите разбить один большой коммит на несколько логичных. 

ВАЖНО – коммит еще не запушен!

  • Решение: git reset --soft HEAD~1 «отматывает» указатель текущей ветки на 1 коммит назад (на родителя HEAD), но сохраняет все изменения из отмененного коммита A в индексе (staging area) и рабочей директории. Фактически, коммит A исчезает из истории текущей ветки, а его изменения готовы к новому коммиту.

#Сделали коммит с ошибкой/недоделкой (commit A), НЕ ПУШИЛИ.

git reset --soft HEAD~1   # История "откатилась" на шаг назад.

# Все изменения из commit A теперь в индексе (как будто вы сделали git add . после правок).
# Исправляем файлы, которые забыли/исправляем ошибки...

git add zabyl.js   # Добавляем то, что забыли
й
git commit -m "Новое сообщение коммита"  # Создаем новый правильный коммит

Польза: Позволяет аккуратно переписать последний, еще не опубликованный коммит, не оставляя следов «стыдных» промежуточных коммитов. Важно: работает только для НЕзапушенных коммитов!

❯ git bisect: Детектив по поиску бага

  • Проблема: В проекте обнаружился баг. Вы уверены, что неделю назад его не было. За это время было сделано 50 коммитов. Ручной поиск коммита, где баг появился — ад. Нужен автоматизированный поиск виноватого.

  • Решение: git bisect использует алгоритм бинарного поиска. Вы указываете:

    «Хороший» коммит (где бага точно нет, git bisect good ).

    «Плохой» коммит (где баг точно есть, обычно текущий HEAD, git bisect bad).
    Git автоматически переключит вас на коммит посередине между "хорошим" и "плохим". Вы проверяете наличие бага и говорите git bisect good (бага нет) или git bisect bad(баг есть). Git сужает диапазон и переключает вас снова. Повторяете, пока Git не укажет точный коммит, где появился баг.

# Начинаем сессию
git bisect start          

#Текущее состояние (HEAD) - плохое (баг есть)
git bisect bad HEAD       

# Тег v1.2 (или хеш коммита) - хорошее (бага нет)
git bisect good v1.2

# Git автоматически переключит на коммит посередине.

# Запускаем тесты/проверяем вручную наличие бага...

# Если баг ЕСТЬ в этом состоянии:
git bisect bad

# Если бага НЕТ в этом состоянии:
git bisect good

# Если не удаётся проверить (например, код не компилируется)
git bisect skip   

# Git переключит на новый коммит (середину нового диапазона). Повторяем проверку...

# В итоге Git сообщит: "abc123 is the first bad commit"

git bisect reset  # Завершаем сессию, возвращаемся в исходную ветку

Польза: Резко сокращает время поиска коммита, в котором была внесена ошибка, с O(n) до O(log n). Незаменим для анализа регрессий.

Фактически, git bisect можно использовать для поиска коммита, который изменил любое свойство вашего проекта; например, коммит, который исправил ошибку, или коммит, который привел к улучшению производительности бенчмарка.


❯ Заключение

Используйте Git не только для линейного добавление кода. Это отличный инструмент для управления историей и рабочим процессом, особенно когда что-то идет не так(а оно всегда идет). Освоение revert, stash, cherry-pick, reset --soft и bisect выводит ваше владение Git на новый уровень. Эти команды:

  1. Сохраняют историю чистой (revert вместо опасного reset).

  2. Повышают вашу гибкость (stash для мгновенного переключения контекста).

  3. Позволяют точечно делиться исправлениями (cherry-pick).

  4. Дают шанс на исправление локальных ляпов (reset --soft для последнего коммита).

  5. Экономят часы отладки (bisect для поиска источника зла).

Не бойтесь их использовать (с пониманием последствий, конечно). Они действительно сэкономят вам кучу нервов и помогут поддерживать репутацию надежного разработчика. 

Когда следующий баг заставит вас плакать в git log, незовите маму — зовите bisect. А если коллега случайно сломает main — дайте ему ссылку на эту статью. Или просто revertните его последний коммит.

Happy Gitting


Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале 

? Читайте также:

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


  1. garm
    24.07.2025 08:39

    Вместо
    git reset --soft HEAD~1

    я обычно использую
    git commit --amend

    Помогает во всех случаях, кроме разбиения большого коммита на несколько маленьких.


    1. Akhmed_theDark
      24.07.2025 08:39

      А чем эта запись отличается от git reset —hard. Помоему тоже самое нет?


      1. garm
        24.07.2025 08:39

        Нет, reset —hard убирает не только последний коммит, но и все его изменения. Если изменения нужно только немного подправить, это не очень удобно.


        1. Fedorkov
          24.07.2025 08:39

          Вы двое, видимо, говорите про git reset --hard HEAD~. Без последнего аргумента команда просто отменяет незакоммиченные изменения (кроме untracked файлов), не трогая последний коммит.


    1. Necessitudo
      24.07.2025 08:39

      А если коммит уже запушен? Работает?


      1. amphasis
        24.07.2025 08:39

        в любом случае после такого придется делать push -f


        1. mvv-rus
          24.07.2025 08:39

          А, может, попробуем обойтись push --force-with-lease ?


          1. amphasis
            24.07.2025 08:39

            Руками я бы это поленился писать, а учитывая то, что веду работу в своей персональной ветке, как будто разницы нет.

            PS. Да и что греха таить, большинство git команд выполняю через интерфейс IDE, а в консоль лишь изредка приходится залезть за каким-нибудь git branch -u


            1. mvv-rus
              24.07.2025 08:39

              Руками я бы это поленился писать

              Visual Studio 2022 позволяет настроить использование из IDE именно --force-with-lease. А я в ней работаю.


    1. Fedorkov
      24.07.2025 08:39

      я обычно использую git commit --amend

      Я обычно ещё добавляю --no-edit, чтобы гит не предлагал редактировать название коммита.


  1. inkvizitor68sl
    24.07.2025 08:39

    Очередная статья про гит без упоминания worktree.
    Worktree нужно пихать в каждую статью про гит двадцать пятым кадром. Как гипнотизеры, в рандомные места в статье вставлять слово worktree. Начинать статью с этого слова, и прощаться с читателями, используя это слово. Можно даже не писать, что это - просто возьмите 10 слов worktree и рассыпьте по статье - но без этого минимума статьи про гит писать нельзя.


  1. eeman22
    24.07.2025 08:39

    git reflog бы еще упомянул.

    Ты случайно долбанул, например,

     git reset --hard

    удалил ветку или потерял коммит - git log их не показывает.

    делаем git reflog + git checkout и в след раз не втыкаем:)


  1. vDyDHp8
    24.07.2025 08:39

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


    1. Viacheslav01
      24.07.2025 08:39

      А я наоборот все руками делаю, ну кроме просмотра изменений больших в файлах.
      Все остальное руками, не доверяю я этим GUI )))


    1. RulenBagdasis
      24.07.2025 08:39

      Ага, а потом: "я не знаю, что случилось, я что-то нажал и оно само" ))) Предпочитаю работать с гитом из консоли, так ты точно уверен, что ты делаешь и какой будет результат. Да и универсальнее так, ты не привязан к редактору/ide, у тебя всегда один и тот же интерфейс.


  1. iboltaev
    24.07.2025 08:39

    --soft можно не писать

    Как же git reabase и git rebase -i ?


  1. guryanov
    24.07.2025 08:39

    А в чем проблема мусорных коммитов? Их же никто не заставляет пушить. Наоборот, закоммитил в ветке задачи коммит tmp и потом можно хоть через год к этой задаче вернуться и доделать. Конечно надо будет этот коммит отредактировать, способов много разных. К примеру тот же git reset HEAD~1 доделать код и закоммить потом как следует.


  1. TAZAQ
    24.07.2025 08:39

    В какой-то момент для меня стала самой полезной команда:
    git rebase --fork-point epic-branch [feature-branch]


    1. Ravius
      24.07.2025 08:39

      Ну вот гуглить что делает(

      да, ребейз - лучшая команда гита, я прост в ide накликиваю.

      upd: rebase прост.


  1. abby
    24.07.2025 08:39

    Если кто-нибудь использует git stash, можете объяснить в чём преимущество по сравнению с неиспользованием. Ещё и в Visual Studio и в Code пиарят, как и тут; запарился уже объяснять альтернативы и помогать коллегам с этим git stash.


    1. xDamneDx
      24.07.2025 08:39

      Очень удобно использовать если ты изменения внес, которые еще рано коммитить, застешил, сходил в другую ветку (например пр чей-то в ide посмотреть), вернулся в свою ветку и сделал git stash pop, но это если аккуратно относиться к коммитам, так-то можно и git commit -am “WIP” и погнал.

      Еще удобно если в текущую ветку нужно подлить изменения: стеш, пулл, поп, вместо ребейса или простигосподи мержа


    1. gluck59
      24.07.2025 08:39

      Git stash полезен например при совпадении следующих двух условий:

      1. Между вашей локальной машиной и сервером существуют некие различия. То ли на сервере линух (а у вас локально вындоуз), то ли на сервере фря (а у вас локально убунта), то ли еще что-то подобное, что нельзя привести в полное соответствие.

      2. У вас локально все ок, а на сервере глюк. Код одинаковый, база одинаковая, а вот глюк.

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

      Даже если вы впоследствии убьете весь этот дебаг, контрольные суммы правленых на сервере файлов изменятся и следующий git pull сругается на "чего-то тут незакоммиченое есть".

      И вот тогда вы пушите фикс найденного глюка в проекте, делаете stash на сервере и затем спокойно повторяете pull там же.

      И всё становится хорошо.


      1. Pavel1114
        24.07.2025 08:39

        не лучшие практики. Отсутствие CI и замена его git pull. Отстуствие логирования, настраиваемого без правки кода. Ну и непонятно зачем тут stash, если логичнее было бы просто git reset --hard - вы же просто хотите потереть вывод дебаг перед pull.


      1. Eltaron
        24.07.2025 08:39

        Git в прод-директории на сервере? Ммм, так вот чей проект ищут боты, брутфорсящие GET /.git/HEAD


        1. gluck59
          24.07.2025 08:39

          Да? Ну хорошо, предположим что уже нашли: https://atmclub.ru/

          Расскажите плиз что у вас получилось.


  1. xDamneDx
    24.07.2025 08:39

    Я бы посоветовал git rebase -i —exec вместо bisect, так можно автоматически прогнать любую команду на интервале коммитов


    1. Pavel1114
      24.07.2025 08:39

      git bisect конечно же поддерживает выполение команды на каждом шаге, что позволяет автоматизировать процесс. Странно, что об этом не упомянуто в статье https://git-scm.com/docs/git-bisect#_bisect_run


  1. abby
    24.07.2025 08:39

    Всё таки, субъективно, со своими коммитами удобнее, потому что сам контролируешь и устоявшийся годами work flow, хотя и stash тоже коммититы создаёт.

    А вообще у меня всегда минимум три worktree или вообще независимых клона. Надо переключиться по какой-либо прочине (срочно, или приоритеты поменялись или что-то перепроверить и т.п.), просто в соседней копии делаешь и всё.

    Тут ещё срочное может быть в ветке другой версии (например, какой-нибудь релиз, или вторая версия, типа legacy, и т.п.) Там свои зависимости как минимум, проект другой, надо всё перезапускать. Всё это дёргать и пересобирать - только время тратить. Со второй копией хоть дебаг оставь в середине, потом вернёшься и всё хорошо.

    При этом почему-то новички в git всегда теряются с этими stash, то у них одно, то другое, то конфликты, то что-то как-то исчезло. Обьясняешь, что делает stash, говоришь, делай так сам, а потом как хочешь применяй свои изменения, и эти проблемы как правило уходят.

    Ответ на https://habr.com/ru/companies/timeweb/articles/927102/comments/#comment_28617254


  1. ZoRDoK
    24.07.2025 08:39

    git commit --amend

    Рекомендую, если хотите красивые коммиты, а не "закоммитил в пятницу вечером, в пн разберусь" - команда добавляет в предыдущий коммит


  1. Contrabondo
    24.07.2025 08:39

    Вероятно, лучше не использовать пуш в main/develop/master а как-нибудь с использованием MR/PR.