2014-02-11 2 views
1

Я создал новую ветку и начал работать над нейФилиалы отделенные после старой фиксации редактировать

Z--A--B--C (master) 
      \-D--E (new-branch) 

Тогда я нормированный редактировать старые фиксации (A) в то же время на new-branch и мои ветви отделились

Z--A--B--C (master) 
\-A*--B--C--D--E (new-branch) (A* -> edited commit) 

Как я могу перевести их обратно в следующее состояние?

Z--A*--B--C (master) 
      \-D--E (new-branch) 

ответ

2

На самом деле, то, что у вас есть пост-Rebase это (я по буквам их B' и т.д., а не B* и т.д., так что, как представляется, более обычным способом написания этих):

Z - A - B - C <-- master 
    \ 
    A'- B'- C'- D'- E' <-- new-branch 

Это потому что rebase должен скопировать каждый старый фиксатор (или, точнее, скопировать большую часть его, за исключением измененных битов), чтобы изменить что-либо в нем, а после изменения фиксации A сделать A', он должен скопировать и изменить B, потому что новый B' отличается: B' имеет A' в качестве своего родителя, rath чем A. (Все остальное одно и то же, но изменение родителя требует создания целого нового коммита. К счастью, коммиты довольно крошечные: у них просто есть родители, временные метки и т. Д., Сообщение commit и один SHA-1 для «дерева», связанного с фиксации и мерзавец может повторно использовать старое дерево.)

Если вы хотите сохранить A' так, как это в настоящее время и он появится в истории для master, вам придется заново точку в master этикетка при фиксации C'.Это будет «отказаться от» совершить C (и ASCII искусство здесь теперь неуютно переполненный :-)):

Z - A - B - C  [abandoned] 
    \   .---------- master 
    A'- B'- C'- D'- E' <-- new-branch 

Это также означает, что кто-то, кто раньше видел, как вы «опубликовать» (или «рекламу "), что ваш master имел в виду, что у SHA-1 есть C, у вас будет« перезаписанная история »: commit C больше не отображается, а не B или A. Вместо этого теперь master указывает на C', что указывает на B', что указывает на A', что указывает на Z.

Конечно, то же самое верно для new-branch: вместо этого он указывал на E, но теперь он указывает на E'.

С другой стороны, возможно, вы действительно не хотите менять master. В этом случае у вас есть только два варианта: полностью отказаться от A' или с master и new-branch расходиться после совершения Z.

Давайте перейдем к каждой группе (за исключением последней опции, это легко: ничего не делайте, вот что у вас есть!).


Для повторной точки master, есть два простых (МОГ) пути:

  • Получить на ветке, а затем использовать git reset, которые (в большинстве своих рабочих режимах) будет меняться фиксации, к которой точки ветвления:

    git checkout master 
    git reset --hard new-branch~2 # point master to commit C' 
    

    (Как всегда с git reset --hard, быть очень осторожным, прежде чем запустить его, что вы на ветке вы хотите повторно установлен, то . D уже не ООН сохраняемых в-работа-дерева данных)

  • While не на ветке, используйте git branch -f принудительно переместить его:

    git branch -f master new-branch~2 # point master to commit C' 
    

Если вы дон Не хотите переместить master и хотите отказаться от A' и восстановить старый new-branch, есть несколько способов. Предполагая, что вы сейчас на нем и ничего не сделали с момента переустановки, специальное ref-name ORIG_HEAD будет указывать на исходное совершение E. Другими словами, мы можем нарисовать более полную картину оригинального после перебазирования ситуации, как это:

   D - E <-- ORIG_HEAD (copied from new-branch before rebase) 
      /
Z - A - B - C   <-- master 
    \ 
    A'- B'- C'- D'- E' <-- new-branch 

Итак:

  • Если вы на new-branch и хотите ип-ли ваш rebase, git reset --hard ORIG_HEAD сделает трюк. (Используйте ту же осторожность с --hard, как обычно.)

  • Если это слишком поздно для этого, вы можете найти совершить E в ваших reflogs и git reset --hard к сырому SHA-1, или с помощью reflog орфографии как [email protected]{yesterday} или [email protected]{3} или любых других.

  • Если вы не против копирования D' и E' пока-новая-копия, D'' и E'', вы можете повторно перебазироваться new-branch с более длинной формой перебазироваться с использованием --onto (который я вижу в Magnus Bäck's answer, который получил до этого).


reflog сохранит фиксации C на некоторое время, так что репо будет сохранять фиксации, пока запись reflog не истечет. Так что это не полностью заброшено или, по крайней мере, еще нет.

Это ORIG_HEAD «специальный» ссылка устанавливается при запуске нового перебазироваться, но и такие вещи, как git merge. Вы можете использовать git log ORIG_HEAD или аналогично, чтобы увидеть, где он на самом деле указывает, если вы не уверены.

+0

спасибо за подробный ответ, я, наконец, сделал 'git reset --hard new-branch ~ 2' – olanod

2

Ваше фактическое состояние после плохого Rebase это:

Z--A--B--C (master) 
\-A*--B*--C*--D*--E* (new-branch) 

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

Вам нужно будет переделать новую ветвь. Это вполне возможно, так просто, как это:

git rebase master 

Git автоматически пропустит применения коммитов B * и С *, так как они, вероятно, в конечном итоге пустой (если не совершить прикоснулся код, который они также коснулись, в этом случае» я получу конфликт). Если вы хотите, чтобы убедиться в только перебазироваться совершить D * и E *, ограничение которых фиксации подлежат перебазироваться и использовать --onto:

git rebase --onto master HEAD~2 

ГОЛОВА ~ 2 означает C * и представляет собой границу Rebase мы будем выбирать D * и E * и применять их к мастеру.

Смежные вопросы