git pull * после * git rebase?

У меня есть ветвь признаков и главная ветвь.

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

Так что я git pull в обоих ветвях, git checkout feature/branch и, наконец, git rebase master.

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

Теперь, что на самом деле произошло в моем случае, я не понимаю:

$>git rebase master
First, rewinding head to replay your work on top of it...
Applying: myFirstCommitDoneOnTheBranch
Applying: myOtherCommitDoneOnTheBranch
$>git status
On branch feature/branch
Your branch and 'origin/feature/feature' have diverged,
and have 27 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
$>git pull
*load of conflicts*

Теперь, насколько я понимаю, он загружает конфликты после тяги; Я не понимаю, зачем нужно тянуть. Логически, он должен откатываться, чтобы справиться, когда он получил разветвленную, сохранить коммиты, сделанные в ветке, переслать на последнюю фиксацию на хозяине, а затем применить сохраненные фиксации.

Я не понимаю, к чему относится сообщение Applying: что применяет коммиты на какой версии?

Ответы

Ответ 1

tl; dr Вы должны обновить master и feature с помощью git pull и git pull --rebase прежде чем перезапустить feature поверх master. Нет необходимости делать git pull после git pull как вы пересоздали свою ветку feature поверх master.

С вашим текущим рабочим процессом, причина, по которой git status говорит вам об этом:

Ваша ветка и "происхождение/особенность" расходятся и имеют соответственно 27 и 2 разных коммита.

потому что в вашей ветке с измененной feature теперь есть 25 новых коммитов, которые недоступны из origin/feature (поскольку они произошли из rebase на master) плюс 2 фиксации, которые достижимы с origin/feature но имеют разные идентификаторы фиксации. Эти коммиты содержат те же самые изменения (т.е. Они эквивалентны патчу), но у них разные хэши SHA-1, поскольку они основаны на другой фиксации по origin/feature чем тот, который вы их переустановили в своем локальном репозитории.

Вот пример. Предположим, что это ваша история, прежде чем делать git pull on master:

A - B - C (master)
         \
          D - E (feature)

После git pull, master получил фиксацию F:

A - B - C - F (master, origin/master)
         \
          D - E (feature)

В этот момент вы переустанавливаете feature поверх master, которая применяет D и E:

A - B - C - F (master, origin/master)
             \
              D - E (feature)

Между тем, origin/feature удаленного ветки по-прежнему основывается на фиксации C:

A - B - C - F (master, origin/master)
         \   \
          \   D' - E' (feature)
           \
             D - E (origin/feature)

Если у вас git status на feature, Git покажет вам, что ваша feature филиал расходились от origin/feature с 3 (F, D' E') и 2 (D, E) совершающее соответственно.

Обратите внимание, что D' и E' содержат те же изменения, что и D и E но имеют разные идентификаторы фиксации, поскольку они были перегруппированы поверх F

Решение состоит в том, чтобы сделать git pull как на master и feature, прежде чем перебазирования feature на master. Однако, так как вы можете иметь фиксации на feature, которые вы еще не сдвинуты к origin, вы хотели бы сделать:

git checkout feature && git pull --rebase

чтобы избежать создания фиксации слияния между origin/feature и вашей локальной feature.

Обновление о последствиях перезагрузки:

В свете этого комментария я расширился на расходящихся ветвях. Причина, по которой git status сообщает о том, что feature и origin/feature отклоняются после переучета, связана с тем, что rebasing привносит новые коммиты в feature, а также перезаписывает коммиты, которые ранее были перенесены в origin/feature.

Рассмотрим ситуацию после тяги, но до перезагрузки:

A - B - C - F (master)
         \
          D - E (feature, origin/feature)

На этом этапе feature и origin/feature указывают на одно и то же совершение E -in другими словами, они находятся в "синхронизации". После восстановления feature поверх master история будет выглядеть так:

A - B - C - F (master)
         \   \
          \   D' - E' (feature)
           \
             D - E (origin/feature)

Как вы можете видеть, feature и origin/feature расходились, их общий предок - совершать C Это связано с тем, что теперь feature содержит новый фиксатор F от master плюс D' и E' (считанные как "D prime" и "E prime"), которые фиксируют D и E применяемые поверх F Несмотря на то, что они содержат те же самые изменения, Git считает их разными, потому что они имеют разные идентификаторы фиксации. Между тем, origin/feature все еще ссылаются на D и E

На этом этапе вы переписали историю: вы изменили существующие коммиты в силу их перезагрузки, эффективно создавая "новые".

Теперь, если вы хотите запустить git pull on feature это то, что произойдет:

A - B - C - F (master)
         \   \
          \   D' - E'- M (feature)
           \         /
             D - E - (origin/feature)

Поскольку git pull делает git fetch + git merge, это приведет к созданию слияния M, родителями которого являются E' и E

Если вместо этого вы git pull --rebase (то есть git fetch + git rebase), тогда Git будет:

  1. Переместить feature для фиксации C (общий предок feature и origin/feature)
  2. Примените D и E от origin/feature
  3. Примените F, D' и E'

Однако, заметив, что D' и E' содержат те же изменения, что и D и E, Git просто отбросит их, в результате чего история будет выглядеть так:

A - B - C - F (master)
         \   
          D - E - F' (feature)
              ^
             (origin/feature)

Обратите внимание, как фиксация F, ранее достижимая из feature, была применена поверх origin/feature привело к F'. На данный момент git status скажет вам следующее:

Ваш филиал опережает "происхождение/особенность" на 1 фиксацию.

Это совершение, конечно, F'.

Ответ 2

Если удаленные версии master и feature/branch обновляются по отдельности, просто перезагрузите локальную ветвь функций

git checkout feature/branch
git fetch origin feature/branch
git reset --hard origin/feature/branch

то, если вы хотите внести изменения в master ветку,

git rebase origin/master

Ответ 3

Каждый have 27 and 2 different commits each говорит вам, что теперь у вас есть 27 новых коммитов от master и 2 новых фиксации в вашей ветке, которые не присутствуют в origin/<yourbranch>.

Поскольку origin/<yourbranch> был массово изменен с помощью rebase, у него больше нет общей базы с origin/<yourbranch>. Поэтому вы не хотите, чтобы после origin/<yourbranch> вытащить изменения из origin/<yourbranch>, потому что, как видите, все H *** ломается.

Если вы знаете, что есть изменения в origin/<yourbranch> которые вам нужны в вашем локальном филиале, а затем потяните их, прежде чем переустанавливать.

Если вы уверены, что ни один из них не изменил origin/<yourbranch> со времени вашего последнего нажатия (безопасная ставка, если это ваша собственная ветвь функции), вы можете использовать push --force чтобы снова синхронизировать их. Тогда origin/<yourbranch> снова будет иметь ту же базу, что и ваша локальная ветвь, и эта база будет содержать все последние master изменения.

Ответ 4

Когда вы пересоздаете свою ветку функций поверх мастера, вы создали кучу новых коммитов. Тем не менее, ваша ветка origin/feature все еще указывает на старые. Это ситуация после перезагрузки:

C' (feature)
B'
A'
* (master, origin/master)
*
*
| C (origin/feature)
| B
| A
|/
* some base commit

Хотя commit A' содержит аналогичный набор изменений как commit A, это отнюдь не одно и то же. Он содержит другое дерево и имеет другого родителя.

Теперь, когда вы снова пытаетесь выполнить feature, вы пытаетесь создать эту историю:

* (feature)
|\
C'|
B'|
A'|
* | (master, origin/master)
* |
* |
| C (origin/feature)
| B
| A
|/
* some base commit

Вы объединяете две ветки, которые ввели очень похожие, реактивные изменения. Это связано с созданием тонны конфликтов, кроме того, что оно совершенно бессмысленно.

Что вам нужно сделать, это сообщить свое восходящее репо о rebase, используя git push -f. Это потеряет старую историю и заменит ее переписанной.

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