Как я могу восстановить / повторно синхронизировать после того, как кто-то нажимает 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-fooIe. сначала вы настраиваете закладку для того, где изначально была удаленная ветвь, а затем используете ее для воспроизведения локальных коммитов с этой точки На перебазированную удаленную ветвь.
перебазирование как насилие: если это не решает вашу проблему, вам просто нужно больше. ☺
вы можете сделать это без закладок конечно, если вы посмотрите предварительно перебазировать
origin/foocommit 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*) приводит к конфликту.