В чем разница между git fetch, git rebase и git pull --rebase?

Читая страницу git pull, он дает строгое предупреждение о git pull --rebase:

Это потенциально опасный режим работы. Он переписывает историю, что не сулит ничего хорошего, если вы уже опубликовали эту историю. Не используйте эту опцию, если вы внимательно не прочитали git-rebase (1).

На странице git rebase содержится много описаний, но нет предупреждений подобного рода.

Кроме того, я видел, как некоторые люди говорили, что

git fetch
git rebase

такой же как

git pull --rebase

в то время как другие говорят, что они немного отличаются.

Что правда?


person Ryan Lundy    schedule 08.06.2011    source источник
comment
Действительно хорошая книга о git, которую стоит держать под подушкой progit.org   -  person Fredrik Pihl    schedule 09.06.2011
comment
Предупреждение на странице git pull звучит так, будто все может пойти не так, как надо. Но описание в книге звучит так, будто вам нужно приложить усилия, чтобы облажаться с ребейзингом.   -  person Ryan Lundy    schedule 09.06.2011
comment
В конечном итоге я регулярно использую git fetch для обновления моего представления об удаленном репо, а затем просматриваю раскрывающуюся историю и решаю, что я хочу сделать. (Обычно я добавляю git rebase.)   -  person Ryan Lundy    schedule 20.03.2013
comment
Аналогичный вопрос http://stackoverflow.com/questions/18930527/difference-between-git-pull-and-git-pull-rebase   -  person Michael Freidgeim    schedule 01.03.2016


Ответы (3)


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

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

Однако, если вы начинаете использовать несколько пультов дистанционного управления и начинаете делать git pull --rebase <arguments> так, чтобы вы больше не переустанавливали один и тот же целевой объект каждый раз, или начинаете подталкивать свою ветку к альтернативным репозиториям перед запуском git pull --rebase с вашим основным восходящим потоком, тогда можно начать нарваться на неприятности.

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

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

Это, эээ, не отвечает на вопрос о разнице между git pull --rebase и git fetch && git rebase @{u}. Я просто продолжу и скажу, что я не замечаю никакой разницы, и если она есть, она достаточно тонкая, чтобы я не заметил ее за те годы, что использовал Git. Возможно, в том, что система определяет правильный репозиторий, который ваша ветка должна получить, если у вас есть несколько репозиториев, а «origin» не является восходящим потоком этой ветки?

И даже если вы очень сильно ошибетесь с git-rebase, вы, конечно, можете легко вернуться к исходной среде до перебазирования с помощью git log -g и / или git reset --hard ORIG_HEAD. Только не выполняйте принудительные нажатия (по умолчанию они запрещены почти на всех серверах Git), и вы будете счастливы.

ИЗМЕНИТЬ

Со временем мое понимание расширилось. git pull --rebase вызывает git rebase для выполнения работы по перебазированию, поэтому в этом смысле между ними нет никакой разницы. Однако на самом деле git-pull вызывает git rebase --onto @{u} $(git merge-base HEAD @{u}@{1})

Хорошо, этот синтаксис ("@ {u} @ {1}"), возможно, немного непрозрачен и упрощает загрузку, но дело в том, что он выясняет, какой была база слияния для восходящего потока ПЕРЕД он выполнил команду выборки. Вы спросите, какая разница?

Ну, в обычном случае нет. Однако, если вы меняете направление восходящего потока или если сам восходящий поток был перебазирован, довольно много. Если апстрим был переписан, а затем вы сделали git rebase @{u}, вы могли быть очень недовольны и могли получить двойные коммиты или конфликты в зависимости от того, насколько старые коммиты были переписаны.

Однако с магией, лежащей в основе git pull --rebase, только ваши и только ваши коммиты будут применяться поверх @ {u}.

Хорошо, это тоже является упрощением. Если апстрим выполнил перебазирование, начиная с 100 коммитов назад (но на самом деле в истории более 101 коммитов) и вы выполнили git fetch до выполнения git pull --rebase, то Git не будет в состоянии точно определить, какова правильная историческая база слияния, чтобы выяснить, каковы ваши локальные коммиты.

В результате git fetch считается вредным (когда у вас есть локальные коммиты и апстрим перезаписан). Однако реальное практическое правило - «никогда не пытайтесь изменить историю после того, как она была опубликована, опубликована или отправлена», с чего я начал.

TL;DR:

git fetch считается вредным (поэтому используйте git pull --rebase); и никогда не пытайтесь изменить историю после того, как она была опубликована, опубликована или отправлена ​​(потому что, помимо прочего, это может git fetch быть вредным).

person Seth Robertson    schedule 08.06.2011
comment
TL; DR (возможно, там закопаны ответы на вопросы, но я никогда не узнаю :) - person Rick O'Shea; 03.08.2016
comment
@ RickO'Shea: Добавлен TL; DR только для вас. - person Seth Robertson; 03.08.2016
comment
TL; DR неверен: git fetch не может быть вредным! Он ничего не делает, кроме как получать новые объекты удаленно. Это никоим образом не меняет состояние локальной кассы или местных филиалов. - person mvp; 05.08.2016
comment
@mvp: Вы правы, fetch не изменяет локальные ветки, но это не мешает ему быть вредным (в определенных обстоятельствах, которые я указал в абзаце над TL; DR). Если вы думаете, что я «сейчас» ошибаюсь в этих обстоятельствах (я недавно не проверял эту часть git), пожалуйста, оспаривайте технические детали, а не общее резюме. - person Seth Robertson; 06.08.2016
comment
@SethRobertson, возможно, @mvp означает, что ваш TL; DR должен быть кратким изложением вашего ответа на полный вопрос В чем разница между git fetch, затем git rebase и git pull --rebase? и не только резюме вашего последнего абзаца, потому что в его нынешнем виде любой, кто просматривает ваш ответ в поисках TL; DR прочитает git fetch, считается вредным? Я думал git fetch просто загружает и ничего не меняет? И как это отвечает на вопрос git pull --rebase / git rebase? - person Alaa Ali; 02.11.2016
comment
@AlaaAli: да, именно это я имел в виду: git fetch не может быть вредным сам по себе. В нынешнем виде этот ответ не имеет никакого смысла, по крайней мере, для меня. - person mvp; 02.11.2016
comment
@mvp: Вы правы, git fetch не вреден сам по себе. Это вредно, потому что git теряет информацию, которая позволяет последующим командам, таким как git pull --rebase или git rebase, работать наилучшим образом, если кто-то другой переписал историю. Обычно это может сойти с рук, потому что все три обстоятельства редко случаются одновременно. - person Seth Robertson; 02.11.2016
comment
@AlaaAli: расширен TL; DR, чтобы вы включили подсказку о том, почему git fetch вреден, как описано в полном ответе. - person Seth Robertson; 02.11.2016
comment
@SethRobertson: к сожалению, я до сих пор не куплюсь на это. - person mvp; 02.11.2016

На самом деле они ДЕЙСТВИТЕЛЬНО разные. Вот действительно полезная веб-страница, которая прекрасно это объясняет:

http://gitolite.com/git-pull--rebase.html

Итак, git pull --rebase имеет некоторую значительную магию над git fetch; git rebase, которую в большинстве случаев вы не заметите, но в тех случаях, когда разработчик апстрима неосмотрительно проигнорировал все эти строгие предупреждения и решил переписать историю общедоступной ветки , это действительно может помочь, проконсультировавшись с вашим локальным рефлогом и сделав локальную перебазировку более разумным способом.

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

Скажу больше о суровых предупреждениях. Они действительны, но лично я нахожу большинство людей немного слишком параноиками по поводу перебазирования, как будто git rebase пробрался в их спальню посреди ночи, когда они были молоды, и съели свою сестру или что-то в этом роде. Это действительно не должно быть так страшно:

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

Это так просто. И да, я бы пошел еще дальше и стал активно поощрять людей регулярно git rebase -i пользоваться своими частными ветвями. Полировка истории перед отправкой куда-нибудь публично / вверх по течению: хорошая вещь, потому что никто не хочет влезать в историю проекта, полную коммитов вроде «упс, исправляем ошибку, которую я сделал 3 коммита назад». (OTOH, не зацикливайтесь на перебазировании в поисках безупречной истории. Мы люди. Мы делаем ошибки. Разбирайтесь с этим.)

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

person Adam Spiers    schedule 17.07.2012

Помимо обновления вашей локальной ветки из своей удаленной ветки отслеживания, -pull обновляет файлы вашей рабочей области.

Так что, вероятно, это более типично для git pull --rebase (или настроить pull для использования перебазирования по умолчанию), чем для git fetch; git rebase.

person Rick O'Shea    schedule 02.08.2016
comment
Это вообще не отвечает на вопрос. Кроме того, похоже, что вы проголосовали против моего правильного ответа, несмотря на то, что у вас не хватило терпения его прочитать. - person Adam Spiers; 03.08.2016