#git #git_rebase
Мне никак не удается сделать для себя выводы, когда мне следует сделать rebase? Прошу опытных товарищей поделиться опытом и высказать критерии, которые влияют на решение о том что нужно сделать rebase. А также привести примеры ситуаций, когда его делать не нужно. Возьмем ситуацию, когда для реализации фичи1 я сделал ветку1. В этот момент ветка master завершена комитом0. Одновременно со мною Вася паралельно реализовал фичу2 в ветке2 и влил ее в master. Ветка2 состоит из комит1, комит2, комит3 и эти комиты попали в master. Мне бы хотелось с помощью GIT привести свою ветку к тому состоянию, как будто бы я сделал свою ветку1 начиная с комита3. Допустимо ли в моей ситуации применять rebase?
Ответы
Ответ 1
Сделайте бэкап Всегда, когда сомневаетесь, делайте бэкап. Сойдёт любой способ: 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 будет идентичен будущему мерж-коммиту. Но этот способ неэффективен по уже описанным причинам: Требует лишней работы по разрешению конфликтов Ломает содержимое промежуточных коммитов Если есть потребность разрешить конфликты и провести полное тестирование результата мержа, но пока что не мержить в master, лучше применить технику обратного мержа: master мержится в feature. Соответственно, мерж-коммит появляется в ветке feature. Полученный мерж-коммит можно тестировать локально, можно запушить в удалённую ветку origin/feature для обновления мерж-реквеста, прогона тестов, CI, развёртывания на тестовое окружение и т.п. Когда все проверки пройдены, делайте "прямой" мерж - feature в master. Не нужно мержить master в вашу ветку просто так, в процессе работы над фичей, это приводит к истории в виде схемы московского метро. Если можете обойтись без мержа master в feature - обязательно обойдитесь.Ответ 2
В описанной ситуации граф выглядит например так: > 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
Комментариев нет:
Отправить комментарий