Git pull --rebase - это то же самое, что и git pull, если в локальной ветке master не выполняется работа? - PullRequest
2 голосов
/ 13 июня 2019

Я понимаю, что разница между git rebase и git merge заключается в том, что git rebase перемещает начало ветви к концу другой ветви, где git merge создает новый коммит, который представляет (то есть включает или интегрируетРазветвленные коммиты из другой ветки.Например:

Поскольку git pull эквивалентно git fetch + git merge, а git pull --rebase эквивалентно git fetch + git rebase, допустим, у вас есть локальная ветвь master иудаленная главная ветвь:

- o - o - o - H - A - B - C (master)
               \
                P - Q - R (origin/master)

HEAD находится в C

Если вы git pull, вы получите следующее:

- o - o - o - H - A - B - C - X (master)
               \             /
                P - Q - R --- (origin/master)

HEAD теперь будет в X, которыйявляется коммитом R истории коммитов удаленного репозитория, потому что коммит слияния (X) представляет (то есть включает или интегрирует) историю коммитов удаленной ветки, которая была объединена

Если с другой стороны вы сделали git pull --rebase, вы быв итоге получим следующее:

- o - o - o - H - P - Q - R - A' - B' - C' (master)
                          |
                          (origin/master)

Как видите, git pull - это не то же самое, что git pull --rebase, потому что git pull --rebase дает HEAD в C ', который является коммитом C локальной ветки master, где каккогда использовался git pull, HEAD находился в R. Другими словами, содержимое истории фиксации с помощью git pull такое же, как содержимое истории фиксации из git pull --rebase, но порядок фиксации в истории фиксации отличается

Но что происходит, когда вы вытаскиваете изветвь mote, когда не было выполнено никакой работы с локальной веткой master:

локальная ветка master и удаленная ветка master:

- o - o - o - H (master)
               \
                P - Q - R (origin/master)

HEAD находится в H

Если выgit pull В итоге вы получите следующее:

- o - o - o - H - X (master)
               \             \
                P - Q - R --- (origin/master)

HEAD теперь будет в X, который является коммитом R репо, потому что коммит слияния представляет удаленную ветвь, которая была объединена

Если включенс другой стороны, вы сделали git pull --rebase, не могли бы вы в итоге это сделать:

- o - o - o - H - P - Q - R (master)
                          |
                          (origin/master)

Это означает, что HEAD находится в точке R, что означает, что git pull --rebase совпадает с git pull, когда работа не выполняетсяв местном филиале

1 Ответ

2 голосов
/ 13 июня 2019

Когда 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:

  1. имеет префикс строки с +;
  2. , напечатанными тремя точками в обновлении вместо двух;и
  3. добавлено (forced update) в конце строки.

Поскольку изменения в origin/next и origin/todo были операциями ускоренной перемотки вперед,мой мерзавец ничего лишнего не сказал о них.

...