20

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

Возьмем ситуацию, когда для реализации фичи1 я сделал ветку1. В этот момент ветка master завершена комитом0. Одновременно со мною Вася паралельно реализовал фичу2 в ветке2 и влил ее в master. Ветка2 состоит из комит1, комит2, комит3 и эти комиты попали в master. Мне бы хотелось с помощью GIT привести свою ветку к тому состоянию, как будто бы я сделал свою ветку1 начиная с комита3.

Допустимо ли в моей ситуации применять rebase?

Nick Volynkin
  • 34,094
sys_dev
  • 4,012
  • 2
    Под ребейзом обычно понимают две разные возможности rebase -i: 1) переставить ветку на другой коммит (обычно на актуальный master); 2) объединить (squash) коммиты в один. О чём из этого (или о чём другом) вы спрашиваете? – Nick Volynkin Sep 21 '16 at 09:57
  • 1
    Я бы хотел отдельно отметить тот момент, что с точки зрения корректности истории мердж зачастую лучше ребейза. Т.е. если взять ту же абстрактную ситуацию с мастером, гораздо лучше, если влитие ваших изменений будет отмечено отдельным конкретным коммитом, чтобы это можно было отследить. – etki Sep 21 '16 at 10:12
  • а почему просто не - находясь в ветке ветка1: git pull origin master раз Вася туда пушанул? Помоему логично периодически сводить побочную ветку с мастером. – Гончаров Александр Sep 21 '16 at 10:13
  • 1
    @Etki я там написал рекомендацию использовать merge --no-ff после ребейза. Буду рад, если что-то полезное добавите. – Nick Volynkin Sep 21 '16 at 10:17
  • 1
    @NickVolynkin да там сложно что-то добавить ) – etki Sep 21 '16 at 10:36
  • @ГончаровАлександр мы тут написали два ответа, в целом в них есть ответ и на ваш вопрос. Но если вы прочитаете и вопрос останется актуальным - сообщите пожалуйста, я что-нибудь добавлю именно про это. – Nick Volynkin Sep 21 '16 at 11:02
  • @Nick Volynkin да, я уже прочитал, вопросов нет, спасибо. – Гончаров Александр Sep 21 '16 at 11:06
  • у rebase нет общего понятия можно/нужно это вопрос политики команды и больше ничего. Это как с исключениями — кто-то использует постоянно, кто-то время от времени, а кто-то бежит от них как от огня. – ixSci Sep 21 '16 at 12:13
  • @Abyx, не правда. В команде могут быть различные политики по-поводу rebase/not rebase побочных веток и вообще по работе с побочными ветками. – ixSci Sep 21 '16 at 12:29
  • В Вашей ситуации это просто must git fetch git rebase origin/master – erapid Sep 28 '16 at 10:21

2 Answers2

15

Сделайте бэкап

Всегда, когда сомневаетесь, делайте бэкап. Сойдёт любой способ:

git branch backup
git tag backup
git reflog

Сохраняйте историю!

Если вы ребейзите feature-ветки на master перед мержем, настоятельно рекомендую вам использовать merge --no-ff, т.е. форсировать создание мерж-коммита. Без этого будет получаться fast-forward и полностью линейная история.

Мерж-коммиты будут показывать историю работы над проектом, в частности момент мержа feature-ветки и автора мержа (кто пропустил код в master). Начиная с версии 2.6.0 git умеет отменять (revert) мерж-коммиты. Без мерж-коммита вам придётся указывать точный набор коммитов для отмены, что будет непросто при линейной истории.

Когда нельзя

  • Нельзя ребейзить ничего в стабильных ветках (master, stable, production, release-1.0 и т.п.).
  • Когда вы запушили коммит в удалённый репозиторий (общий) и кто-то его использовал:
    • Ответвился от него
    • Сделал cherry-pick в другую ветку
    • Замержил в другую ветку
    • Сослался на этот коммит (GitLab & GitHub в таком случае создают комментарий на странице коммита с упоминанием ссылки)
  • Никогда нельзя ребейзить чужие коммиты. Если вы это сделаете, ночью к вам придёт Линус и сделает ребейз рук на бёдра.

С осторожностью

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

Если в вашей ветке довольно много коммитов и есть конфликты - вам придётся разрешать их многократно (именно потому, что переписывается содержимое каждого коммита). Для сравнения, при обычном мерже вы разрешаете их один раз, собственно в мерж-коммите.

Когда можно

  • Когда у вас есть локальная ветка, которой нет в удалённом репозитории
  • Или когда ветка есть в удалённом репозитории, но её точно никто не использовал.

Когда следует

  • Если в вашей команде принято делать ребейз на master перед мержем и/или открытием мерж-реквеста.
  • Если в вашей команде принято объединять (сплющивать, squash) коммиты в один перед мержем и/или открытием мерж-реквеста.

Вышеуказанные причины работают, если в команде есть также правило не использовать чужие коммиты, которые не замержены в мастер. Если какое-то из условий из раздела "Когда нельзя" выполняется - ребейзить нельзя.

Тестирование перед мержем

Ребейз даёт некоторое преимущество в тестировании. Предположим, есть ветки master и feature. Автоматические и ручные тесты, автопроверки кода, профилировщики и прочее показывают положительный результат на обоих ветках. Сохранится ли этот результат после мержа? В общем случае, неизвестно. Даже если мерж без конфликтов, код вообще может не компилироваться после мержа.

Поэтому есть резон сделать ребейз на master перед финальным тестированием. Тогда головной коммит feature будет идентичен будущему мерж-коммиту. Но этот способ неэффективен по уже описанным причинам:

  1. Требует лишней работы по разрешению конфликтов
  2. Ломает содержимое промежуточных коммитов

Если есть потребность разрешить конфликты и провести полное тестирование результата мержа, но пока что не мержить в master, лучше применить технику обратного мержа: master мержится в feature. Соответственно, мерж-коммит появляется в ветке feature.

Полученный мерж-коммит можно тестировать локально, можно запушить в удалённую ветку origin/feature для обновления мерж-реквеста, прогона тестов, CI, развёртывания на тестовое окружение и т.п. Когда все проверки пройдены, делайте "прямой" мерж - feature в master.

Не нужно мержить master в вашу ветку просто так, в процессе работы над фичей, это приводит к истории в виде схемы московского метро. Если можете обойтись без мержа master в feature - обязательно обойдитесь.

Nick Volynkin
  • 34,094
  • Правильно я понял из ответа, что если в команде не принято эти rebase использовать, то они и не нужны вообще? Я вот просто перед pullRequest делаю мерж мастера, разрешаю конфликты и всё. А зачем этот rebase - непонятно) – ЮрийСПб Sep 21 '16 at 11:26
  • @ЮрийСПб мерж мастера немного усложняет граф истории. Если ваши коммиты никто не использовал, то можно сделать squash всех коммитов в один + ребейз на мастер. Тогда разрешать конфликты придётся всего раз, как с мержем. В истории будет всего один лаконичный коммит фичи и мерж-коммит в мастер. – Nick Volynkin Sep 21 '16 at 11:38
  • @ЮрийСПб но это не годится для промежуточного ревью, например. – Nick Volynkin Sep 21 '16 at 11:39
  • «Нельзя ребейзить ничего в стабильных ветках» можно и нужно — git pull --rebase – ixSci Sep 21 '16 at 12:08
  • @NickVolynkin, Просто вы столько страшных вещей описали... Мне теперь страшно будет это делать) – ЮрийСПб Sep 21 '16 at 12:08
  • @ixSci я имел в виду стабильные ветки в общем репозитории. А git pull --rebase предполагает, что я сам в свою копию стабильной ветки что-то коммичу. Для чего это может быть нужно? – Nick Volynkin Sep 21 '16 at 12:17
  • @ixSci но вообще замечание верное, надо уточнить ответ. – Nick Volynkin Sep 21 '16 at 12:18
  • Не понял, Вы не понимаете зачем может быть нужно git pull --rebase? Самый просто примеру: A сделал pull, потом коммит и делает push, но не может, ибо в это время Б уже сделал push. Теперь A должен сделать снова pull, но если не указать rebase, то pull создаст коммит. Со временем из таких коммитов вырастает весьма страшная история. – ixSci Sep 21 '16 at 12:31
  • "Сделал cherry-pick в другую ветку" - но cherry-pick же не связан с исходными коммитами и их исчезновение никак не повлияет на результирующую ветку. – Qwertiy Oct 18 '16 at 17:55
4

В описанной ситуации граф выглядит например так:

> git log --graph --decorate --oneline --all
*   12ef823 (HEAD -> master) Merge branch 'b2'
|\
| * 3b8d7a6 (b2) b2:commit3
| * 5892389 b2:commit2
| * 245fefe b2:commit1
|/
| * ccca93c (b1) b1:commit1
|/
* 406f362 initial commit

rebase

Самый простой и логичный способ обновиться - это rebase

> git checkout b1
> git rebase master
> git log --graph --decorate --oneline --all
* 5f613a9 (HEAD -> b1) b1:commit1
*   12ef823 (master) Merge branch 'b2'
|\
| * 3b8d7a6 (b2) b2:commit3
| * 5892389 b2:commit2
| * 245fefe b2:commit1
|/
* 406f362 initial commit

merge

В принципе можно вмержить себе мастер, но при этом граф усложнится

> git checkout b1
> git merge master
> git log --graph --decorate --oneline --all
*   16d4e98 (HEAD -> b1) Merge branch 'master' into b1
|\
| *   12ef823 (master) Merge branch 'b2'
| |\
| | * 3b8d7a6 (b2) b2:commit3
| | * 5892389 b2:commit2
| | * 245fefe b2:commit1
| |/
* | ccca93c b1:commit1
|/
* 406f362 initial commit

А после мержа в мастер граф станет еще сложнее:

> git checkout master
> git merge b1 --no-ff
> git log --graph --decorate --oneline --all
*   1443680 (HEAD -> master) Merge branch 'b1'
|\
| *   16d4e98 (b1) Merge branch 'master' into b1
| |\
| |/
|/|
* |   12ef823 Merge branch 'b2'
|\ \
| * | 3b8d7a6 (b2) b2:commit3
| * | 5892389 b2:commit2
| * | 245fefe b2:commit1
|/ /
| * ccca93c b1:commit1
|/
* 406f362 initial commit

новая ветка

Вместо rebase можно сделать новую ветку, и перенести туда свои коммиты

> git checkout -b b1-1 master
> git cherry-pick ccca93c
> git log --graph --decorate --oneline --all
* ebaac4a (HEAD -> b1-1) b1:commit1
*   12ef823 (master) Merge branch 'b2'
|\
| * 3b8d7a6 (b2) b2:commit3
| * 5892389 b2:commit2
| * 245fefe b2:commit1
|/
| * ccca93c (b1) b1:commit1
|/
* 406f362 initial commit

но смысла в этом мало, проще сделать rebase

Abyx
  • 31,143
  • можно вмержить себе мастер - я против вмерживания мастера, если только в этом нет строгой необходимости. – Nick Volynkin Sep 21 '16 at 10:36
  • Ну вы хорошо показали, к какому аду это приводит. ) – Nick Volynkin Sep 21 '16 at 10:41