Git рабочий процесс и ребаз против вопросов слияния

971

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

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

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

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature
git checkout master
git merge my_new_feature

По сути, создайте ветвь объектов, ВСЕГДА перебирайте с мастера на ветку и сливайте с ветки обратно на ветку. Важно отметить, что филиал всегда остается локальным.

Вот рабочий процесс, с которого я начал

clone remote repository
create my_new_feature branch on remote repository
git checkout -b --track my_new_feature origin/my_new_feature
..work, commit, push to origin/my_new_feature
git merge master (to get some changes that my partner added)
..work, commit, push to origin/my_new_feature
git merge master
..finish my_new_feature, push to origin/my_new_feature
git checkout master
git merge my_new_feature
delete remote branch
delete local branch

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

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

Мое рассуждение о слиянии вместо rebase заключается в том, что слияние кажется стандартным, а rebase - расширенной функцией. У меня такое ощущение, что я пытаюсь не продвинутая настройка, поэтому ребаз должен быть ненужным. Я даже просмотрел новую книгу «Прагматическое программирование» по Git, и в ней подробно рассматриваются слияния и едва упоминается ребазинг.

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

Каков «правильный» рабочий процесс для чего-то подобного? Git должен сделать ветвление и слияние очень легким, и я просто не вижу этого.

Обновление 2011-04-15

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

Оказывается, исходный рабочий процесс корректен, по крайней мере, в нашем случае. Другими словами, это то, что мы делаем, и это работает:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge my_new_feature

На самом деле, наш рабочий процесс немного отличается, так как мы склонны делать сквош-слияния вместо сырых слияний. ( Примечание: это противоречиво, см. Ниже. ) Это позволяет нам превратить всю нашу ветку объектов в один коммит на master. Затем мы удаляем нашу ветку функций. Это позволяет нам логически структурировать наши коммиты на master, даже если они немного запутаны в наших ветках. Итак, вот что мы делаем:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge --squash my_new_feature
git commit -m "added my_new_feature"
git branch -D my_new_feature

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

Github и Bitbucket (другие?) Запросы на извлечение - Если вам интересно, как слияние / перебазирование связано с запросами на извлечение, я рекомендую выполнить все вышеописанные шаги до тех пор, пока вы не будете готовы к слиянию с мастером. Вместо ручного слияния с git, вы просто принимаете пиар. Обратите внимание, что это не будет выполнять слияние с помощью сквоша (по крайней мере, по умолчанию), но без сквоша, без ускоренной перемотки является принятым соглашением о слиянии в сообществе запросов на извлечение (насколько я знаю). В частности, это работает так:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git push # May need to force push
...submit PR, wait for a review, make any changes requested for the PR
git rebase master
git push # Will probably need to force push (-f), due to previous rebases from master
...accept the PR, most likely also deleting the feature branch in the process
git checkout master
git branch -d my_new_feature
git remote prune origin

Я полюбил Git и больше не хочу возвращаться в SVN. Если вы боретесь, просто придерживайтесь этого, и в конце концов вы увидите свет в конце туннеля.

Михей
источник
31
К сожалению, новая книга Pragmstic Programming в основном написана с использованием Git, все еще думая в SVN, и в этом случае она ввела вас в заблуждение. В Git rebase делает вещи простыми, когда они могут быть. Ваш опыт может сказать вам, что ваш рабочий процесс не работает в Git, не то, что Git не работает.
Пол
18
В этом случае я бы не рекомендовал объединять сквош, так как он не сохраняет информации о том, что объединяется (как svn, но здесь нет mergeinfo).
Мариус К
7
Мне нравится записка внизу, у меня был похожий опыт борьбы с Git, но сейчас я пытаюсь представить, что не использую ее. Спасибо за окончательное объяснение, очень помогли с rebaseпониманием
Джон Фенов
6
После того, как вы закончите эту функцию, не следует ли вам сделать еще одну перебазировку, прежде чем объединить new_feature с master?
softarn
17
Ваш рабочий процесс теряет всю историю коммитов из удаленной ветки :(
Max Nanasy

Ответы:

372

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

Причина, по которой ребазинг тогда лучше, чем слияние, заключается в том, что:

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

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

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


На эту тему (перебазирование, а затем слияние рабочего процесса) Баррапонто упоминает в комментариях два интересных поста, оба из randyfay.com :

Используя эту технику, ваша работа всегда идет поверх публичной ветки, как патч, который обновляется до текущей HEAD.

(похожая техника существует для базара )

VonC
источник
27
Для техники, которая позволяет перебазировать и делиться, см. Softwareswirl.blogspot.com/2009/04/…
mhagger
2
randyfay.com/node/91 и randyfay.com/node/89 - замечательные чтения. Эти статьи помогли мне понять, что беспокоит мой рабочий процесс и каков будет идеальный рабочий процесс.
Capi Etheriel
просто чтобы сделать это прямо, перебазирование из основной ветки на ваш локальный означает в основном обновить любую историю, которую ваш местный житель мог пропустить, о которой мастер знает после какого-либо слияния?
Hellatan
@dtan, что я описываю здесь, это перебазирование локального поверх мастера. Вы не точно обновляете локальную историю, а скорее повторно применяете локальную историю поверх мастера, чтобы разрешить любой конфликт в локальной ветви.
VonC
386

TL; DR

Рабочий процесс git rebase не защищает вас от людей, которые плохо разбираются в разрешении конфликтов, или от людей, привыкших к рабочему процессу SVN, как это предлагается в статье «Избежание Git Disasters: История Гори» . Это только делает разрешение конфликтов более утомительным для них и затрудняет восстановление после плохого разрешения конфликтов. Вместо этого используйте diff3, чтобы это не было так сложно в первую очередь.


Перебазировать рабочий процесс не лучше для разрешения конфликтов!

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

Если во время слияния он пойдет «все в ад», то во время перебазировки он пойдет «все в ад», и, возможно, намного больше в ад! Вот почему:

Причина № 1: Разрешать конфликты один раз, а не один раз для каждого коммита

Когда вы перебазируете вместо слияния, вам придется выполнять разрешение конфликтов столько раз, сколько вы выполняете перебазирование, для одного и того же конфликта!

Реальный сценарий

Я разветвляюсь от мастера, чтобы провести рефакторинг сложного метода в ветке. Моя работа по рефакторингу состоит из 15 коммитов, так как я работаю над ее рефакторингом и получаю обзоры кода. Часть моего рефакторинга включает исправление смешанных вкладок и пробелов, которые присутствовали в master раньше. Это необходимо, но, к сожалению, оно будет конфликтовать с любыми изменениями, внесенными впоследствии в этот метод в master. Конечно же, пока я работаю над этим методом, кто-то вносит простое, законное изменение в тот же метод в основной ветке, который должен быть объединен с моими изменениями.

Когда пришло время объединить мою ветку с master, у меня есть два варианта:

Git Merge: я получаю конфликт. Я вижу изменения, которые они сделали, чтобы освоить и объединить их с (конечным продуктом) моей ветки. Выполнено.

git rebase: у меня конфликт с первым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт со вторым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим третьим коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим четвертым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим пятым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с шестым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с седьмымсовершить. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим восьмым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим девятым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим десятым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим одиннадцатым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим двенадцатым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим тринадцатым коммитом. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с моим четырнадцатымсовершить. Я разрешаю конфликт и продолжаю перебазирование. У меня конфликт с пятнадцатым коммитом. Я разрешаю конфликт и продолжаю перебазирование.

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

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

Причина № 2: с rebase, нет отмены!

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

Когда вы объединяете ветку, git создает коммит слияния, который можно отменить или изменить, если разрешение конфликта идет плохо. Даже если вы уже отправили неудачный коммит слияния в публичное / авторитетное репо, вы можете использовать его, git revertчтобы отменить изменения, внесенные слиянием, и правильно повторить слияние в новом коммите слияния.

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

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

* Может быть возможно отменить ребазинг, если вы можете выкопать старые ссылки из внутренних журналов git, или если вы создадите третью ветку, которая указывает на последний коммит перед ребазингом.

Избавьтесь от разрешения конфликта: используйте diff3

Возьмите этот конфликт, например:

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

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

на помощь diff3!

git config --global merge.conflictstyle diff3

Когда вы используете diff3, каждый новый конфликт будет иметь 3-й раздел, объединенный общий предок.

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
||||||| merged common ancestor
EmailMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

Сначала изучите объединенного общего предка. Затем сравните каждую сторону, чтобы определить намерение каждой ветви. Вы можете видеть, что HEAD изменил EmailMessage на TextMessage. Его цель - изменить используемый класс на TextMessage, передавая те же параметры. Вы также можете видеть, что намерение ветви функции - передать false вместо true для опции: include_timestamp. Чтобы объединить эти изменения, объедините намерение обоих:

TextMessage.send(:include_timestamp => false)

В основном:

  1. Сравните общего предка с каждой ветвью и определите, какая ветвь имеет самое простое изменение
  2. Примените это простое изменение к версии кода другой ветви, чтобы оно содержало как более простые, так и более сложные изменения.
  3. Удалите все секции кода конфликта, кроме той, в которую вы только что слили изменения вместе

Альтернатива: разрешить вручную, применяя изменения ветви

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

Давайте посмотрим, как мы можем разрешить конфликт в сценарии, где происходит слияние, origin/feature1где lib/message.rbконфликты.

  1. Решите, является ли наш измененный филиал ( HEADили --ours) или филиалом, который мы объединяем ( origin/feature1или --theirs), более простым изменением, чтобы применить его. Использование diff с тройной точкой ( git diff a...b) показывает изменения, произошедшие bс момента последнего расхождения a, или, другими словами, сравнивает общего предка a и b с b.

    git diff HEAD...origin/feature1 -- lib/message.rb # show the change in feature1
    git diff origin/feature1...HEAD -- lib/message.rb # show the change in our branch
    
  2. Проверьте более сложную версию файла. Это удалит все маркеры конфликта и будет использовать ту сторону, которую вы выберете.

    git checkout --ours -- lib/message.rb   # if our branch's change is more complicated
    git checkout --theirs -- lib/message.rb # if origin/feature1's change is more complicated
    
  3. Сложное изменение проверено, найдите различие более простого изменения (см. Шаг 1). Примените каждое изменение из этого diff к конфликтующему файлу.

Эдвард Андерсон
источник
4
Как объединить все конфликты за один раз лучше, чем отдельные коммиты? Я уже получаю проблемы от объединения отдельных коммитов (особенно от людей, которые не разбивают коммиты на логические части и предоставляют достаточные тесты для проверки). Кроме того, rebase не хуже, чем слияние, когда дело доходит до опций резервного копирования, интеллектуальное использование интерактивной перебазировки и инструментов, таких как tortoisegit (который позволяет выбирать, какие коммиты включать), очень поможет.
Пруссван
8
Я чувствую, что обратился к причине в # 1. Если отдельные коммиты не являются логически непротиворечивыми, тем больше причин объединять логически непротиворечивую ветвь, чтобы вы могли понять конфликт. Если коммит 1 содержит ошибки, а коммит 2 исправляет его, слияние коммит 1 будет сбивать с толку. Есть законные причины, по которым вы можете получить 15 конфликтов подряд, как я описал выше. Также ваш аргумент в пользу того, что ребаз не хуже, является несколько необоснованным. Rebase смешивает плохие слияния с оригинальными хорошими коммитами и не оставляет хороших коммитов, чтобы позволить вам попробовать еще раз. Слияние делает.
Эдвард Андерсон,
6
Я полностью согласен с тобой nilbus. Великий пост; это проясняет некоторые вещи. Интересно, будет ли rerere хоть какая-то помощь здесь. Кроме того, спасибо за предложение по использованию diff3, я определенно собираюсь включить его прямо сейчас.
Дерик
45
+1 за то, что рассказал мне только о diff3 - как часто он смотрел на непонятный конфликт, проклинающий того, кто отвечает за то, что не сказал мне, что должен был сказать общий предок. Большое спасибо.
Джон
4
Это должен был быть принятый ответ. Рабочий процесс rebase также ужасен, потому что он скрывает тот факт, что в какой-то момент времени в кодовой базе произошли огромные расхождения, что может быть полезно знать, если вы хотите понять, как был написан код, который вы просматриваете. Только небольшие ветви, которые не конфликтуют, должны быть перебазированы на мастер.
Роберт Рюгер
32

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

Однако даже в рабочем процессе, основанном на ребазе, есть место для слияний.

Напомним, что слияние фактически создает узел, у которого есть два родителя. Теперь рассмотрим следующую ситуацию: у меня есть две независимые ветви функций A и B, и теперь я хочу разработать материал для ветви функций C, который зависит как от A, так и от B, в то время как A и B рассматриваются.

Что я тогда делаю, так это следующее:

  1. Создать (и оформить заказ) ветку C поверх A.
  2. Объединить это с B

Теперь ветвь C включает в себя изменения как от A, так и от B, и я могу продолжать развивать ее. Если я сделаю какие-либо изменения в A, то я восстановлю график ветвей следующим образом:

  1. создать ветку T на новой вершине A
  2. объединить T с B
  3. перебазировать С на Т
  4. удалить ветку T

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

Алекс Гонтмахер
источник
1
Вы могли бы достичь того же с помощью просто перебазирования. Слияние здесь на самом деле не нужно (за исключением случаев, когда вы не хотите дублировать коммиты - но я вряд ли рассматриваю это как аргумент).
odwl
1
На самом деле я не хочу дублировать коммиты. Я хотел бы сохранить структуру своей работы в полете как можно более чистой. Но это вопрос личного вкуса, и это не обязательно подходит для всех.
Алекс Гонтмахер
Я на 100% согласен с первым абзацем. (Ответ @ Эдварда работает там, где это не так, но я бы предпочел, чтобы все проекты в мире работали так, как вы предлагаете). Остальная часть ответа кажется немного надуманной в том смысле, что работа над C во время выполнения A и B уже в некотором роде рискованна (по крайней мере, в той степени, в которой это действительно зависит от A и B), и даже в конце концов вы вероятно, не будет сохранять слияния (C будет перебазирован поверх последних и самых больших).
Алоис Махдал
23

НЕ ИСПОЛЬЗУЙТЕ git push origin --mirror В СООТВЕТСТВИИ С ЛЮБОЙ ЛЮБОЙ ОБСТОЯТЕЛЬНОСТЬЮ.

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

http://twitter.com/dysinger/status/1273652486

Скотт Браун
источник
6
Или не делать то, что вы не уверены, каков будет результат? Машина, которую я использовал для администратора, была Instructions to this machine may lead to unintended consequences, loss of work/data, or even death (at the hands of the sysad). Remember that you are solely responsible for the consequences of your actions в MOTD.
Ричо
используйте его, если у вас есть зеркальное репо (хотя в моем случае оно теперь выполняется специальным пользователем в репо-источнике на перехвате после получения)
prusswan
14

У меня есть один вопрос после прочтения вашего объяснения: может быть, вы никогда не делали

git checkout master
git pull origin
git checkout my_new_feature

перед выполнением 'git rebase / merge master' в вашей ветке функций?

Потому что ваша основная ветка не будет обновляться автоматически из репозитория вашего друга. Вы должны сделать это с git pull origin. Т.е., может быть, вы всегда сделали бы ребаз из неизменной локальной ветки master? И затем наступает время push, вы запускаете репозиторий, в котором есть (локальные) коммиты, которые вы никогда не видели, и, следовательно, push не выполняется.

knweiss
источник
13

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

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

Вы все равно можете продолжать отправлять свою частную ветку разработки в удаленный репозиторий ради резервного копирования, но другие не должны воспринимать это как "публичную" ветку, так как вы будете перебазировать. Кстати, простая команда для этогоgit push --mirror origin .

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

Пэт Нотц
источник
1
Ссылка на программное обеспечение для упаковки с использованием git больше не работает. Я не смог найти хорошую ссылку для редактирования исходного ответа.
Четан
Вы не должны зеркально отображать origin, вы должны зеркально отображать третий хранилище выделенных резервных копий.
Мирал
12

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

Ни в вашем партнёре, ни в предложенных вами рабочих процессах вы не должны сталкиваться с конфликтами, которые не имеют смысла. Даже если у вас есть, если вы следуете предлагаемым рабочим процессам, после разрешения «принудительный» толчок не требуется. Это говорит о том, что вы на самом деле не слили ветку, в которую вы толкали, но вам пришлось толкнуть ветку, которая не была потомком удаленного кончика.

Я думаю, вам нужно внимательно посмотреть на то, что произошло. Может ли кто-то другой (намеренно или нет) перемотать удаленную главную ветку между созданием локальной ветки и точкой, в которой вы попытались объединить ее с локальной веткой?

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

CB Bailey
источник
Вы намекаете, что у ОП есть неопознанная перебазировка или ошибка в его процессе, верно?
krosenvold
8

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

  • Создать новую ветку B из существующей ветки A

  • Добавить / зафиксировать изменения в ветке B

  • Перебазировать обновления из ветки А

  • Объединить изменения из ветви B в ветку A "

https://www.atlassian.com/git/tutorials/merging-vs-rebasing/

Rakka Rage
источник
7

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

Pepe
источник
4

В Git нет «правильного» рабочего процесса. Используйте все, что плавает на вашей лодке. Однако, если вы постоянно сталкиваетесь с конфликтами при объединении веток, возможно, вам следует лучше координировать свои усилия с коллегами-разработчиками? Похоже, вы двое продолжаете редактировать одни и те же файлы. Кроме того, следите за пробелами и подрывными ключевыми словами (например, «$ Id $» и другие).

Бомбы
источник
0

Я использую только рабочий процесс rebase, потому что он визуально более понятен (не только в GitKraken, но и в Intellij и в gitk, но я рекомендую самый первый): у вас есть ветвь, она исходит от мастера и возвращается к мастеру , Когда диаграмма будет чистой и красивой, вы будете знать, что ничто не идет в ад, никогда .

введите описание изображения здесь

Мой рабочий процесс почти такой же, как у вас, но с одним небольшим отличием: я squashфиксирую один в своем локальном филиале перед тем, как rebaseмой филиал включит последние изменения master, потому что:

rebaseработает на основе каждого коммита

Это означает, что если у вас есть 15 коммитов, меняющих ту же строку, что masterи вы, вы должны 15 раз проверить, не сквошите ли вы, но какое значение имеет конечный результат, верно?

Итак, весь рабочий процесс:

  1. Проверьте masterи потяните, чтобы убедиться, что у вас последняя версия

  2. Оттуда создайте новую ветку

  3. Делайте свою работу там, вы можете свободно фиксировать несколько раз и передавать удаленно, не беспокойтесь, потому что это ваша ветвь.

  4. Если кто-то скажет вам: «Эй, мой PR / MR одобрен, теперь он объединен с мастером», вы можете получить их / вытащить их. Вы можете сделать это в любое время или на шаге 6.

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

  6. Проверьте master, pullснова, чтобы убедиться, что у вас есть последние masterв местном. Ваша диаграмма должна быть похожа на это:

введите описание изображения здесь

Как видите, вы находитесь в своем местном филиале, который имеет устаревшее состояние master, в то время как master(как локальный, так и удаленный) продвинулся вперед с изменениями вашего коллеги.

  1. Оформите заказ обратно в свою ветку и сделайте ребаз до мастера. Теперь у вас будет только один коммит, поэтому вы разрешаете конфликты только один раз (а в GitKraken вам нужно только перетащить ветку на masterи выбрать «Rebase»; еще одна причина, по которой мне это нравится). После этого вы будете подобно:

введите описание изображения здесь

  1. Итак, теперь у вас есть все последние изменения в masterсочетании с изменениями в вашей ветке. Теперь вы можете нажать на пульт, и, если вы нажали раньше, вам придется принудительно нажать; Git скажет вам, что вы не можете просто перемотать вперед. Это нормально, из-за перебазировки вы изменили начальную точку своей ветки. Но вы не должны бояться: используйте силу, с умом . В конце концов, пульт дистанционного управления также является вашей веткой, поэтому вы не оказываете влияния, masterдаже если делаете что-то не так.

  2. Создайте PR / MR и подождите, пока он не будет одобрен, поэтому masterвнесу свой вклад. Congrats! Так что теперь вы можете оформить заказ master, вытащить свои изменения и удалить свою локальную ветку, чтобы очистить диаграмму. Удаленная ветвь тоже должна быть удалена, если этого не сделать, когда вы объедините ее с master.

Окончательная диаграмма снова чиста и ясна:

введите описание изображения здесь

WesternGun
источник