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

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

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

1265
задан Coocoo4Cocoa 29 апр. '09 в 23:26
источник поделиться
14 ответов

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

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

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

Объединить

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

Rebase

  • Второй сценарий был бы, если бы вы начали делать некоторую разработку, а затем другой разработчик сделал несвязанное изменение. Вероятно, вы захотите вытащить, а затем rebase, чтобы основывать свои изменения на текущей версии из репо.
977
ответ дан Rob Di Marco 29 апр. '09 в 23:38
источник поделиться

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

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

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

$git checkout master
$git merge cool-feature

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

$git checkout cool-feature
$git rebase master

а затем объединить его в master:

$git checkout master
$git merge cool-feature

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

295
ответ дан Aldo 'xoen' Giambelluca 05 февр. '12 в 9:28
источник поделиться

Чтобы дополнить мой собственный ответ, упомянутый от 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" может быть допустимым рабочим процессом, чтобы сначала разрешить конфликт изолированно, а затем вернуть вашу работу.
254
ответ дан VonC 29 апр. '09 в 23:44
источник поделиться

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

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

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

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

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

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

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

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

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 для сохранения очень чистой истории фиксации. Это позволило мне очень легко увидеть, что зафиксировал данный дефект, и включено ли это коммитирование в релиз. Он служит отличным примером правильного использования переадресации.

121
ответ дан Pace 13 апр. '16 в 5:16
источник поделиться

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

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 столько раз, сколько вы хотите (опять же, только если вы не подтолкнули свои изменения вверх по течению). Объединяйте только после перезагрузки.

65
ответ дан Carl 05 февр. '12 в 9:47
источник поделиться

перед слиянием /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/

55
ответ дан guybrush 07 июня '12 в 9:19
источник поделиться

Хотя слияние, безусловно, самый простой и наиболее распространенный способ интеграции изменений, это не единственный: 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 также хорошо читаются в том же сообщении.

25
ответ дан Abdullah Khan 12 окт. '17 в 14:52
источник поделиться

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

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

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

25
ответ дан Joaquin Sargiotto 05 янв. '15 в 16:50
источник поделиться

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

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

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

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

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

15
ответ дан xero 21 дек. '12 в 0:41
источник поделиться

Этот ответ широко ориентирован на 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

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

14
ответ дан sp00m 10 февр. '17 в 20:26
источник поделиться

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

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

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

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

4
ответ дан cvibha 24 сент. '13 в 9:11
источник поделиться

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

Я объединяюсь, когда я поднимаю ветвь своей функции на новый удаленный мастер. Это дает минимальную работу по поднятию и легко отслеживает историю разработки функции, например, 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
2
ответ дан Martin G 23 февр. '16 в 9:13
источник поделиться

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

-7
ответ дан Marnen Laibow-Koser 20 янв. '18 в 0:01
источник поделиться

Другие вопросы по меткам или Задайте вопрос