Когда вы используете git rebase вместо git merge? - программирование

Когда вы используете git rebase вместо git merge?

Когда рекомендуется использовать git rebase vs. git merge?

Нужно ли мне снова объединиться после успешной перезагрузки?

4b9b3361

Ответ 1

Краткая версия

  • Merge принимает все изменения в одной ветки и объединяет их в другую ветвь в одном коммите.
  • Rebase говорит, что мне нужна точка, в которой я разветвлен, чтобы перейти к новой отправной точке.

Итак, когда вы используете один из них?

Объединить

  • Предположим, вы создали ветвь с целью разработки единой функции. Когда вы захотите вернуть эти изменения к мастеру, вам, вероятно, понадобится merge (вы не заботитесь о сохранении всех промежуточных коммитов).

Rebase

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

Ответ 2

Это просто, с rebase вы говорите использовать другую ветку в качестве новой базы для вашей работы.

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

Теперь в определенный момент вы хотите добавить новую функцию, которую вы реализовали в master ветке. Вы можете просто переключиться на master и объединить ветку с cool-feature:

$ git checkout master
$ git merge cool-feature

но таким образом добавляется новый фиктивный коммит, если вы хотите избежать истории спагетти, вы можете перебазировать:

$ git checkout cool-feature
$ git rebase master

а затем слить его в master:

$ git checkout master
$ git merge cool-feature

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

Ответ 3

Чтобы дополнить мой собственный ответ, упомянутый от TSamper,

  • репозиция довольно часто бывает хорошей идеей перед слиянием, потому что идея состоит в том, что вы интегрируете в свою ветвь Y работу ветки B, с которой вы будете сливаться.
    Но опять же, перед слиянием, вы разрешаете любой конфликт в своем филиале (т.е. "Rebase", как в "повторить мою работу в моей ветке, начиная с последней точки из ветки B)
    Если все сделано правильно, последующее слияние с вашей веткой на ветку B может быть перемоткой вперед.

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


точка слияния после переустановки?

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

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

Дерево Git по умолчанию, когда мы не слились и не пересозились

rebase1

мы получаем путем перезагрузки:

rebase3

Второй сценарий: о том, как вернуть новую функцию в мастер.

Моя точка зрения, описывая первый сценарий перезаписи, состоит в том, чтобы напомнить всем, что перебаза также может быть использована в качестве предварительного шага к этому (что означает "вернуть новую функцию в мастер" ). Вы можете использовать rebase, чтобы сначала перенести master-in в ветку новой функции: rebase будет переигрывать новую функцию, фиксируя ее с HEAD master, но все же в ветке новой функции, эффективно перемещая начальную точку вашего ветки со старого мастера зафиксировать HEAD-master.
Это позволяет разрешать любые конфликты в вашем филиале (что означает изолированно, позволяя мастеру продолжать развиваться параллельно, если уровень разрешения конфликта занимает слишком много времени).
Затем вы можете переключиться на master и слить new-feature (или rebase new-feature на master, если вы хотите сохранить фиксации, выполненные в ветки new-feature).

Итак:

  • "rebase vs. merge" можно рассматривать как два способа импорта работы, скажем, master.
  • Но "rebase then merge" может быть допустимым рабочим процессом, чтобы сначала разрешить конфликт изолированно, а затем вернуть вашу работу.

Ответ 4

TL; DR

Если у вас есть сомнения, используйте слияние.

Краткий ответ

Единственные различия между rebase и слиянием:

  • Полученная древовидная структура истории (как правило, только заметная при просмотре графика фиксации) отличается (у одного есть ветки, а другая - нет).
  • Слияние обычно создает дополнительную фиксацию (например, node в дереве).
  • Слияние и переустановка будут обрабатывать конфликты по-разному. Rebase будет представлять конфликты, которые совершаются в момент, когда слияние представит их все сразу.

Таким образом, короткий ответ заключается в выборе rebase или merge на основе того, что вы хотите, чтобы ваша история выглядела.

Длинный ответ

При выборе используемой операции необходимо учитывать несколько факторов.

Является ли филиалом, с которым вы получаете изменения, совместно с другими разработчиками вне вашей команды (например, с открытым исходным кодом, общедоступным)?

Если да, не переустанавливайте. Rebase уничтожает ветку, и у этих разработчиков будут сломанные/непоследовательные репозитории, если они не используют git pull --rebase. Это хороший способ быстро расстроить других разработчиков.

Насколько квалифицирована ваша команда разработчиков?

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

Я работал над командами, в которых разработчики все пришли с того времени, когда компании могли позволить себе преданный персонал заниматься разветвлением и слиянием. Эти разработчики мало знают о Git и не хотят много знать. В этих командах я бы не рискнул рекомендовать перезагрузку по любой причине.

Является ли сама ветка полезной информацией

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

Я также работал над командами, которые использовали модель для каждого разработчика (мы все были там). В этом случае сама ветвь не передает никакой дополнительной информации (у коммита уже есть автор). Не было бы вреда при перезагрузке.

Возможно, вы хотите вернуть слияние по какой-либо причине?

Возвращение (как в случае отмены) перебаза является значительно сложной и/или невозможной (если у rebase были конфликты) по сравнению с возвратом слияния. Если вы считаете, что есть шанс, что вы захотите вернуться, используйте слияние.

Вы работаете в команде? Если да, согласны ли вы принять все или ничего на эту ветку?

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

Общие мифы

Объединить историю уничтожения (squashes commits)

Предполагая, что у вас есть следующее слияние:

    B -- C
   /      \
  A--------D

Некоторые люди укажут, что слияние "уничтожает" историю фиксации, потому что если вы должны смотреть на журнал только основной ветки (A-D), вы пропустите важные сообщения о фиксации, содержащиеся в B и C.

Если бы это было так, у нас не было бы вопросов вроде этого. В принципе, вы увидите B и C, если вы явно не попросите их не видеть (используя - first-parent). Это очень легко попробовать для себя.

Rebase позволяет более безопасные/более простые слияния

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

Rebase более холодный/более сексуальный/более профессиональный

Если вам нравится псевдоним rm до rm -rf, чтобы "сэкономить время", возможно, вам потребуется переустановка.

Мои два цента

Я всегда думаю, что когда-нибудь я столкнусь с сценарием, где Git rebase - это потрясающий инструмент, который решает проблему. Как и мне кажется, я столкнулся с сценарием, где Git reflog - отличный инструмент, который решает мою проблему. Я работал с Git уже более пяти лет. Этого не произошло.

Бесполезные истории никогда не были проблемой для меня. Я никогда не читал историю совершения, как захватывающий роман. В большинстве случаев мне нужна история, я собираюсь использовать w20 > wame или Git bisect в любом случае. В этом случае наличие слияния действительно полезно для меня, потому что если слияние ввело проблему, которая имеет для меня значимую информацию.

Обновление (4/2017)

Я чувствую себя обязанным упомянуть, что я лично смягчился при использовании rebase, хотя мой общий совет все еще стоит. Недавно я много взаимодействовал с проектом Angular 2 Material. Они использовали rebase для сохранения очень чистой истории фиксации. Это позволило мне очень легко увидеть, что зафиксировал данный дефект, и включено ли это коммитирование в релиз. Он служит отличным примером правильного использования переадресации.

Ответ 5

Многие ответы здесь говорят о том, что слияние превращает все ваши коммиты в одно, и поэтому предлагает использовать rebase для сохранения ваших коммитов. Это неверно. И плохая идея, если вы уже сделали свои коммиты.

Слияние не уничтожает ваши фиксации. Слияние сохраняет историю! (просто посмотрите на gitk) Rebase перезаписывает историю, которая является Bad Thing после того, как вы ее нажали.

Использовать merge - not rebase, если вы уже нажали.

Вот Linus '(автор git) возьмет на себя. Это действительно хорошо читать. Или вы можете прочитать мою собственную версию той же идеи ниже.

Восстановление ветки на главном сервере:

  • содержит неверное представление о том, как были созданы коммиты.
  • загрязняет мастер с кучей промежуточных коммитов, которые, возможно, не были хорошо протестированы
  • может действительно вводить разрывы сборки для этих промежуточных коммитов из-за изменений, которые были сделаны, чтобы справиться между ними, когда была создана оригинальная ветка темы и когда она была переустановлена.
  • затрудняет поиск хороших мест в мастер-процедуре.
  • Заставляет метки времени на фиксации не совпадать с их хронологическим порядком в дереве. Таким образом, вы увидите, что commit A предшествует фиксации B в master, но commit B сначала был автором. (Что?!)
  • Создает больше конфликтов, потому что отдельные фиксации в ветке темы могут включать конфликты слияния, которые должны быть индивидуально разрешены (далее в истории рассказывается о том, что произошло в каждой транзакции).
  • - переписывание истории. Если ветка, подлежащая переустановке, была нажата куда-нибудь (поделилась с кем-либо, кроме вас самого), тогда вы повредили всех, кто имеет эту ветвь, с тех пор, как вы переписали историю.

Напротив, объединение ветки темы в master:

  • сохраняет историю того, где были созданы ветки тем, включая любые слияния от ведущего к ветке темы, чтобы поддерживать его актуальность. Вы действительно получаете точное представление о том, с каким кодом работал разработчик, когда они строили.
  • master - это ветвь, состоящая в основном из слияний, и каждая из этих коммитов слияния обычно является "хорошими моментами" в истории, которые безопасны для проверки, потому что там, где ветвь темы была готова к интеграции.
  • сохраняются все индивидуальные фиксации ветки темы, в том числе тот факт, что они были в ветке темы, поэтому выделение этих изменений является естественным, и вы можете развернуть его там, где это необходимо.
  • конфликты слияния должны быть разрешены только один раз (в точке слияния), поэтому промежуточные изменения фиксации, сделанные в ветки темы, не должны быть разрешены независимо.
  • можно сделать несколько раз гладко. Если вы интегрируете ветвь темы для периодического обучения, люди могут продолжать строить ветку темы, и она может продолжать быть объединенной независимо.

Ответ 6

Объединить средства: создать новый новый коммит, который объединяет мои изменения в пункт назначения.

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

Учитывая это, зачем вам переустанавливать? Просто чтобы история развития была ясна. Предположим, вы работаете над функцией X, и когда вы закончите, вы объедините свои изменения. Теперь у получателя будет одно коммит, который скажет что-то вроде строки "Добавлена ​​функция X". Теперь вместо слияния, если вы переустановили и затем объединили, история развития назначения будет содержать все отдельные коммиты в одной логической прогрессии. Это значительно облегчает анализ изменений. Представьте, как бы вы могли найти его, чтобы просмотреть историю развития, если 50 разработчиков все время объединяли различные функции.

Тем не менее, если вы уже нажали на ветку, над которой работаете, вы не должны пересобираться, а вместо этого сливаться. Для ветвей, которые не были выдвинуты вверх по течению, переустановите, протестируйте и слейте.

В другой раз, когда вы захотите переустановить, вы должны избавиться от коммитов из своей ветки, прежде чем нажать вверх. Например: Commits, которые вводят некоторый код отладки на ранней стадии, а другие фиксируют далее, что очищают этот код. Единственный способ сделать это - выполнить интерактивную перезагрузку: git rebase -i <branch/commit/tag>

UPDATE: вы также хотите использовать rebase при использовании Git для взаимодействия с системой управления версиями, которая не поддерживает нелинейную историю (например, подрывная операция). При использовании моста git -svn очень важно, чтобы изменения, которые вы объединили обратно в subversion, представляют собой последовательный список изменений поверх последних изменений в магистрали. Это можно сделать только двумя способами: (1) Вручную заново создать изменения и (2) Использовать команду rebase, которая выполняется намного быстрее.

UPDATE2: Еще один способ подумать о переадресации заключается в том, что он позволяет сопоставить вид вашего стиля разработки со стилем, принятым в репозитории, в который вы совершаете. Пусть говорят, что вы любите совершать в маленьких крошечных кусках. У вас есть одна фиксация, чтобы исправить опечатку, одну фиксацию, чтобы избавиться от неиспользуемого кода и так далее. Когда вы закончите то, что вам нужно сделать, у вас есть длинная серия коммитов. Теперь позвольте сказать, что репозиторий, который вы совершаете, поощряет большие коммиты, поэтому для работы, которую вы делаете, можно было бы ожидать одного или двух коммитов. Как вы берете свою строку коммитов и сжимаете их до ожидаемого? Вы бы использовали интерактивную переработку и сквош, чтобы ваши крошечные коммиты превращались в более маленькие куски. То же самое верно, если обратное было необходимо - если ваш стиль был несколькими крупными коммитами, но репо требовало длинные строки мелких коммитов. Для этого вы также будете использовать rebase. Если бы вы слились вместо этого, теперь вы перенесли свой стиль фиксации в основной репозиторий. Если есть много разработчиков, вы можете себе представить, как тяжело было бы следить за историей с несколькими разными стилями фиксации через некоторое время.

UPDATE3: Does one still need to merge after a successful rebase? Да, да. Причина в том, что перебаза по существу включает в себя "переключение" коммитов. Как я уже сказал выше, эти коммиты вычисляются, но если у вас было 14 коммитов от точки ветвления, то при условии, что с вашей перестановкой ничего не получится, вы будете на 14 коммитов вперед (с того момента, когда вы переустанавливаете) после rebase делается. У вас была ветка до переустановки. После этого у вас будет ветка одинаковой длины. Вам все равно нужно объединиться, прежде чем публиковать свои изменения. Другими словами, rebase столько раз, сколько вы хотите (опять же, только если вы не подтолкнули свои изменения вверх по течению). Объединяйте только после перезагрузки.

Ответ 7

перед слиянием /rebase:

A <- B <- C    [master]
^
 \
  D <- E       [branch]

после git merge master:

A <- B <- C
^         ^
 \         \
  D <- E <- F

после git rebase master:

A <- B <- C <- D' <- E'

(A, B, C, D, E и F являются коммитами)

этот пример и гораздо более хорошо иллюстрированная информация о git можно найти здесь: http://excess.org/article/2008/07/ogre-git-tutorial/

Ответ 8

Хотя слияние, безусловно, самый простой и наиболее распространенный способ интеграции изменений, это не единственный: Rebase - это альтернативный способ интеграции.

Понимание слияния немного лучше

Когда Git выполняет слияние, он ищет три фиксации:

  • (1) Общее обязательство предка. Если вы следуете истории двух ветвей в проекте, у них всегда есть как минимум одно совместное сообщение: на данный момент обе ветки имели одинаковый контент, а затем развивались по-разному.
  • (2) + (3) Конечные точки каждой ветки. Целью интеграции является объединение текущих состояний двух ветвей. Поэтому их соответствующие последние изменения представляют особый интерес. Объединение этих трех коммитов приведет к интеграции, к которой мы стремимся.

Быстрая перемотка или слияние

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

enter image description here

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

enter image description here

Однако во многих случаях обе ветки продвигались индивидуально. enter image description here

Чтобы выполнить интеграцию, Git должен будет создать новую фиксацию, содержащую различия между ними - объединение слиянием.

enter image description here

Человеческие коммиты и слияния

Как правило, фиксация тщательно создается человеком. Это значимая единица, которая обертывает только связанные изменения и комментирует их комментариями.

Согласование слияния немного отличается: вместо того, чтобы создавать разработчик, он автоматически создается Git. И вместо того, чтобы обернуть набор связанных изменений, его цель - соединить две ветки, точно так же, как узел. Если вы хотите понять операцию слияния позже, вам нужно взглянуть на историю обеих ветвей и соответствующий граф фиксации.

Интеграция с Rebase

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

enter image description here

Позвольте пройти шаг за шагом по операции переустановки. Сценарий такой же, как в предыдущих примерах: мы хотим интегрировать изменения из ветки-B в ветвь-A, но теперь с помощью rebase.

enter image description here

Мы сделаем это в три этапа

  1. git rebase branch-A//syncs the history with branch-A
  2. git checkout branch-A//change the current branch to branch-A
  3. git merge branch-B//merge/take the changes from branch-B to branch-A

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

enter image description here

Затем он применяет коммиты из ветки-B, которые мы хотим интегрировать. На данный момент обе ветки выглядят одинаково.

enter image description here

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

enter image description here

Наконец, вы получаете чистую ветку ветки A без каких-либо нежелательных и автоматически генерируемых коммитов.

Примечание: взято из удивительного поста git-tower. Недостатки rebase также хорошо читаются в том же сообщении.

Ответ 9

Это предложение получает:

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

Источник: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge

Ответ 10

Этот ответ широко ориентирован на Git Flow. Таблицы были созданы с помощью хорошего ASCII Table Generator, а деревья истории с этой замечательной командой (aliased как git lg):

git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'

Таблицы находятся в обратном хронологическом порядке, чтобы быть более согласованными с деревьями истории. См. Также разницу между git merge и git merge --no-ff в первую очередь (вы обычно хотите использовать git merge --no-ff, поскольку это приближает вашу историю к реальности):

git merge

Команды

Time          Branch "develop"             Branch "features/foo"
------- ------------------------------ -------------------------------
15:04   git merge features/foo
15:03                                  git commit -m "Third commit"
15:02                                  git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Результат:

* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
|           Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
|           Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge --no-ff

Команды

Time           Branch "develop"              Branch "features/foo"
------- -------------------------------- -------------------------------
15:04   git merge --no-ff features/foo
15:03                                    git commit -m "Third commit"
15:02                                    git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Результат:

*   1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/            Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge vs git rebase

Первая точка: всегда объединяет функции в разработку, никогда не перестраивается из функций. Это является следствием Golden Rule of Rebasing:

Золотое правило git rebase заключается в том, чтобы никогда не использовать его в публичных ветвях.

Другими словами:

Никогда не перепутайте все, что вы где-то нажали.

Я лично добавлю: если это не ветка с функциями, и вы и ваша команда узнаете о последствиях.

Таким образом, вопрос о git merge vs git rebase применяется почти только к ветвям признаков (в следующих примерах --no-ff всегда использовался при слиянии). Обратите внимание, что, поскольку я не уверен, что есть одно лучшее решение (существует дискуссия), я расскажу только, как ведут себя обе команды. В моем случае я предпочитаю использовать git rebase, поскольку он создает более приятное дерево истории:)

Между ветвями функций

git merge

Команды

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Результат:

*   c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\            Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | |           Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | |           Fourth commit - Christophe
* | |   98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \            Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Команды

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git rebase features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Результат:

*   7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

От develop до ветки функции

git merge

Команды

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git merge --no-ff development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Результат:

*   9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\            Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* |   5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | |           Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ /            Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Команды

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git rebase development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Результат:

*   b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
*   856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\            Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

Боковые заметки

git cherry-pick

Если вам нужна только одна конкретная фиксация, git cherry-pick - это приятное решение (опция -x добавляет строку, в которой говорится: "(вишня выбрана из фиксации...)" в исходное тело сообщения коммита, так что обычно хорошая идея использовать его - git log <commit_sha1>, чтобы увидеть его):

Команды

Time           Branch "develop"              Branch "features/foo"                Branch "features/bar"           
------- -------------------------------- ------------------------------- -----------------------------------------
15:10   git merge --no-ff features/bar                                                                            
15:09   git merge --no-ff features/foo                                                                            
15:08                                                                    git commit -m "Sixth commit"             
15:07                                                                    git cherry-pick -x <second_commit_sha1>  
15:06                                                                    git commit -m "Fifth commit"             
15:05                                                                    git commit -m "Fourth commit"            
15:04                                    git commit -m "Third commit"                                             
15:03                                    git commit -m "Second commit"                                            
15:02   git checkout -b features/bar                                                                              
15:01   git checkout -b features/foo                                                                              
15:00   git commit -m "First commit"                                                                              

Результат:

*   50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| |           Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git pull --rebase

Не уверен, что я могу объяснить это лучше, чем Дерек Гурлей... В принципе, используйте git pull --rebase вместо git pull:) Что пропало в статье, однако, что вы можете включить его по умолчанию:

git config --global pull.rebase true

git rerere

Снова, приятно объяснил здесь. Но поставите просто, если вы включите его, вам больше не придется разрешать один и тот же конфликт.

Ответ 11

Книга pro git как действительно хорошее объяснение на странице .

В основном слияние будет принимать 2 коммита и объединить их.

Перестановка будет идти к общему предку на 2 и постепенно применять изменения друг к другу. Это создает "более чистую" и более линейную историю.

Но когда вы переустанавливаете, вы отказываетесь от предыдущих коммитов и создаете новые. Поэтому вы никогда не должны переустанавливать репо, которое является публичным. Другие люди, работающие над репо, будут вас ненавидеть.

По этой причине я почти исключительно сливаюсь. В 99% случаев мои ветки не отличаются друг от друга, поэтому, если есть конфликты, это только в одном или двух местах.

Ответ 12

Git rebase используется, чтобы сделать ветвящиеся пути в структуре истории и структуры хранилища линейными.

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

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

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

Ответ 13

Некоторые практические примеры, несколько связанные с крупномасштабным развитием, где герит используется для проверки и интеграции доставки.

Я объединяюсь, когда я поднимаю ветвь своей функции на новый удаленный мастер. Это дает минимальную работу по поднятию и легко отслеживает историю разработки функции, например, gitk.

git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature

Я сжимаюсь, когда готовлю фиксацию доставки.

git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master

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

git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master

Ответ 14

Много раз объяснялось, что такое ребазинг и что такое слияние, но когда и что использовать?

Когда использовать rebase?

  • когда вы не нажали на ветку/над ней больше никто не работает
  • Вы хотите полную историю
  • Вы хотите избежать всех автоматически генерируемых сообщений о слиянии

Как git rebase меняет историю. Поэтому вы не должны использовать его, когда кто-то еще работает над той же веткой/если вы нажали ее. Но если у вас есть локальная ветвь, вы можете выполнить мастер слияния ребаз перед слиянием своей ветки с главной, чтобы сохранить более чистую историю. Делая это, после слияния с основной ветвью не будет видно, что вы использовали ветку в основной ветке - история "чище", поскольку у вас нет автоматически сгенерированной "слитой", но все еще есть полная история в вашей главной ветке без автоматической генерации коммитов "merged..". Тем не менее, убедитесь, что вы используете git merge feature-branch --ff-only, чтобы избежать конфликтов при создании одного коммита при слиянии вашей функции с основной. Это интересно, если вы используете ветки функций для каждой задачи, над которой работаете, так как вы получаете историю ветки функций, а не коммит "объединенный.."

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

Когда использовать слияние?

  • когда вы нажали на ветку/другие тоже работают над этим
  • вам не нужна полная история
  • для вас достаточно простого слияния

Когда вам не нужно или вы хотите иметь всю историю ветки функций в вашей основной ветке или если другие работают в той же ветке/вы добавили ее. Если вы все еще хотите иметь историю, просто объедините мастер с ветвью объектов, прежде чем объединять ветвь объектов с мастером. Это приведет к ускоренному слиянию, при котором у вас будет история ветки объектов в вашем мастере (включая коммит слияния, который был в вашей ветки функций, потому что вы слили мастер в него).

Ответ 15

Давайте посмотрим на пример. Работая над веткой с именем login, основанной на ветке master, один из членов вашей команды внес некоторые изменения в master. Эти изменения необходимы для завершения функции login в вашей ветки.

enter image description here Рисунок 1. Новые коммиты в ветке master (E и F) необходимы для завершения работы в ветке login.

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

enter image description here Рисунок 2. Слияние двух ветвей приводит к фиксации слияния.

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

Команда Gits rebase временно перематывает коммиты в вашей текущей ветке, извлекает коммиты из другой ветки и снова применяет переизданные коммиты сверху. Путем переключения тока Это основывает текущую ветвь на другую ветвь.

enter image description here

Рисунок 3. Перебазирование применяет коммиты из ветки login поверх ветки master.

Источник здесь

Ответ 16

Когда я использую git rebase? Почти никогда, потому что он переписывает историю. git merge - почти всегда предпочтительный выбор, потому что он уважает то, что на самом деле произошло в вашем проекте.