Руководство по исправлению ошибок с помощью Git (часть 2)

Опубликовано: 2022-03-10
Краткое резюме ↬ Ошибки. Эти жестокие злодеи не останавливаются даже на прекрасном мире разработки программного обеспечения. Но хотя мы не можем избежать ошибок, мы можем научиться их исправлять! В этой статье будут показаны правильные инструменты для вашей повседневной работы с Git. Возможно, вы также захотите ознакомиться с первой статьей серии.

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

Поехали!

Восстановление удаленной ветки с помощью Reflog

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

К счастью, есть способ вернуть эту ветку из мертвых — с помощью инструмента Git под названием «Reflog». Мы использовали этот инструмент в первой части нашей серии, но вот небольшое напоминание: Reflog похож на журнал, в котором Git отмечает каждое движение указателя HEAD в вашем локальном репозитории. Другими словами, менее заумные слова: каждый раз, когда вы извлекаете, фиксируете, объединяете, перебазируете, выбираете вишни и т. д., создается запись в журнале. Это делает Reflog идеальной подстраховкой, когда что-то идет не так!

Давайте рассмотрим конкретный пример:

 $ git branch * feature/login master

Мы видим, что в настоящее время у нас проверена feature/login нашей ветки. Предположим, что это ветка, которую мы собираемся удалить (непреднамеренно). Однако, прежде чем мы сможем это сделать, нам нужно переключиться на другую ветку, потому что мы не можем удалить нашу текущую ветку HEAD!

 $ git checkout master $ git branch -d feature/login

Наша ветка с ценными функциями исчезла, и я дам вам минуту, чтобы (а) понять серьезность нашей ошибки и (б) немного пооплакать. После того, как вы вытерли слезы, нам нужно найти способ вернуть эту ветку! Давайте откроем Reflog (просто набрав git reflog ) и посмотрим, что он нам приготовил:

Reflog Git протоколирует все основные действия в нашем локальном репозитории.
Git's Reflog протоколирует все основные действия в нашем локальном репозитории. (Большой превью)

Вот несколько комментариев, которые помогут вам разобраться в выводе:

  • Прежде всего, вам нужно знать, что Reflog сортирует свои записи в хронологическом порядке: самые новые элементы находятся вверху списка.
  • Самый верхний (и, следовательно, самый новый) элемент — это команда git checkout , которую мы выполнили перед удалением ветки. Это регистрируется здесь в Reflog, потому что это одно из тех «движений указателя HEAD», которые Reflog так прилежно записывает.
  • Чтобы исправить нашу серьезную ошибку, мы можем просто вернуться в состояние до этого — что также чисто и ясно записано в Reflog!

Итак, давайте попробуем это, создав новую ветку (с именем нашей «потерянной» ветки), которая начинается с этого хэша SHA-1 состояния «до»:

 $ git branch feature/login 776f8ca

И вуаля! Вы будете рады видеть, что мы восстановили нашу, казалось бы, потерянную ветку!

Если вы используете графический интерфейс Git для рабочего стола, такой как «Tower», вы можете воспользоваться хорошим ярлыком: просто нажмите CMD + Z на клавиатуре, чтобы отменить последнюю команду — даже если вы только что насильственно удалили ветку!

Настольный графический интерфейс, такой как Tower, может упростить процесс исправления ошибок.
Еще после прыжка! Продолжить чтение ниже ↓

Перемещение коммита в другую ветку

Во многих командах существует соглашение не фиксировать долго выполняющиеся ветки, такие как main или develop : такие ветки должны получать новые коммиты только через интеграцию (например, слияния или перебазирования). И все же, конечно, ошибки неизбежны: мы иногда забываем и тем не менее совершаем эти ветки! Итак, как мы можем убрать беспорядок, который мы сделали?

Перемещение фиксации в правильную ветку назначения
Наш коммит попал не в ту ветку. Как мы можем переместить его в правильную ветку назначения? (Большой превью)

К счастью, такие проблемы можно легко исправить. Засучим рукава и приступим к работе.

Первый шаг — переключиться на правильную ветку назначения, а затем переместить фиксацию, используя команду cherry-pick :

 $ git checkout feature/login $ git cherry-pick 776f8caf

Теперь у вас будет фиксация в нужной ветке, где она должна была быть изначально. Потрясающий!

Но осталось сделать еще одно: нам нужно сначала очистить ветку, на которую он случайно приземлился! Команда cherry-pick , так сказать, создала копию коммита, но оригинал все еще присутствует в нашей долго работающей ветке:

Копия фиксации в правильной ветке, но оригинал по-прежнему отображается в неправильной ветке.
Мы успешно создали копию коммита в правильной ветке, но оригинал все еще здесь — в неправильной ветке. (Большой превью)

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

 $ git checkout main $ git reset --hard HEAD~1

Как видите, здесь мы используем команду git reset , чтобы стереть ошибочный коммит. Параметр HEAD~1 указывает Git «вернуться на 1 ревизию назад за HEAD», эффективно удаляя самую верхнюю (и в нашем случае нежелательную) фиксацию из истории этой ветки.

И вуаля: коммит теперь там, где он должен был быть в первую очередь, и наша длительная ветка чиста — как будто нашей ошибки никогда не было!

Редактирование сообщения старого коммита

Слишком легко вставить опечатку в сообщение коммита и обнаружить ее гораздо позже. В таком случае старый добрый --amend параметр git commit не может решить эту проблему, потому что он работает только для самого последнего коммита. Чтобы исправить любую фиксацию, которая старше этой, мы должны прибегнуть к инструменту Git под названием «Интерактивная перебазировка».

Сообщение коммита, которое стоит изменить
Вот сообщение коммита, которое стоит изменить. (Большой превью)

Во-первых, мы должны сообщить Interactive Rebase, какую часть истории коммитов мы хотим отредактировать. Это делается путем передачи ему хэша коммита: родительского коммита того, которым мы хотим манипулировать.

 $ git rebase -i 6bcf266b

После этого откроется окно редактора. Он содержит список всех коммитов после того, который мы предоставили в качестве основы для Interactive Rebase в команде:

Отображение диапазона коммитов, которые мы выбрали для редактирования в сеансе Interactive Rebase
Диапазон коммитов, которые мы выбрали для редактирования в сеансе Interactive Rebase. (Большой превью)

Здесь важно, чтобы вы не следовали своему первому импульсу: на этом шаге мы еще не редактируем сообщение коммита. Вместо этого мы только сообщаем Git, какие манипуляции мы хотим выполнить с какими коммитами. Весьма удобно, что в комментариях внизу этого окна есть список ключевых слов действия. В нашем случае мы размечаем строку #1 с помощью reword (тем самым заменяя стандартный pick ).

Все, что осталось сделать на этом шаге, это сохранить и закрыть окно редактора. В ответ откроется новое окно редактора, содержащее текущее сообщение фиксации, которую мы разметили. И вот , наконец, пришло время внести свои правки!

Вот весь процесс с первого взгляда для вас:

Использование Interactive Rebase для редактирования старого сообщения коммита от начала до конца.

Исправление сломанного коммита (очень элегантным способом)

Наконец, мы собираемся взглянуть на fixup , швейцарский армейский нож среди инструментов для удаления. Проще говоря, это позволяет вам исправить сломанный/неполный/неправильный коммит постфактум. Это действительно замечательный инструмент по двум причинам:

  1. Неважно, в чем проблема.
    Возможно, вы забыли добавить файл, должны были что-то удалить, сделать неправильное изменение или просто опечатку. fixup работает во всех этих ситуациях!
  2. Это очень элегантно.
    Наша нормальная инстинктивная реакция на ошибку в коммите — создать новый коммит, исправляющий проблему. Такой способ работы, каким бы интуитивным он ни казался, очень быстро делает историю коммитов очень хаотичной. У вас есть «оригинальные» коммиты, а затем эти маленькие «вспомогательные» коммиты, которые исправляют то, что пошло не так в исходных коммитах. Ваша история усеяна мелкими, бессмысленными коммитами, из-за которых трудно понять, что произошло в вашей кодовой базе.
Историю ваших коммитов может быть очень трудно прочитать, если вы постоянно исправляете небольшие ошибки с помощью так называемых временных коммитов.
Постоянное исправление мелких ошибок с помощью «вспомогательных коммитов» делает вашу историю коммитов очень трудной для чтения. (Большой превью)

Вот здесь-то и вступает в дело исправление. Оно позволяет вам по-прежнему делать эту корректирующую fixup фиксацию. Но тут начинается волшебство: затем он применяет его к исходному, сломанному коммиту (исправляя его таким образом), а затем полностью отбрасывает уродливый пластырь!

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

Мы можем пройти практический пример вместе! Допустим, выбранный здесь коммит не работает.

Элегантное исправление выбранного неверного коммита
Выбранный коммит некорректен — и мы собираемся исправить это элегантным способом. (Большой превью)

Допустим также , что я подготовил изменения в файле с именем error.html , которые решат проблему. Вот первый шаг, который нам нужно сделать:

 $ git add error.html $ git commit --fixup 2b504bee

Мы создаем новый коммит, но сообщаем Git, что он особенный: это исправление старого коммита с указанным хэшем SHA-1 (в данном случае 2b504bee ).

Теперь вторым шагом является запуск сеанса Interactive Rebase, поскольку fixup принадлежит большому набору инструментов Interactive Rebase.

 $ git rebase -i --autosquash 0023cddd

Об этой команде стоит пояснить две вещи. Во-первых, почему я указал здесь 0023cddd в качестве хэша ревизии? Потому что нам нужно начать нашу сессию Interactive Rebase с родительской фиксации нашего сломанного товарища.

Во-вторых, для чего нужна опция --autosquash ? С наших плеч уходит много работы! В открывшемся окне редактора для нас уже все подготовлено:

Окно сеанса Interactive Rebase
Окно сеанса Interactive Rebase (большой предварительный просмотр)

Благодаря опции --autosquash Git уже сделал за нас всю тяжелую работу:

  1. Он пометил нашу маленькую временную фиксацию ключевым словом fixup action. Таким образом, Git объединит его с фиксацией непосредственно выше , а затем отбросит его.
  2. Он также соответствующим образом переупорядочил строки, переместив наш вспомогательный коммит прямо под коммит, который мы хотим исправить (опять же: fixup работает, комбинируя размеченный коммит с коммитом выше !).

Короче: нам ничего не остается, как закрыть окно!

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

  • Бывший неработающий коммит исправлен: теперь он содержит изменения, которые мы подготовили в нашем пластыре коммита.
  • От самого уродливого пластыря-фиксатора отказались: история коммитов чистая и легко читаемая — как будто и не было никакой ошибки.
Пример того, как выглядит чистая история коммитов
Конечный результат после использования инструмента исправления: чистая история коммитов! (Большой превью)

Умение исправлять ошибки — это суперсила

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

Если вы хотите узнать больше об исправлении ошибок с помощью Git, я могу порекомендовать бесплатную «Аптечку первой помощи для Git», серию коротких видеороликов именно на эту тему.

Получайте удовольствие от ошибок — и, конечно же, с легкостью их исправляйте!