Как я могу восстановить / повторно синхронизировать после того, как кто-то отправит ребаз или сброс в опубликованную ветку?
Мы все слышали, что никогда нельзя перебазировать опубликованную работу, что она опасна и т. Д. Однако я не видел ни одного выложенного рецепта о том, как справиться с ситуацией в случае публикации перебазировки.
Теперь обратите внимание, что это действительно возможно, только если репозиторий клонируется только известной (и предпочтительно небольшой) группой людей, так что тот, кто нажимает на ребаз или сброс, может уведомить всех остальных, что им нужно будет обратить внимание в следующий раз, когда они выборки (!).
Одно очевидное решение, которое я видел, будет работать, если у вас нет локальных коммитов на foo
и это будет перебазировано:
git fetch
git checkout foo
git reset --hard origin/foo
Это просто выбросит местное foo
в пользу своей истории согласно удаленному хранилищу.
Но как справиться с ситуацией, если в этой отрасли произошли существенные локальные изменения?
3 ответа
Возврат в синхронизацию после принудительной перебазировки в большинстве случаев не так уж и сложен.
git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo
То есть. сначала вы устанавливаете закладку для того места, где изначально находилась удаленная ветвь, а затем используете ее для воспроизведения ваших локальных коммитов с этой точки в перебазированную удаленную ветвь.
Перебазирование - это как насилие: если оно не решит вашу проблему, вам просто нужно больше. ☺
Вы можете сделать это без закладки, конечно, если вы посмотрите предварительную перебазирование origin/foo
зафиксировать идентификатор и использовать его.
Это также, как вы справляетесь с ситуацией, когда вы забыли сделать закладку перед загрузкой. Ничего не потеряно - вам просто нужно проверить reflog для удаленной ветки:
git reflog show origin/foo | awk '
PRINT_NEXT==1 { print $1; exit }
/fetch: forced-update/ { PRINT_NEXT=1 }'
Это напечатает идентификатор фиксации, который origin/foo
указал на самый последний выбор, который изменил его историю.
Вы можете тогда просто
git rebase --onto origin/foo $commit foo
Я бы сказал, что раздел восстановления исходной версии на странице руководства git-rebase охватывает почти все это.
Это на самом деле ничем не отличается от восстановления вашей собственной перебазировки - вы перемещаете одну ветку и перемещаете все ветки, которые имели ее в своей истории, на новую позицию.
Начиная с git 1.9/2.0 Q1 2014, вам не нужно будет отмечать свое предыдущее происхождение ветки, прежде чем перебазировать его в переписанной ветке восходящего потока, как описано в Aristotle Pagaltzis:
Смотрите коммит 07d406b и коммит d96855f:
После работы над
topic
ветка создана сgit checkout -b topic origin/master
, история удаленного отслеживания веткиorigin/master
могли быть перемотаны и перестроены, что привело к истории этой формы:
o---B1
/
---o---o---B2--o---o---o---B (origin/master)
\
B3
\
Derived (topic)
где
origin/master
используется для указания на коммитыB3
,B2
,B1
и теперь он указывает наB
, и вашtopic
ветвь была начата сверху, когдаorigin/master
был вB3
,Этот режим использует рефлог
origin/master
найтиB3
в качестве точки разветвления, так чтоtopic
может быть перебазирован поверх обновленногоorigin/master
от:
$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic
Вот почему git merge-base
Команда имеет новую опцию:
--fork-point::
Найдите точку, в которой ветвь (или любая история, которая ведет к
<commit>
) разветвляется из другой ветки (или любой ссылки)<ref>
,
Это не только ищет общего предка двух коммитов, но и учитывает рефлог<ref>
чтобы увидеть, если история ведет к<commit>
раздвоенный от более раннего воплощения ветви<ref>
,
"
git pull --rebase
msgstr "команда вычисляет точку ветвления перебазируемой ветви, используя записи reflog"base
"ветвь (обычно ветвь удаленного отслеживания), на которой была основана работа ветки, чтобы справиться со случаем, когда" базовая "ветвь была перемотана и перестроена.
Например, если история выглядела как где:
- текущий совет "
base
"Филиал находится наB
, но ранее fetch заметил, что его наконечник раньшеB3
а потомB2
а потомB1
прежде чем перейти к текущему коммиту, и- ветвь, перебазируемая поверх последней "базы", основана на коммите
B3
,он пытается найти
B3
пройдя через вывод "git rev-list --reflog base
"(то естьB
,B1
,B2
,B3
до тех пор, пока он не найдет коммит, который является предком текущей подсказкиDerived (topic)
".Внутренне мы имеем
get_merge_bases_many()
который может вычислить это за один раз.
Мы хотели бы объединить базу междуDerived
и фиктивный коммит слияния, который получился бы в результате слияния всех исторических подсказок "base (origin/master)
".
Когда такой коммит существует, мы должны получить один результат, который точно соответствует одной из записей reflog:base
".
Git 2.1 (3 квартал 2014 г.) добавит, чтобы сделать эту функцию более надежной: см. Commit 1e0dacd от John Keeping ( johnkeeping
)
правильно обработать сценарий, в котором мы имеем следующую топологию:
C --- D --- E <- dev
/
B <- master@{1}
/
o --- B' --- C* --- D* <- master
где:
B'
это исправленная версияB
это не совпадает с патчемB
;C*
а такжеD*
патч-идентичныеC
а такжеD
соответственно и конфликтуют текстуально, если применяются в неправильном порядке;E
зависит от текстаD
,
Правильный результат git rebase master dev
в том, что B
определяется как точка разветвления dev
а также master
, чтобы C
, D
, E
коммиты, которые нужно воспроизвести на master
; но C
а также D
патч-идентичные с C*
а также D*
и так может быть отброшено, так что конечный результат:
o --- B' --- C* --- D* --- E <- dev
Если точка разветвления не определена, то комплектация B
на ветку, содержащую B'
приводит к конфликту, и если идентичные исправления коммиты не идентифицированы правильно, то выбор C
на ветку, содержащую D
(или эквивалентно D*
) приводит к конфликту.