Skip to content

Instantly share code, notes, and snippets.

@AMashoshyna
Last active June 29, 2020 15:19
Show Gist options
  • Save AMashoshyna/3e445f7d89e0d1074b4629b1d99a4d8f to your computer and use it in GitHub Desktop.
Save AMashoshyna/3e445f7d89e0d1074b4629b1d99a4d8f to your computer and use it in GitHub Desktop.

git rebase

В общем случае команда git rebase добавляет все коммиты из ветки, на которой вы находитесь, следующими за коммитом, который вы передаете git rebase как аргумент. Если передать первым аргументом ветку, Git найдет последний общий коммит между текущей веткой и целевой веткой и добавит коммиты из текущей в целевую один за одним. Можно представить себе, что git rebase по очереди "накатывает" каждый из коммитов вашей ветки на целевой коммит. При этом у всех "накатанных" коммитов изменяются метаданные (например, родительский коммит), поэтому с точки зрения Git это теперь новые коммиты.

На семинаре мы познакомились с двумя случаями применения git rebase.

Случай 1: объединение веток, git rebase как альтернатива git merge

Для того, чтобы объединить две ветки в одну (например, когда работа над задачей закончена и нужно влить это задачу в ветку master), часто используют команду git merge. Это команда объединяет ветки путем создания отдельного коммита, у которого два родителя - коммиты-вершины каждой из веток на момент слияния. Иногда команда git merge вызывается неявно. Например, это может произойти при вызове команды git pull. Если гит не сможет добавить новые изменения по стратегии fast-forward, создастся merge commit. Мерж-коммиты делают гит-историю нелинейной и плохо управляемой. Проблемы объединения веток при помощи git merge:

  • с историей тяжело работать из-за обилия мерж-коммитов (трудно разобраться)
  • может быть трудно взять нужные коммиты в отдельную ветку при помощи cherry-pick, так как они будут зависеть от предыдущих

Примечание. Избежать нежелательного мерж-коммита при затягивании обновлений можно, если использовать git pull с флагом --ff-only.

git rebase избавляет от нежелательных мерж-коммитов, так как он не меняет целевую ветку, а коммиты из текущей ветки добавляет один за одним. Таким образом, ветки не смешиваются, мерж-коммита нет, а ваша работа оказывается в самом верху целевой ветки.

Дополнительно: Гит присваивает коммитам хеши и различает коммиты по хешам. Рекомендуем почитать о том, как работют хеш-функции (на семинаре эта тема не рассматривалась)

Упражнение
Исходное положение: коммит 0
Шаг 1. Создать ветки feat-1 и feat-2 от коммита 0. В каждую из веток добавить по 2-3 коммита, изменяющих один файл.
Объединить ветки при помощи git merge. Посмотреть, как выглядит история при помощи команды git logg*.
Повторить Шаг 1
Объединить ветки при помощи git rebase. Посмотреть, как выглядит история при помощи команды git logg. Обратить внимание на изменение хешей коммитов при rebase

Случай 2: Чистая история при помощи squash

С одной стороны - желательно комитить почаще, чтобы не потерять работу. с другой стороны, в конце хочется иметь чистую и понятную историю, где каждый коммит представляет собой завершенный кусок работы, а не бесконечные "fix", "fixed fix" etc. Например, если вы работаете над несколькими файлами одновременно и коммитите изменения в каждый из них в случайном порядке, но хотим, чтобы в результате на изменение одного файла приходился только один коммит. Выход - сквош Для этого нужно познакомиться с другим применением git rebase: пересаживать коммиты можно не только на другую ветку, но и на предыдущий коммит в той же ветке. Какая от этого польза? Так как коммиты "накатываются" один за одним, в процессе мы можем их редактировать. Например, изменять commit message, менять коммиты местами или объединять несколько коммитов в один. Последний случай - это и есть squash.

Упражнение: Исходной положение: мы на коммите 0

  1. Внести любое изменение в файл А, сделать коммит 1
  2. Внести любое изменение в файл Б, сделать коммит 2
  3. Снова изменить файл А, сделать коммит 3
  4. При помощи git rebase исправить историю таким образом, чтобы было два коммита - один, меняющий файл А, и один, меняющий файл Б. Для этого нужно заребейсить три последних коммита на коммит 0 интерактивно, при этом поменяв местами коммиты 1 и 3 и "засквошив" их.

Важные замечания:

  1. Так как git rebase меняет коммиты, которые он добавляет в указанное место, нужно быть очень осторожным при rebase коммитов, которые уже отправлены на сервер. Ребейсить коммиты в общих ветках нельзя!
  2. Если в процессе git rebase возникает конфликт, git rebase останавливается, создает маркеры конфликта в файле (<<<<<<<<) и ждет, пока вы решите конфликт и явно продолжите процесс при помощи git rebase --continue. Отдельный коммит (как при мерже) для разрешения конфликта не создается (это еще один плюс git rebase)

Git в распределенной команде

Стратегии Git (например, ГитФлоу) позволяют дают готовое решение для разделения и изоляции работ таким образом, чтобы отдельные команды (или люди) работающие на проектом, не мешали друг другу. Например, тестировщики и разработчики работают со своей веткой и на своем сервере и не мешают друг другу. Как правило, разработчик создает для своей задачи отдельную ветку от ветки master, делает задачу и вливает свою ветку в master через пул-реквест. В зависимости от проекта и выбранной стратегии промежуточных этапов между завершением работы над задачей и попаданием кода в master может быть несколько - бывают отдельные ветки dev, qa, stage (названия примерные). Каждая такая ветка может быть залита (задеплоена) на отдельную машину, где часть команды (разработчики, тестировщики, продакт-оунер) может протестировать код.

*git logg - это алиас для графического представление дерева коммитов: "log --graph --full-history --all --color --pretty=tformat:\"%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s\"". Этот алиас будет доступен тем, кто настроил окружение согласно нашей инструкции.

@AMashoshyna
Copy link
Author

@webuxmotion от коммита 0. По сути это значит "добавь ярлык ветки на коммит 0".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment