Как я могу восстановить / повторно синхронизировать после того, как кто-то нажимает rebase или сброс в опубликованную ветвь?
мы все слышали, что никогда не следует перебазировать опубликованную работу, что это опасно и т. д. Однако я не видел никаких рецептов, опубликованных для того, как справиться с ситуацией в случае перебазирования и опубликовано.
Теперь обратите внимание, что это действительно возможно только в том случае, если репозиторий клонируется только известной (и предпочтительно небольшой) группой людей, так что тот, кто нажимает rebase или reset, может уведомить всех остальных, что им нужно будет обратить внимание в следующий раз принести(!).
одно очевидное решение, которое я видел, будет работать, если у вас нет локальных коммитов на foo
и он получает rebased:
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
Ie. сначала вы настраиваете закладку для того, где изначально была удаленная ветвь, а затем используете ее для воспроизведения локальных коммитов с этой точки На перебазированную удаленную ветвь.
перебазирование как насилие: если это не решает вашу проблему, вам просто нужно больше. ☺
вы можете сделать это без закладок конечно, если вы посмотрите предварительно перебазировать
origin/foo
commit ID, и использовать его.Это также, как вы справляетесь с ситуацией, когда вы забыли сделать закладку до выборки. Ничего не потеряно – нужно просто проверить reflog для удаленного филиала:
git reflog show origin/foo | awk ' PRINT_NEXT==1 { print ; exit } /fetch: forced-update/ { PRINT_NEXT=1 }'
это выведет идентификатор фиксации, который
origin/foo
указал перед самой последней выборкой, которая изменила свою историю.вы можете тогда просто
git rebase --onto origin/foo $commit foo
Это действительно ничем не отличаются от восстановления из своего собственного перебазировать - переместить одну ветку, и перебазировать все ветви, которые были в их истории на своей новой должности.
начиная с git 1.9 / 2.0 Q1 2014, вам не нужно будет отмечать свое предыдущее происхождение ветви, прежде чем перебазировать его на переписанную восходящую ветвь, как описано в Аристотель Pagaltzis ' s ответ:
Смотрите commit 07d406b и commit 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
.этот режим использует reflog из
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>
.
Это не просто поиск общего предка двух коммитов, но также учитывает reflog из<ref>
чтобы увидеть, если история приводит к<commit>
раздвоенный от более раннего воплощение ветви<ref>
.
"
git pull --rebase
команда" вычисляет точку развилки ветви перебазированы с помощью записи reflog для "base
" ветвь (обычно ветвь удаленного отслеживания) работа ветви была основана на том, чтобы справиться с тем случаем, когда "базовая" ветвь была перемотана и перестроена.например, если история выглядела так:
- текущий наконечник "
base
филиал" находится вB
, но ранее fetch заметил, что его наконечник раньше былB3
а тоB2
а тоB1
прежде чем перейти к текущей фиксации, и- ветвь, которая перебазируется поверх последней "базы", основана на commit
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 (Q3 2014) добавит сделайте эту функцию более надежной для этого: см. commit 1e0dacd by 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'
приводит к конфликту, и если патч-идентичные коммиты не определены правильно, то pickingC
на ветку, содержащуюD
(или, что эквивалентноD*
) приводит к конфликту.