Когда я должен использовать git pull --rebase?

806

Я знаю некоторых людей, которые используют git pull --rebaseпо умолчанию и других, которые настаивают на том, чтобы никогда не использовать его. Мне кажется, я понимаю разницу между слиянием и перебазированием, но я пытаюсь представить это в контексте git pull. Речь идет о нежелании видеть много сообщений о коммитах слияния или есть другие проблемы?

Джейсон Бейкер
источник
1
Источник для людей, которые советуют против git pull --rebase? Rebase или git rebase - это отдельное действие от git pull --rebase!
przemo_li

Ответы:

584

Вы должны использовать git pull --rebaseкогда

  • ваши изменения не заслуживают отдельной ветки

Действительно - почему бы и нет? Это более понятно и не накладывает логическую группировку на ваши коммиты.


Хорошо, я полагаю, это нуждается в пояснениях. В Git, как вы, наверное, знаете, вам рекомендуется ветвиться и сливаться. Ваша локальная ветвь, в которую вы вносите изменения, и удаленная ветвь, на самом деле, являются разными ветвями, и git pullвот-вот объединятся Это разумно, поскольку вы нажимаете не очень часто и обычно накапливаете ряд изменений, прежде чем они станут законченной функцией.

Однако иногда - по какой-либо причине - вы думаете, что на самом деле было бы лучше, если бы эти два - удаленный и локальный - были одной ветвью. Как в SVN. Именно здесь git pull --rebaseвступает в игру. Вы больше не объединяетесь - вы фактически делаете коммит поверх удаленной ветви . Вот о чем это на самом деле.

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

П Швед
источник
17
Я думаю, что это полезно, когда вы работаете в той же ветке, но вы можете изменить свою рабочую станцию. Я стремлюсь зафиксировать и перенести свои изменения с одной рабочей станции, затем перенести ребаз в другую и продолжать работать в той же ветке.
Пабло Пасос
11
Рекомендуется настроить Git на автоматическую перебазировку при извлечении с помощью команды git config --global pull.rebase preserve (сохраняйте, помимо включения перебазировки, пытается сохранить слияния, если вы сделали их локально).
Колин Д. Беннетт
2
Я не согласен с тем, что вы должны использовать pull --rebase только при работе с одной веткой. Вы должны использовать его все время, если это невозможно из-за каких-то других обстоятельств.
Томаш Фейфар
@P Швед ... «Однако иногда - по какой-то причине - вы думаете, что на самом деле было бы лучше, если бы эти два - удаленный и локальный - были одной ветвью» ... это можно сделать? что в локальной среде я могу иметь свою ветку и зеркало удаленной ветки как origin / master. Можете ли вы предоставить вход здесь?
Mandroid
736

Я хотел бы представить другой взгляд на то, что на самом деле означает «git pull --rebase», потому что иногда кажется, что он теряется.

Если вы когда-либо использовали Subversion (или CVS), вы можете привыкнуть к поведению «svn update». Если у вас есть изменения для фиксации, и фиксация завершается неудачей, потому что изменения были внесены в апстрим, вы "svn update". Subversion действует путем слияния изменений в верхнем потоке с вашими, что может привести к конфликтам.

То, что только что сделал Subversion, было «pull --rebase». Акт переформулировки ваших локальных изменений в соответствии с более новой версией - это «перебазирование» его части. Если вы выполнили «svn diff» до неудачной попытки коммита и сравнили полученный в результате diff с выводом «svn diff», то разница между этими двумя разностями заключается в том, что сделала операция перебазировки.

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

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

Если вы действительно чувствуете необходимость того, чтобы что-то было филиалом по какой-либо причине, то, на мой взгляд, это другое дело. Но если у вас нет конкретного и активного желания представлять свои изменения в форме слияния, поведение по умолчанию, на мой взгляд, должно быть «git pull --rebase».

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

SCODE
источник
18
@MarceloCantos Чтобы было ясно, я не говорю, что git (инструмент) должен по умолчанию перебазировать. Это было бы опасно, поскольку перебазировка по существу уничтожает историю. Я говорю, что с точки зрения рабочего процесса, когда вы не намереваетесь выполнять ветвление и просто взламываете какую-то ветку, над которой работают другие люди, «git pull --rebase» должно быть поведением пользователя по умолчанию.
Scode
1
Вы говорите, что не следует git config --global branch.autosetupmerge always?
Марсело Кантос
9
@MarceloCantos Нет, я не являюсь;) Лично я бы оставил autosetupmerge как значение по умолчанию true (если я сливаю назад и четвертую между ветвями, отличными от локальной <-> remote, мне бы хотелось, чтобы это было явным). Я просто говорю, что как человек я всегда использую «git pull --rebase» как часть моего обычного рабочего процесса «захватить последнюю в основной ветке», потому что я никогда не хочу создавать коммит слияния, если я не выполняю явное ветвление.
scode
9
+1 @ код После многих мучительных часов борьбы с вопросом о перебазировании / слиянии, наконец, вот ответ, который прибивает его.
AgileYogi
10
Этот ответ является просто попыткой адаптировать пользователей систем управления версиями для Git вместо того, чтобы дать им возможность правильно понять преимущества наличия соответствующих веток.
Алексей Зимарев
211

Возможно, лучший способ объяснить это на примере:

  1. Алиса создает ветку темы А и работает над ней
  2. Боб создает несвязанную ветку темы B и работает над ней
  3. Алиса делает git checkout master && git pull. Мастер уже в курсе.
  4. Боб делает git checkout master && git pull. Мастер уже в курсе.
  5. Алиса делает git merge topic-branch-A
  6. Боб делает git merge topic-branch-B
  7. Боб делает git push origin masterдо Алисы
  8. Алиса делает git push origin master, что отклонено, потому что это не ускоренное слияние.
  9. Алиса смотрит на журнал происхождения / мастера и видит, что фиксация не связана с ее.
  10. Алиса делает git pull --rebase origin master
  11. Фиксация слияния Алисы отменяется, фиксация Боба отменяется, а фиксация Алисы применяется после фиксации Боба.
  12. Алиса делает git push origin master, и все рады, что им не нужно читать бесполезный коммит слияния, когда они смотрят журналы в будущем.

Обратите внимание, что конкретная ветвь, которая объединяется, не имеет отношения к примеру. Master в этом примере также может быть веткой релиза или веткой разработчика. Ключевым моментом является то, что Алиса и Боб одновременно объединяют свои локальные ветви в общую удаленную ветку.

Коди Полл
источник
2
Ницца. Я склонен быть явным и git co master && git pull; git checkout topic-branch-A; git rebase master; git checkout master; git merge topic-branch-A; git push origin masterповторять, если чужой толчок к мастеру случился раньше моего. Хотя я вижу краткие преимущества в вашем рецепте.
HankCa
Хорошее объяснение @ Коди Опрос
Раджаниканта Прадхан
148

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

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

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

(*) Во время преподавания курса Git у меня был студент, арестовавший меня по этому поводу, поскольку я также выступал за перебазирование ветвей функций в определенных обстоятельствах. И он прочитал этот ответ;) Такой перебазирование также возможно, но оно всегда должно быть в соответствии с заранее оговоренной / согласованной системой, и как таковое не должно "всегда" применяться. И в то время я обычно тоже не делаю pull --rebase, о чем вопрос;)

krosenvold
источник
2
конечно, можно написать скрипт, чтобы скрыть коммиты слияния из журнала
hasen
3
Слияния могут также содержать различия, что означает, что это не совсем тривиально
krosenvold
9
@hasen j Да, но СОДЕРЖАНИЕ этих слияний может иметь значение
krosenvold
Этот ответ является расплывчатым и самоуверенным по сравнению с выбранным ответом: что вы подразумеваете под «той же ветвью»? Однако есть несколько хороших моментов, которых нет в выбранном ответе.
Iwein
1
Неопределенность вокруг «ответвления» вполне преднамеренная, поскольку существует множество способов использования ссылок; «направление работы» - это всего лишь один из вариантов.
krosenvold
50

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

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

Dustin
источник
2
«При просмотре истории никогда не бывает интересно узнать, когда парень, работающий над этой функцией, перестал синхронизироваться». / но разве это не означает, что эти промежуточные коммиты, скорее всего, являются сломанными сборками?
eglasius
10
Да, и они тоже не "целое государство". Вот почему мы не хотим их. Я хочу знать, что он хотел, а не как он туда попал.
Дастин
4
Если pull --rebaseвсегда следует использовать, почему не pullделает это по умолчанию?
страя
2
Боюсь, вам придется составить собственное мнение. У меня есть несколько вещей, .gitconfigчтобы заставить некоторые варианты делать правильные вещи. Я думаю, что git rebase по умолчанию делает не то, что делает git tag и т. Д. Если вы не согласны, вам не нужно обосновывать свое мнение.
Дастин
8
Это хороший совет, если вы извлекаете информацию из «вверх по течению», скажем из master, и если ветвь, в которую вы входите, еще не стала публичной (пока). Если вы потяните с другой стороны ветвь функции на другую, masterэто будет как наоборот: нет никакой причины использовать --rebase, верно? Это может быть причиной того, что это не по умолчанию. Я обнаружил, что Rebases - это то, как изменения должны проходить от вершины иерархии вниз, а слияния - как они возвращаются вверх. derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase
jolvi
38

Просто помни:

  • тянуть = получить + объединить
  • pull --rebase = fetch + rebase

Итак, выберите способ, которым вы хотите управлять своей веткой.

Вы бы лучше знали разницу между слиянием и перебазированием :)

leohxj
источник
9

Я думаю, что это сводится к личным предпочтениям.

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

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

Hasen
источник
8
Примечание для любого, кто просматривает этот вопрос: этот ответ совершенно не имеет отношения к вопросу "когда мне следует использовать git pull --rebase?"
therealklanni
3
@therealklanni Я отредактировал ответ, чтобы было понятнее, как он имеет отношение к вопросу (надеюсь, не разрушая намерения).
Паŭло Эберманн
Разделять грязный и неструктурированный журнал работ - это не честное дело, а просто лень. Вы тратите время людей, заставляя их преследовать вас через вашу кроличью нору разработки и отладки; дать им результат, а не бред.
krystah
8

git pull --rebaseможет скрыть переписывание истории от соавтора git push --force. Я рекомендую использовать, git pull --rebase только если вы знаете, что забыли подтолкнуть свои коммиты, прежде чем кто-то другой сделает то же самое.

Если вы ничего не совершали, но ваше рабочее пространство не чистое, просто git stashперед этим git pull. Таким образом, вы не будете молча переписывать свою историю (которая может молча отбросить некоторые ваши работы).

Habax
источник