Когда рекомендуется использовать git rebase
vs. git merge
?
Нужно ли мне снова объединиться после успешной перезагрузки?
Когда рекомендуется использовать git rebase
vs. git merge
?
Нужно ли мне снова объединиться после успешной перезагрузки?
Итак, когда вы используете один из них?
Это просто, с 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 и коммиты с новой функцией, слияние будет просто ускоренной перемоткой вперед.
Чтобы дополнить мой собственный ответ, упомянутый от TSamper,
репозиция довольно часто бывает хорошей идеей перед слиянием, потому что идея состоит в том, что вы интегрируете в свою ветвь Y
работу ветки B
, с которой вы будете сливаться.
Но опять же, перед слиянием, вы разрешаете любой конфликт в своем филиале (т.е. "Rebase", как в "повторить мою работу в моей ветке, начиная с последней точки из ветки B
)
Если все сделано правильно, последующее слияние с вашей веткой на ветку B
может быть перемоткой вперед.
влияние слияния непосредственно на ветвь назначения B
, что означает, что слияние будет более тривиальным, иначе ветка B
может быть длинной, чтобы вернуться в стабильное состояние (время, когда вы разрешаете все конфликты)
точка слияния после переустановки?
В том случае, когда я описываю, я переустанавливаю B
на свою ветку, чтобы иметь возможность воспроизвести мою работу из более поздней точки из B
, но оставаясь в моей ветке.
В этом случае слияние все еще необходимо, чтобы моя "переигравшая" работа на B
.
Другой сценарий (описанный в Git Ready, например), должен привести вашу работу непосредственно в B
через rebase ( который сохраняет все ваши хорошие коммиты или даже дает вам возможность переупорядочить их через интерактивную переадресацию).
В этом случае (где вы переустанавливаете, находясь в ветки B) вы правы: никакого дальнейшего слияния не требуется:
Дерево Git по умолчанию, когда мы не слились и не пересозились
мы получаем путем перезагрузки:
Второй сценарий: о том, как вернуть новую функцию в мастер.
Моя точка зрения, описывая первый сценарий перезаписи, состоит в том, чтобы напомнить всем, что перебаза также может быть использована в качестве предварительного шага к этому (что означает "вернуть новую функцию в мастер" ).
Вы можете использовать rebase, чтобы сначала перенести master-in в ветку новой функции: rebase будет переигрывать новую функцию, фиксируя ее с HEAD master
, но все же в ветке новой функции, эффективно перемещая начальную точку вашего ветки со старого мастера зафиксировать HEAD-master
.
Это позволяет разрешать любые конфликты в вашем филиале (что означает изолированно, позволяя мастеру продолжать развиваться параллельно, если уровень разрешения конфликта занимает слишком много времени).
Затем вы можете переключиться на master и слить new-feature
(или rebase new-feature
на master
, если вы хотите сохранить фиксации, выполненные в ветки new-feature
).
Итак:
master
.Если у вас есть сомнения, используйте слияние.
Единственные различия между rebase и слиянием:
Таким образом, короткий ответ заключается в выборе rebase или merge на основе того, что вы хотите, чтобы ваша история выглядела.
При выборе используемой операции необходимо учитывать несколько факторов.
Если да, не переустанавливайте. Rebase уничтожает ветку, и у этих разработчиков будут сломанные/непоследовательные репозитории, если они не используют git pull --rebase
. Это хороший способ быстро расстроить других разработчиков.
Rebase - это деструктивная операция. Это означает, что если вы не применяете его правильно, , вы можете потерять совершенную работу и/или нарушить согласованность других репозиториев разработчиков.
Я работал над командами, в которых разработчики все пришли с того времени, когда компании могли позволить себе преданный персонал заниматься разветвлением и слиянием. Эти разработчики мало знают о Git и не хотят много знать. В этих командах я бы не рискнул рекомендовать перезагрузку по любой причине.
В некоторых командах используется модель для каждой ветки, где каждая ветвь представляет собой функцию (или исправление, или вспомогательную функцию и т.д.). В этой модели ветвь помогает идентифицировать совокупности связанных коммитов. Например, можно быстро вернуть функцию, возвращая слияние этой ветки (справедливости ради, это редкая операция). Или сравните функцию, сравнив две ветки (более общие). Rebase уничтожил бы ветку, и это было бы непросто.
Я также работал над командами, которые использовали модель для каждого разработчика (мы все были там). В этом случае сама ветвь не передает никакой дополнительной информации (у коммита уже есть автор). Не было бы вреда при перезагрузке.
Возвращение (как в случае отмены) перебаза является значительно сложной и/или невозможной (если у rebase были конфликты) по сравнению с возвратом слияния. Если вы считаете, что есть шанс, что вы захотите вернуться, используйте слияние.
Операции перезагрузки необходимо потянуть с помощью соответствующего git pull --rebase
. Если вы работаете самостоятельно, вы можете вспомнить, что вы должны использовать в соответствующее время. Если вы работаете в команде, это будет очень сложно согласовать. Вот почему большинство рабочих процессов rebate рекомендуют использовать rebase для всех слияний (и git pull --rebase
для всех нажатий).
Предполагая, что у вас есть следующее слияние:
B -- C
/ \
A--------D
Некоторые люди укажут, что слияние "уничтожает" историю фиксации, потому что если вы должны смотреть на журнал только основной ветки (A-D), вы пропустите важные сообщения о фиксации, содержащиеся в B и C.
Если бы это было так, у нас не было бы вопросов вроде этого. В принципе, вы увидите B и C, если вы явно не попросите их не видеть (используя - first-parent). Это очень легко попробовать для себя.
Оба подхода сливаются по-разному, но неясно, что он всегда лучше другого, и он может зависеть от рабочего процесса разработчика. Например, если разработчик имеет тенденцию совершать регулярные (например, они могут совершать два раза в день при переходе с работы на дом), тогда может быть много коммитов для данной ветки. Многие из этих коммитов могут выглядеть не так, как конечный продукт (я имею тенденцию реорганизовывать мой подход один или два раза за функцию). Если кто-то другой работал над связанной областью кода, и они пытались изменить мои изменения, это может быть довольно утомительной операцией.
Если вам нравится псевдоним rm
до rm -rf
, чтобы "сэкономить время", возможно, вам потребуется переустановка.
Я всегда думаю, что когда-нибудь я столкнусь с сценарием, где Git rebase - это потрясающий инструмент, который решает проблему. Как и мне кажется, я столкнулся с сценарием, где Git reflog - отличный инструмент, который решает мою проблему. Я работал с Git уже более пяти лет. Этого не произошло.
Бесполезные истории никогда не были проблемой для меня. Я никогда не читал историю совершения, как захватывающий роман. В большинстве случаев мне нужна история, я собираюсь использовать w20 > wame или Git bisect в любом случае. В этом случае наличие слияния действительно полезно для меня, потому что если слияние ввело проблему, которая имеет для меня значимую информацию.
Я чувствую себя обязанным упомянуть, что я лично смягчился при использовании rebase, хотя мой общий совет все еще стоит. Недавно я много взаимодействовал с проектом Angular 2 Material. Они использовали rebase для сохранения очень чистой истории фиксации. Это позволило мне очень легко увидеть, что зафиксировал данный дефект, и включено ли это коммитирование в релиз. Он служит отличным примером правильного использования переадресации.
Многие ответы здесь говорят о том, что слияние превращает все ваши коммиты в одно, и поэтому предлагает использовать rebase для сохранения ваших коммитов. Это неверно. И плохая идея, если вы уже сделали свои коммиты.
Слияние не уничтожает ваши фиксации. Слияние сохраняет историю! (просто посмотрите на gitk) Rebase перезаписывает историю, которая является Bad Thing после того, как вы ее нажали.
Использовать merge - not rebase, если вы уже нажали.
Вот Linus '(автор git) возьмет на себя. Это действительно хорошо читать. Или вы можете прочитать мою собственную версию той же идеи ниже.
Восстановление ветки на главном сервере:
Напротив, объединение ветки темы в master:
Объединить средства: создать новый новый коммит, который объединяет мои изменения в пункт назначения.
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 столько раз, сколько вы хотите (опять же, только если вы не подтолкнули свои изменения вверх по течению). Объединяйте только после перезагрузки.
перед слиянием /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/
Хотя слияние, безусловно, самый простой и наиболее распространенный способ интеграции изменений, это не единственный: Rebase - это альтернативный способ интеграции.
Понимание слияния немного лучше
Когда Git выполняет слияние, он ищет три фиксации:
Быстрая перемотка или слияние
В очень простых случаях одна из двух ветвей не имеет никаких новых коммитов, так как произошло ветвление - ее последняя фиксация по-прежнему является общим предком.
В этом случае выполнение интеграции просты: Git может просто добавить все коммиты другой ветки поверх общей фиксации предка. В Git эта простейшая форма интеграции называется "быстрым" слиянием. Обе ветки тогда разделяют ту же самую историю.
Однако во многих случаях обе ветки продвигались индивидуально.
Чтобы выполнить интеграцию, Git должен будет создать новую фиксацию, содержащую различия между ними - объединение слиянием.
Человеческие коммиты и слияния
Как правило, фиксация тщательно создается человеком. Это значимая единица, которая обертывает только связанные изменения и комментирует их комментариями.
Согласование слияния немного отличается: вместо того, чтобы создавать разработчик, он автоматически создается Git. И вместо того, чтобы обернуть набор связанных изменений, его цель - соединить две ветки, точно так же, как узел. Если вы хотите понять операцию слияния позже, вам нужно взглянуть на историю обеих ветвей и соответствующий граф фиксации.
Интеграция с Rebase
Некоторые люди предпочитают идти без таких автоматических слияний. Вместо этого они хотят, чтобы история проекта выглядела так, как будто она развивалась по одной прямой. Пока нет признаков того, что в какой-то момент он был разбит на несколько ветвей.
Позвольте пройти шаг за шагом по операции переустановки. Сценарий такой же, как в предыдущих примерах: мы хотим интегрировать изменения из ветки-B в ветвь-A, но теперь с помощью rebase.
Мы сделаем это в три этапа
git rebase branch-A//syncs the history with branch-A
git checkout branch-A//change the current branch to branch-A
git merge branch-B//merge/take the changes from branch-B to branch-A
Во-первых, Git "отменит" все фиксации на ветке-A, которая произошла после того, как линии начали разветвляться (после того, как общий предок совершил). Однако, конечно, он не отбросит их: вместо этого вы можете думать о том, что эти коммиты "временно сберегаются".
Затем он применяет коммиты из ветки-B, которые мы хотим интегрировать. На данный момент обе ветки выглядят одинаково.
На последнем этапе новые коммиты на ветке-A теперь снова применяются, но в новой позиции поверх интегрированных коммитов из ветки-B (они основаны на повторной основе). Результат выглядит так, как будто развитие произошло по прямой. Вместо слияния, содержащего все комбинированные изменения, исходная структура фиксации была сохранена.
Наконец, вы получаете чистую ветку ветки A без каких-либо нежелательных и автоматически генерируемых коммитов.
Примечание: взято из удивительного поста git-tower
. Недостатки rebase
также хорошо читаются в том же сообщении.
Это предложение получает:
В общем, способ получить лучшее из обоих миров состоит в том, чтобы изменения вы сделали, но havent shared еще, пока вы не нажмете их чтобы очистить вашу историю, но никогда не перезаряжайте все, что вы толкнули где-то.
Источник: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge
Этот ответ широко ориентирован на 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
Снова, приятно объяснил здесь. Но поставите просто, если вы включите его, вам больше не придется разрешать один и тот же конфликт.
Книга pro git как действительно хорошее объяснение на странице .
В основном слияние будет принимать 2 коммита и объединить их.
Перестановка будет идти к общему предку на 2 и постепенно применять изменения друг к другу. Это создает "более чистую" и более линейную историю.
Но когда вы переустанавливаете, вы отказываетесь от предыдущих коммитов и создаете новые. Поэтому вы никогда не должны переустанавливать репо, которое является публичным. Другие люди, работающие над репо, будут вас ненавидеть.
По этой причине я почти исключительно сливаюсь. В 99% случаев мои ветки не отличаются друг от друга, поэтому, если есть конфликты, это только в одном или двух местах.
Git rebase используется, чтобы сделать ветвящиеся пути в структуре истории и структуры хранилища линейными.
Он также используется для сохранения ветвей, созданных вами лично, так как после перезагрузки и нажатия изменений на сервере, если вы удаляете свою ветку, не будет никаких доказательств отрасли, над которой вы работали. Итак, ваш филиал теперь является вашей местной проблемой.
После выполнения rebase мы также избавимся от дополнительной фиксации, которую мы использовали, чтобы увидеть, выполняем ли мы обычное слияние.
И да, все еще нужно объединить после успешной перезагрузки, так как команда rebase просто помещает вашу работу поверх ветки, о которой вы упомянули во время rebase say master, и делает первую фиксацию вашей ветки прямым потоком ведущей ветки. Это означает, что теперь мы можем выполнить быстрое слияние вперед, чтобы внести изменения из этой ветки в ведущую ветвь.
Некоторые практические примеры, несколько связанные с крупномасштабным развитием, где герит используется для проверки и интеграции доставки.
Я объединяюсь, когда я поднимаю ветвь своей функции на новый удаленный мастер. Это дает минимальную работу по поднятию и легко отслеживает историю разработки функции, например, 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
Много раз объяснялось, что такое ребазинг и что такое слияние, но когда и что использовать?
Когда использовать rebase?
Как git rebase меняет историю. Поэтому вы не должны использовать его, когда кто-то еще работает над той же веткой/если вы нажали ее. Но если у вас есть локальная ветвь, вы можете выполнить мастер слияния ребаз перед слиянием своей ветки с главной, чтобы сохранить более чистую историю. Делая это, после слияния с основной ветвью не будет видно, что вы использовали ветку в основной ветке - история "чище", поскольку у вас нет автоматически сгенерированной "слитой", но все еще есть полная история в вашей главной ветке без автоматической генерации коммитов "merged..". Тем не менее, убедитесь, что вы используете git merge feature-branch --ff-only
, чтобы избежать конфликтов при создании одного коммита при слиянии вашей функции с основной. Это интересно, если вы используете ветки функций для каждой задачи, над которой работаете, так как вы получаете историю ветки функций, а не коммит "объединенный.."
Второй сценарий будет, если вы разветвляетесь из ветки и хотите знать, что изменилось в основной ветке. rebase дает вам информацию, поскольку она включает в себя каждый коммит.
Когда использовать слияние?
Когда вам не нужно или вы хотите иметь всю историю ветки функций в вашей основной ветке или если другие работают в той же ветке/вы добавили ее. Если вы все еще хотите иметь историю, просто объедините мастер с ветвью объектов, прежде чем объединять ветвь объектов с мастером. Это приведет к ускоренному слиянию, при котором у вас будет история ветки объектов в вашем мастере (включая коммит слияния, который был в вашей ветки функций, потому что вы слили мастер в него).
Давайте посмотрим на пример. Работая над веткой с именем login
, основанной на ветке master
, один из членов вашей команды внес некоторые изменения в master
. Эти изменения необходимы для завершения функции login
в вашей ветки.
Рисунок 1. Новые коммиты в ветке master
(E и F) необходимы для завершения работы в ветке login
.
Слияние ветки master
с вашей версией приведет к фиксации слияния, которая включает изменения между обеими ветвями и существует, чтобы показать, где произошло слияние.
Рисунок 2. Слияние двух ветвей приводит к фиксации слияния.
Нам не нужно знать, когда мы в будущем объединим master
с веткой login
. Вместо этого мы хотели бы сделать вид, что все фиксации в ветки login
произошли на основе нового состояния ветки master
.
Команда Gits rebase временно перематывает коммиты в вашей текущей ветке, извлекает коммиты из другой ветки и снова применяет переизданные коммиты сверху. Путем переключения тока Это основывает текущую ветвь на другую ветвь.
Рисунок 3. Перебазирование применяет коммиты из ветки login
поверх ветки master
.
Источник здесь
Когда я использую git rebase
? Почти никогда, потому что он переписывает историю. git merge
- почти всегда предпочтительный выбор, потому что он уважает то, что на самом деле произошло в вашем проекте.