August 12, 2021

Как мне не удалось гладко перенести выборочные изменения с Git

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

Итак, я попробовал два решения:

  • Первое - сохранить правки значений переменных в стек, модифицировать код функций и закоммитить изменения, а затем отменить действия из стека.
  • Второе - сохранить в отдельной ветке в виде двух коммитов правку переменных и правку функций и перенести только второй коммит в основную ветку.

Изменения стека

Рассмотрим проект с файлом, который изначально имел следующий вид:

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

Затем восстановим изменения:

Новая версия файла такая:

Затем сымитируем изменения функционала (которые нам реально нужно будет сохранить) - добавим строку и сделаем коммит:

Модифицированная версия файла:

Теперь отменим изменения из стека командой:

git stash show -p stash@{1} | git apply -R:

Получили ошибку, так как версия файла после применения изменений из стека поменялась (я же надеялся на гладкое изменение строки со значением df2):

Если модифицировать команду, нацеливая на поиск общего предка (у версии перед исправлением и новой), Git потребует разрешить конфликт:

git stash show -p stash@{1} | git apply -R3

То есть сама система не может догадаться, что нужно оставить, а что удалить. Изменения, внесенные через стек и коммит объединены.

Перенос изменений выбранного коммита

Создадим отдельную ветку, закоммитим изменения переменной df2, затем добавим строку с df3 и закоммитим опять:

Теперь переключимся на ветку master:

И с помощью команды

git cherry-pick хеш_коммита

попробуем перенести "вторые" изменения:

Получим схожее с первым "неполное" решение:

Опять же из-за несовпадение версий файлов второго коммита (зависит от первого) и того, который перед первым, система не может самостоятельно принять решение.