что это означает, что git rebase перезаписывает историю? [Дубликат]

Новые кодеры иногда пишут такой код:

my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...

Затем кодер остается с кучей именованных переменных с усилием кодирования O ( m * n ), где m - это число именованных переменных, а n - это количество раз, к которому необходимо получить доступ к группе переменных (включая создание) , Более проницательный новичок отмечает, что единственная разница в каждой из этих строк - это число, которое изменяется на основе правила и решает использовать цикл. Тем не менее, они зациклились на том, как динамически создавать эти имена переменных, и могут попробовать что-то вроде этого:

for i in range(10):
    my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)

Вскоре они обнаруживают, что это не сработает.

Если программа требует произвольных переменных «имена», лучше всего подходит словарь, как объясняется в других ответах. Однако, если вы просто пытаетесь создать много переменных, и вы не возражаете ссылаться на них с последовательностью целых чисел, вы, вероятно, ищете list. Это особенно верно, если ваши данные однородны, например, ежедневные показания температуры, еженедельные оценки викторины или сетка графических виджета.

Это можно собрать следующим образом:

my_calculator.buttons = []
for i in range(10):
    my_calculator.buttons.append(tkinter.Button(root, text=i))

Этот list также может быть создан в одной строке с пониманием:

my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]

Результат в любом случае - это заполненный list, с первым элементом, к которому обращаются с помощью my_calculator.buttons[0], следующего с my_calculator.buttons[1] и т. д. Имя переменной «base» становится именем list, и для доступа к нему используется различный идентификатор.

Наконец, не забудьте другие структуры данных, такие как set - это аналогично словарю, за исключением того, что каждое «имя» не имеет привязанного к нему значения. Если вам просто нужна «сумка» объектов, это может быть отличным выбором. Вместо этого:

keyword_1 = 'apple'
keyword_2 = 'banana'

if query == keyword_1 or query == keyword_2:
    print('Match.')

У вас будет следующее:

keywords = {'apple', 'banana'}
if query in keywords:
    print('Match.')

Используйте последовательность list для последовательности похожих объектов, a set для произвольного - помещенный пакет предметов или dict для мешка с именами со связанными значениями.

1284
задан Nick Volynkin 24 June 2015 в 04:24
поделиться

14 ответов

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

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

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

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

Fast-Forward или Merge Commit

В очень простых случаях одна из двух ветвей не работает [new]

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

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

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

Человеческие комманды & amp; Merge Commits

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

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

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

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

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

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

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

Затем, он применяет фиксации от ветви-B, которую мы хотим интегрировать. На этом этапе обе ветви выглядят одинаково.

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

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

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

24
ответ дан Abdullah Khan 22 August 2018 в 02:03
поделиться

Это просто, с 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

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

293
ответ дан Aldo 'xoen' Giambelluca 22 August 2018 в 02:03
поделиться
  • 1
    but this way a new dummy commit is added, if you want to avoid spaghetti-history - Как это плохо? – アレックス 19 May 2014 в 15:07
  • 2
    Кроме того, флаг -no-ff слияния очень полезен. – Aldo 'xoen' Giambelluca 22 May 2014 в 13:39
  • 3
    @ ア レ ッ ク ス, как пользователь Sean Schofield помещает его в комментарий: «Rebase также хорош, потому что, как только u в конечном итоге объединит ур материал обратно в master (что тривиально, как уже описано), у вас есть сидение в верхней части страницы. истории фиксации ур. В более крупных проектах, где функции могут быть записаны, но объединены через несколько недель, вы не хотите просто объединять их в мастер, потому что они получают "stuffed & quot; в мастер путь назад в истории. Лично мне нравится иметь возможность делать git log и видеть, что недавняя функция прямо на вершине. Обратите внимание, что даты фиксации сохраняются - rebase не изменяет эту информацию. & Quot; – Adrien Be 1 March 2016 в 05:37
  • 4
    Я думаю, что здесь повторяется - помните, что все эти термины (merge, rebase, fast-forward и т. Д.) Относятся к конкретным манипуляциям направленного ациклического графа. Им становится легче рассуждать с учетом этой ментальной модели. – Roy Tinker 27 January 2017 в 20:24
  • 5
    @Aldo Нет ничего «чистого». или "аккуратный" о предыстории. Обычно это filthy , и ИМХО ужасно, потому что ты понятия не имеешь, что действительно продолжалось. "Самый чистый" История Git - это та, которая на самом деле произошла. :) – Marnen Laibow-Koser 14 May 2018 в 13:58

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

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

Использовать слияние - не переустанавливать всякий раз, когда вы уже нажали.

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

Снятие ветви на master:

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

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

  • сохраняет историю того, где были созданы ветви тем, включая любые слияния от мастера к ветке темы, помогите сохранить его в актуальном состоянии. Вы действительно получаете точное представление о том, с каким кодом работал разработчик, когда они строились.
  • master - это ветвь, состоящая в основном из слияний, и каждая из этих коммитов слияния обычно является «хорошими моментами» в истории которые безопасны для проверки, потому что именно там было готово интегрироваться ветвь темы.
  • сохраняются все отдельные фиксации ветви темы, в том числе тот факт, что они были в ветке темы, поэтому выделение этих изменения являются естественными, и вы можете сверлить их там, где это необходимо.
  • конфликты слияния должны быть разрешены только один раз (в точке слияния), поэтому промежуточные изменения фиксации, сделанные в ветке темы, не должны быть разрешены независимо.
  • можно выполнять несколько раз плавно. Если вы периодически интегрируете ветвь темы в мастер, люди могут продолжать строить ветку темы, и она может продолжать быть объединенной независимо.
153
ответ дан Andrew Arnott 22 August 2018 в 02:03
поделиться
  • 1
    Кроме того, git merge имеет значение «- no-ff». (без быстрой перемотки вперед), что позволяет очень легко отменить все изменения, внесенные определенным слиянием. – Tiago 8 September 2014 в 23:07
  • 2
    Просто сделайте это более понятным: вы ссылаетесь на ситуацию «всякий раз, когда вы уже толкнули» - это должно быть смелым. Ссылка на сообщение Linus отличная, кстати, уточняет. – honzajde 14 February 2015 в 15:40
  • 3
    – ProblemsOfSumit 7 January 2016 в 12:40
  • 4
    @AndrewArnott & quot; Большинство ветвей темы должны иметь возможность сливаться без конфликтов в свои целевые ветви & quot; Как это возможно, когда 20 разработчиков работают на 30 филиалов? Там будут слияния, пока вы работаете над своим - так что, конечно, вам нужно обновить ветку темы от цели, прежде чем создавать PR ... нет? – ProblemsOfSumit 11 January 2016 в 09:21
  • 5
    Не обычно, @Sumit. Git может объединить любое направление, даже если изменения были внесены в одну или обе ветви. Только когда одни и те же строки кода (или очень близкие) будут изменены по двум ветвям, вы получите конфликты. Если это часто случается в любой команде, команде следует переосмыслить, как они распределяют работу, поскольку разрешение конфликтов является налогом и замедляет их. – Andrew Arnott 15 January 2016 в 14:29
  • 6
    Ссылка мертва, пожалуйста, обновите – Warpzit 7 February 2017 в 16:28

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

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

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

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

В другой раз, когда вы захотите переустановить, вы должны избавиться от коммитов из своей ветки, прежде чем нажать вверх. Например: Commits, которые вводят некоторый код отладки на ранней стадии, а другие фиксируют далее, что очищают этот код. Единственный способ сделать это - выполнить интерактивную rebase: 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 22 August 2018 в 02:03
поделиться
  • 1
    Слияние с мастером может привести к быстрой перемотке вперед. В ветви признака могут быть некоторые коммиты, которые имеют незначительные ошибки или даже не компилируются. Если вы выполняете только модульное тестирование в ветви функции, некоторые ошибки в интеграции меня скользят. Перед слиянием с мастером необходимы интеграционные тесты и могут отображать некоторые ошибки. Если они исправлены, функция может быть интегрирована. Поскольку вы не хотите совершать багги-код для мастеринга, необходима перебаза, необходимая для того, чтобы предотвратить все-коммиты-быструю перемотку вперед. – mbx 15 July 2012 в 19:15
  • 2
    @mbx git merge поддерживает параметр --no-ff, который заставляет его совершать слияние. – g.rocket 8 June 2017 в 22:31
254
ответ дан Community 22 August 2018 в 02:03
поделиться

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

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

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

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

4
ответ дан cvibha 22 August 2018 в 02:03
поделиться

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

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

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

Merge

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

Rebase

  • Второй сценарий был бы, если бы вы начали делать некоторую разработку, а затем другой разработчик сделал несвязанное изменение. Вероятно, вы захотите вытащить, а затем переустановить, чтобы основывать свои изменения на текущей версии из репо.
976
ответ дан Dennis 22 August 2018 в 02:03
поделиться
  • 1
    @Rob упомянул о поддержании промежуточных обязательств при слиянии. Я полагаю, что по умолчанию объединение ветви B (ветви функции, над которой вы работали) в ветвь M (главная ветвь) будет создавать одну фиксацию в M для каждой фиксации, которая была сделана в B, так как два расходились. Но если вы объединитесь с помощью опции -squash, все коммиты, сделанные на ветке B, будут «объединены вместе» и, и объединены как единый фиксатор на ветке M, сохраняя журнал на вашей мастер-ветке приятным и чистым. Скриптинг - это, вероятно, то, что вы хотите, если у вас есть многочисленные разработчики, работающие независимо и слияния с мастером. – spaaarky21 24 January 2013 в 23:46
  • 2
    Я считаю, что предположение о слиянии spaaarky21 неверно. Если вы объедините ветвь B в мастер M, на M будет только одна фиксация (даже если B имеет несколько коммитов), независимо от того, используете ли вы простой или -squash-слияние. Что -squash будет делать, это исключить ссылку на B как родителя. Хорошая визуализация здесь: syntevo.com/smartgithg/howtos.html?page=workflows.merge – jpeskin 26 May 2013 в 16:19
  • 3
    @jpeskin Это не то, что я вижу. Я просто сделал быстрый тест, чтобы проверить. Создайте каталог с текстовым файлом, init новый репо, add файл и commit. Оформить новую ветвь функции (checkout -b feature.) Измените текстовый файл, зафиксируйте и повторите, чтобы в ветви функции были две новые фиксации. Затем checkout master и merge feature. В log я вижу свою начальную фиксацию на главном, а затем две, которые были объединены с функцией. Если вы merge --squash feature, функция объединяется в master, но не фиксируется, поэтому единственным новым фиксатором на master будет тот, который вы сделаете сами. – spaaarky21 27 May 2013 в 21:55
  • 4
    @ spaaarky21 Похоже, мы оба правы. Когда возможно быстрое слияние (как в вашем примере), git будет по умолчанию включать все коммиты в ветви функции B (или, как вы предлагаете, вы можете использовать -squash для объединения в одно коммит). Но в случае, когда есть две расходящиеся ветви M и B, которые вы объединяете, git не будет включать все отдельные фиксации из ветви B, если они объединены в M (независимо от того, используете ли вы --squash). – jpeskin 28 May 2013 в 02:36
  • 5
    Почему это «(вы не заботитесь о сохранении всех промежуточных коммитов)» в стороне все еще в этом ответе? Это не имело смысла в '09, и теперь это не имеет никакого смысла. Кроме того, конечно, вы только захотите переустановить, если другой разработчик выполнил связанные изменения , которые вам нужны, - если они сделали несвязанные изменения, ваша ветка функций должна легко сливаться без конфликтов, и ваша история будет сохранена. – Mark Booth 27 April 2016 в 10:59

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

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

A rebase перейдет к общему предку на 2 и постепенно применит изменения друг к другу. Это создает «более чистую» и более линейную историю.

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

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

15
ответ дан franzlorenzon 22 August 2018 в 02:03
поделиться
  • 1
    Слияния не объединяют коммиты - это будет переписывать историю. Rebase делает это. – kellyfj 29 March 2016 в 21:30

перед слиянием / 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 / огр-ГИТ-учебник /

55
ответ дан guybrush 22 August 2018 в 02:03
поделиться

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

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

Источник: http://www.git-scm.com/book/en/v2/ Гит-Ветвление-перебазирования # Rebase-против-Merge

25
ответ дан Joaquin Sargiotto 22 August 2018 в 02:03
поделиться

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

-7
ответ дан Marnen Laibow-Koser 22 August 2018 в 02:03
поделиться

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

Я сливаю, когда я поднимаю свою ветвь свойств на новый удаленный мастер. Это дает минимальную работу по поднятию, и легко следить за историей разработки функции, например, в 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 22 August 2018 в 02:03
поделиться

Этот ответ широко ориентирован вокруг Git Flow . Таблицы были созданы с помощью приятного ASCII Table Generator и деревьев истории с этой замечательной командой ( aliased as 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

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

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

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

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

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

Таким образом, вопрос о 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 22 August 2018 в 02:03
поделиться
255
ответ дан Community 5 November 2018 в 00:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: