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


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

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

одно очевидное решение, которое я видел, будет работать, если у вас нет локальных коммитов на foo и он получает rebased:

git fetch
git checkout foo
git reset --hard origin/foo

Это будет просто выбросить местное состояние foo в пользу его истории в соответствии с удаленным репозиторием.

но как можно справиться с ситуацией, если вы совершили существенные локальные изменения в этой отрасли?

3 82

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' приводит к конфликту, и если патч-идентичные коммиты не определены правильно, то picking C на ветку, содержащую D (или, что эквивалентно D*) приводит к конфликту.