Когда git pull
запускает git merge
, он не указывает ни --ff-only
, ни --no-ff
, если только вы не попросите его об этом.
[с учетом графика фиксации]
...--o--o--o--H <-- master (HEAD)
\
P--Q--R <-- origin/master
[вы предполагаете, что git merge и, следовательно, git pull, будут производить]
...--o--o--o--H---------X <-- master (HEAD)
\ /
P--Q--R <-- origin/master
Это не так - по умолчанию, во всяком случае.Если вы запустите git merge --no-ff origin/master
, вы do получите этот результат.Если вы запускаете git merge --ff-only
или разрешаете действие по умолчанию, вы получаете вместо этого:
...--o--o--o--H
\
P--Q--R <-- master (HEAD), origin/master
Git называет это fast-forward .Когда это конкретно git merge
, которое делает это, 1 Git называет это ускоренным слиянием , хотя фактическое слияние не происходит: Git действительно просто делает git checkout
коммит R
при перемещении имени ветви master
так, чтобы оно указывало на фиксацию R
(и оставляя HEAD
присоединенным к имени ветви master
).
Опция --no-ff
сообщает Git: Не делайте ускоренную перемотку вперед, даже если можете. Результатом является новый коммит слияния (или ошибка, или что-то еще, конечно, может пойти не так).Опция --ff-only
говорит Git: Если вы можете сделать перемотку вперед, сделайте это;если нет, ничего не делайте, просто выведите ошибку.
Если у вас есть git pull
run git merge
, вы получаете тот же набор опций.Если ускоренная перемотка вперед (а) возможна и (б) разрешена, результат git merge
совпадает с результатом git rebase
: имя master
обновляется, и в графе фиксации ничего не меняетсяпуть.Если ускоренная перемотка вперед не возможна или запрещена с помощью --no-ff
, результат git merge
отличается от результата git rebase
тем, что существует новый коммит слияния X
.
Содержимое - сохраненный снимок - вашего нового коммита слияния X
соответствует данным вашего коммита R
.Но поскольку R
и X
- это разные коммиты, у них разные хэш-идентификаторы, и последующие операции Git будут вести себя по-разному.
1 И git push
, и git fetch
может сделать это для ссылок, обновленных через refspecs.Когда git push
перемещает ветку сервера в ускоренном режиме, вы обычно не видите ничего особенного.Когда git push
не может переместить ветку таким образом, вы обычно получаете отказ от сервера.git fetch
аннотация, а не ! rejected (non-fast-forward)
, составляет (forced update)
.(Ну, это одна из трех (!) git fetch
аннотаций.) См. Пример ниже.
Здесь я хотел бы подчеркнуть, что ускоренная перемотка вперед является свойством движения надписи.Ускоренная перемотка вперед возможна, если фиксация, идентифицированная перед движением - в данном случае фиксация H
- является предком фиксации, которая должна быть идентифицирована позже, т. Е. Фиксация R
.
Вот примеробновление без ускоренной загрузки.У меня есть локальный клон Git-репозитория для Git.Одна из веток в апстриме называется pu
, что означает предлагаемые обновления .Эта ветвь регулярно перематывается и перестраивается с новыми коммитами: кто-то предлагает какую-то новую функцию, пишет первый удар по ней, и те начинают тестирование.Ошибки обнаруживаются, функция перерабатывается, а сделанные коммиты отбрасываются в пользу новых улучшенных, которые входят в ветку pu
.Так что мой origin/pu
будет принудительно обновлен:
$ git fetch
remote: Counting objects: 509, done.
remote: Compressing objects: 100% (214/214), done.
remote: Total 509 (delta 325), reused 400 (delta 295)
Receiving objects: 100% (509/509), 468.38 KiB | 1.52 MiB/s, done.
Resolving deltas: 100% (325/325), done.
From [url]
d8fdbe21b5..95628af9bb next -> origin/next
+ b6268ac8c6...465df7fb28 pu -> origin/pu (forced update)
8051bb0ca1..f0bab95d47 todo -> origin/todo
$
Обратите внимание, что мой Git обновил мой origin/next
, мой origin/pu
и мой origin/todo
.Два из этих обновлений были операциями ускоренной пересылки: например, commit d8fdbe21b5
(мой старый origin/next
) является предком 95628af9bb
(мой обновленный origin/next
).Но b6268ac8c6
, мой старый origin/pu
, не предок 465df7fb28
.My Git обновил мой origin/pu
в любом случае , потеряв доступ к коммиту b6268ac8c6
(кроме как через reflogs).
Чтобы объявить об этом факте, git fetch
:
- имеет префикс строки с
+
; - , напечатанными тремя точками в обновлении вместо двух;и
- добавлено
(forced update)
в конце строки.
Поскольку изменения в origin/next
и origin/todo
были операциями ускоренной перемотки вперед,мой мерзавец ничего лишнего не сказал о них.