Как и в обоих других ответах, эффект, как правило, практически одинаков. Мсэнфорд указал на одну определенную и одну разность потенциалов , но есть и другие. Чтобы увидеть, что и почему, мы должны разобрать git pull
на составляющие.
Все привередливые детали (предупреждение: длинные)
За некоторыми незначительными исключениями (такими как запуск в совершенно пустом хранилище), git pull
означает:
- запустить
git fetch
с различными параметрами и аргументами; то
- запустить вторую команду Git, выбранную до запуска шага 1, также с различными параметрами и аргументами.
Вторая команда обычно git merge
, но вы можете указать Git использовать git rebase
. Параметры и аргументы, передаваемые двум командам, зависят от параметров, переданных в git pull
, и других параметров конфигурации, а также от результата или результатов выборки на шаге 1.
Однако, как своего рода общее правило, аргументы, переданные в git pull
, передаются в git fetch
, поэтому это означает, что ваша вторая последовательность команд, которая передает origin master
в git pull
, передает origin master
в git fetch
. Если вы запускаете git pull
без этих аргументов, как в вашей первой последовательности команд, Git извлекает remote (обычно origin
) и имя восходящей ветви (обычно совпадает с текущим именем ветви) из вашей конфигурации, в частности, по результатам этих двух команд: 1
git config --get branch.$branch.remote
git config --get branch.$branch.merge
(где $branch
- текущая ветвь). Если текущая ветвь имеет значение master
, в качестве пульта используется branch.master.remote
. Это то, что мы имеем в виду, предполагая, что есть только один пульт. merge
имя, вероятно, master
, но если нет, это еще одно предположение, которое мы должны сделать, прежде чем мы сможем утверждать, что они делают то же самое.
1 , если ваш Git достаточно стар, git pull
- это скрипт оболочки, который буквально выполняет различные другие команды Git. Если он более новый, git pull
был преобразован в программу на языке C, и он встроен непосредственно в него.
Rebase копии фиксирует, затем переключается на новые копии
То, что делает git rebase
, усложняется, если мы углубляемся во все детали, но на высоком уровне его работа заключается в copy commits. Чтобы увидеть, какие коммиты будут копироваться, вы должны нарисовать график коммитов или использовать git log --graph
, чтобы Git нарисовал его для вас. (Некоторые графические пользовательские интерфейсы всегда рисуют его, а некоторые веб-интерфейсы * кашель * GitHub * кашель * никогда не позволяют просматривать его!) С графическим рисунком это легко - ну, иногда легко - сказать, какие коммиты копируются:
...--A--B--C--D <-- master
\
E--F--G <-- br
Перебазирование вашей ветви br
на ваш мастер копирует три коммита, здесь E
- G
, размещая копии после коммита D
. Это похоже на то, что вы нарисовали.
Предположим, мы добавили origin/
имен для удаленного слежения и покажем, что ваш собственный master
в данный момент указывает на фиксацию B
, в то время как origin/master
в данный момент указывает на фиксацию D
, например:
C--D <-- origin/master
/
...--A--B <-- master
\
E--F--G <-- br
Теперь мы видим, что мы должны перебазировать br
на origin/master
, чтобы копии шли после коммита D
. Перебазирование на master
приведет к копированию после B
, где находятся оригиналы, поэтому копировать все равно не нужно. (То, является ли rebase копированием или повторным использованием оригиналов, является одной из самых хитроумных деталей: например, это зависит от опции -f
.)
Как только копирование завершено, git rebase
просто повторно указывает имя ветки, чтобы указать на окончательно скопированный (или повторно использованный) коммит, который мы можем назвать здесь G'
, чтобы отметить, что это копия * 1096. *. Первоначальные коммиты фактически отменяются, хотя записи журнала для HEAD и исходной ветки и имя ORIG_HEAD
временно сохраняют их:
E'-F'-G' <-- br
/
C--D <-- origin/master
/
...--A--B <-- master
\
E--F--G [abandoned, but see ORIG_HEAD and reflogs]
По умолчанию записи журнала сохраняют оригиналы доступными не менее 30 дней. В конечном итоге ORIG_HEAD
перемещается в другое место из-за других операций, и срок действия записей reflog истекает, а исходные коммиты собираются сборщиком мусора.
Теперь мы можем посмотреть на ваши оригинальные последовательности команд
LeПредположим, что у нас есть приведенный выше график (как у вас, но с еще одним коммитом на ветке br
, и мы уже запустили git fetch
, чтобы обновить origin/master
). Затем последовательность команд Atlassian начинается с этих двух команд:
git checkout master
git pull --rebase
Это прикрепит наш HEAD
к нашему master
, проверяя коммит B
; затем, предполагая, что восходящий поток равен origin/master
, запустите git fetch origin master
, чтобы обновить наш origin/master
, что в этом случае оставляет origin/master
, указывая на D
. Если бы мы еще не запустили git fetch
, то получило бы коммитов C
и D
и указало бы origin/master
на D
.
Последнее, это будет работать git rebase <hash-of-commit-D>
. Операция rebase использует хеш-идентификатор, потому что использует трассировки, которые git fetch
оставляет в .git/FETCH_HEAD
, и, в зависимости от точной версии Git и других деталей, которые мы здесь проигнорируем, также использует git merge-base --fork-point
, чтобы найти хеш коммита, чтобы оправиться от перебазирования вверх по течению. (Этот процесс иногда идет не так, в зависимости от вашего рабочего процесса, и я не уверен, что мне нравится поведение по умолчанию.)
Как только это будет сделано, мы перейдем к двум последним командам:
git checkout br
git rebase master
Первый присоединяет HEAD
к имени br
, проверяя коммит G
. Затем ребаз копирует последовательность коммита E-F-G
, которая идет после коммита, на который теперь указывает master
. Итак, игнорируя все записи reflog, мы получаем график:
E'-F'-G' <-- br (HEAD)
/
...--A--B--C--D <-- master, origin/master
\
E--F--G [abandoned]
Сравните это с вашей более короткой последовательностью команд:
git checkout br
git pull --rebase origin master
Оформление заказа прикрепляет HEAD
к br
. pull
запускает git fetch origin master
, что гарантирует, что у нас есть коммиты C-D
(если мы их еще не получили) и обновляет origin/master
(если наш Git по крайней мере 1.8.4), затем запускается git rebase <hash-of-D>
, который копирует цепочку E-F-G
, давая:
E'-F'-G' <-- br
/
C--D <-- origin/master
/
...--A--B <-- master
\
E--F--G [abandoned]
Итак, ключевое отличие в том, что ваше собственное имя, master
, никогда не обновляется, чтобы указывать на коммит D
.
Что я рекомендую вместо
Важно отметить (и знать), что если вы запускаете git fetch
самостоятельно - это мой предпочтительный метод - это скажет вашему Git вызывать другой Git по URL-адресу пульта и иметь другой список Git для вашего Git, все его (мы предполагаем, происхождения) ветвей. Затем ваш Git получит все коммитов, которых у вас нет, и поместит их в репозиторий вашего Git, и обновит все ваших имен для удаленного отслеживания, таких как origin/master
и origin/develop
и т. Д.
Другими словами, ваши имена для удаленного отслеживания, которые ваш Git запоминает их ветвей, будут все обновляться. Обычно это хорошая вещь. Это плохо, только если у них много веток и много больших коммитов, а ваше сетевое соединение медленное; в этом случае вам, возможно, придется долго ждать, чтобы загрузить все.
Когда git pull
запускает git fetch
, он запускает его с ограничивающим параметром. Например, если ваш git pull
работает:
git fetch origin master
, который говорит вашему Git вызвать Git по URL-адресу для origin
и попросить их передать только фиксирует новое для их master
. Если у них есть обновления к develop
и production
и feature/tall
и т. Д., Вы не получите ни одного из них - вы получите только новые коммиты, которые находятся на их master
. Ваш Git обновляет ваш origin/master
для запоминания новых коммитов, 2 , но оставляет остальные ваши имена для удаленного отслеживания без изменений.
Во второй последовательности команд вы запускаете явный git pull origin master
(также с --rebase
), так что это ограничивает ваш Git обновлением origin/master
. В вашей последовательности команд first вы запускаете git pull
без аргументов, но git pull
вставляет origin
и master
, предполагая, что это настроенные параметры для вашей ветви master
, так что это также ограничивает ваш Git обновлением только вашего origin/master
.
Я упоминаю все это, потому что я рекомендую вообще не использовать git pull
. Запустите git fetch
самостоятельно - вы можете разрешить ему по умолчанию извлекать все из origin
- и затем запускать любые команды git rebase
, которые вы хотите! После fetch
у вас есть все коммиты и все соответствующие origin/*
имена; Затем вы можете запустить:
git checkout <whatever-name>
git rebase origin/<whatever-other-name>
копy все, что фиксирует и / или корректирует, какие из ваших собственных веток вы хотите обновить.Одна выборка позволяет выполнять любое количество операций слияния, сброса, ускоренной перемотки вперед или операций перебазирования.Вы также можете посмотреть на что было получено, прежде чем вы решите, какие другие команды Git запускать!
2 Это предполагает, что ваш Git по крайней мере версии 1.8+0,4.Если нет, то git fetch
не может обновиться даже origin/master
.Вы должны запустить git fetch
или git fetch origin
, чтобы обновить имена для удаленного отслеживания!