Как я могу восстановить / повторно синхронизировать после того, как кто-то отправит ребаз или сброс в опубликованную ветку?

Мы все слышали, что никогда нельзя перебазировать опубликованную работу, что она опасна и т. Д. Однако я не видел ни одного выложенного рецепта о том, как справиться с ситуацией в случае публикации перебазировки.

Теперь обратите внимание, что это действительно возможно, только если репозиторий клонируется только известной (и предпочтительно небольшой) группой людей, так что тот, кто нажимает на ребаз или сброс, может уведомить всех остальных, что им нужно будет обратить внимание в следующий раз, когда они выборки (!).

Одно очевидное решение, которое я видел, будет работать, если у вас нет локальных коммитов на 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*) приводит к конфликту.

Другие вопросы по тегам