(Edit, 30 ноября 2016: Смотри также this answer к Why is git rebase discarding my commits? Теперь уже практически уверен, что это связано с опцией вилочного точки.).
Там - несколько отличий между руководством и pull
- git rebase
(меньше в 2.7, чем в версиях git, предшествующих --fork-point
в git merge-base
). И, я подозреваю, что ваши автоматические сбережения-слияния могут быть задействованы. Это немного сложно убедиться, но тот факт, что ваш локальный филиал следует за вашим другим местным филиалом, который получает пересылку, весьма наводящий на размышления. Тем временем старый сценарий git pull
был также переписан в C недавно, поэтому сложнее увидеть, что он делает (хотя вы можете установить переменную окружения GIT_TRACE
на 1
, чтобы git показывал вам команды, когда они запускают их внутри).
В любом случае, есть два или три ключевых пунктов здесь (в зависимости от того, как вы считаете, и разделить их, я сделаю это в 3):
git pull
работает git fetch
, то либо git merge
или git rebase
в соответствии с инструкциями, но когда он запускается git rebase
, он использует новый механизм fork-point для «восстановления с восходящей ребазы».
Когда git rebase
запущен без аргументов, у него есть специальный футляр, который вызывает машины для токарной обработки. При запуске с аргументами механизм fork-point отключается, если явно не запрашивается с --fork-point
.
Когда git rebase
поручено сохранять слияния, он использует интерактивный код переустановки (не интерактивно). Я не уверен, что это действительно имеет значение здесь (отсюда «может быть задействовано» выше). Обычно он сглаживает слияния, и только для интерактивного скрипта сводки есть код для их сохранения (этот код действительно повторяет слияния, поскольку нет другого способа справиться с ними).
Самый важный пункт здесь (обязательно) - код точки вилки. Этот код использует reflog для обработки случаев, наилучшим образом отображаемых путем рисования части графика фиксации.
В нормальном (без точки вил материала необходим) перебазироваться случае у вас есть что-то вроде этого:
... - A - B - C - D - E <-- origin/foo
\
I - J - K <-- foo
где A
и B
являются совершившим вас, когда вы начали свой филиал (так что B
является merge- основание), через E
- это новые коммиты, которые вы выбрали с пульта дистанционного управления через git fetch
, а I
через K
- ваши собственные коммиты. Коды пересчета копируются I
по номеру K
, прилагается первый экземпляр до E
, второй экземпляр-номер I
, а третий - копия J
.
Гит выяснит или раньше, anyway- который совершающего скопировать с помощью git rev-list origin/foo..foo
, то есть, используя имя текущей ветви (foo
), чтобы найти K
и работать в обратном направлении, и имя его вверх по течению (origin/foo
), чтобы найти E
и работать в обратном направлении. Назад марш останавливается на базе слияния, в этом случае B
и скопированный результат выглядит следующим образом:
... - A - B - C - D - E <-- origin/foo
\ \
\ I' - J' - K' <-- foo
\
I - J - K [[email protected]{1}: reflog for foo]
Проблема с этим методом возникает, когда origin/foo
здесь расположенные в верхнем-сама нормированный. Предположим, например, что на origin
кто-то силой нажал так, что B
был заменен новой копией B'
с другой формулировкой фиксации (и, возможно, другим деревом, но, мы надеемся, ничего не скажется на нашем I
-through-K
).Отправная точка теперь выглядит следующим образом:
B' - C - D - E <-- origin/foo
/
... - A - B <-- [origin/[email protected]{n}]
\
I - J - K <-- foo
Используя git rev-list origin/foo..foo
, мы бы выбрать фиксации B
, I
, J
и K
быть скопированы, и попытаться вставить их после E
, как обычно; но мы не хотим, чтобы скопировать B
так как он действительно исходил от origin
и был заменен на свою собственную копию B'
.
Что представляет собой код точки прокрутки, это посмотреть на reflog для origin
, чтобы узнать, удалось ли добраться до B
. То есть, он проверяет не только origin/master
(поиск E
и сканирование обратно в B'
и затем A
), но и origin/[email protected]{1}
(указывая непосредственно B
, вероятно, в зависимости от того, как часто вы запускаете git fetch
), origin/[email protected]{2}
, и так далее. Любые фиксации на foo
, которые достижимы от любыеorigin/[email protected]{n}
включены для рассмотрения при поиске узла Lowest Common Ancestor на графике (т. Е. Все они рассматриваются как опции, чтобы стать базой слияния, которую выдает git merge-base
).
(Здесь стоит отметить такой дефект: это автоматическое обнаружение точек разметки может обнаруживать только те коммиты, которые были доступны в течение времени, в течение которого сохраняется запись reflog, которая в этом случае по умолчанию составляет 30 дней. Однако это не особенно отношение к вашему вопросу)
в вашем случае, у вас есть три имена ветвей (и, следовательно, три reflogs) участвуют:.
origin/master
, который обновляется git fetch
(первый шаг ваш git pull
в то время как филиал master
)
master
, которая обновляется с помощью и вы (с помощью обычных фиксаций) и git rebase
(на втором этапе вашего git pull
) и
feature
, который обновляется обоими вы (через обычные коммиты) и git rebase
(второй шаг вашего второйgit pull
: вы «забираете» себя, нет-op, затем переустанавливаете feature
на master
).
Оба rebases выполняются с --preserve-merges
(и, следовательно, не взаимодействующим интерактивным режимом) и --onto new-tipfork-point
, где fork-point
фиксацией ID найдено, запустив git merge-base --fork-point upstream-name HEAD
. upstream-name
для первого Rebase является origin/master
(ну, refs/remotes/origin/master
) и upstream-name
для второго Rebase является master
(refs/heads/master
).
Это должно быть все Just Work.Если ваша фиксация графика в начале всего процесса что-то вроде того, что вы описали:
... - A - B <-- master, origin/master
\
I - J - K <-- feature
тогда первый fetch
приносит в некоторых фиксаций и делает origin/master
точку на новый наконечник:
C - D - E <-- origin/master
/
... - A - B <-- master, origin/[email protected]{1}
\
I - J - K <-- feature
и первый Rebase то ничего не находит для копирования (слияние-основание master
и B
- B
= вилка-точка (мастер, происхождения/мастер) -это просто B
так что нет ничего, чтобы скопировать), что дает:
C - D - E <-- master, origin/master
/
... - A - B <-- [email protected]{1}, origin/[email protected]{1}
\
I - J - K <-- feature
Вторая выборка - от вас самих и без-op/пропущена полностью, оставив это как вход во вторую перезагрузку. --onto
цели master
который совершает E
и вилку-точку HEAD
(feature
) и master
также совершают B
, оставляя фиксации I
через K
скопировать после E
, как обычно.
Если какой-либо фиксатор (ы) отбрасывается, в этом процессе что-то происходит не так, но я не вижу, что.
Вы не должны перегружать ветвь удаленного отслеживания 'origin/master', а вы пытаетесь перенести это вперед, не затрагивая вашу (отслеживающую) копию этого пульта. Я не проверял руководства для правильных вызовов, но, возможно, check -b, которые связаны с новым временным именем, и переустановка временной ветви на ваш текущий HEAD. –
Я думаю, здесь есть какая-то путаница. Я не перезаряжаю 'origin/master', но переустанавливаю текущую ветку' master' на 'origin/master'. Это должно, по моему мнению, по существу довести 'HEAD' до конца' origin/master' и повторно использовать фиксации, которые были на кончике 'master' обратно в ветку. По существу, переписывать новые коммиты на 'master', как если бы они произошли после изменений из' origin/master'. – ashays
Какая у вас (локальная) версия git? Я спрашиваю, потому что я помню (несколько неопределенно и еще не вернулся к проверке), что в нескольких версиях 2.x была автоматизированная ошибка перебора басов в «git pull», и, зная, что версия может сделать проверку на это немного проще. – torek