четверг, 27 июня 2013 г.

Git: Изменение последовательности коммитов

Итак, есть некий сайт/магазин и необходимо сделать кустому. Сливаем сайт, заводим в git, коммитаем кустому. А потом оказывается, что сайт за это время изменился. Сливаем сайт и коммитаем изменения в репозитарий. Может так получится, что "затрётся" кустома (в истории коммитов она, конечно, останется).
Задача, перенести кустому поверх изменённого сайта.


Ситуаций 1, всё в одной ветке, кустома и изменения с живого сайта - по одному коммиту:
A - B - C - D(HEAD,master)

(С - кустома, D - изменения с живого сайта)
Необходимо сделать так:
A - B - D - С(HEAD,masetr)

Решение (на самом деле их несколько, но в такой ситуации удобнее это):
$ git rebase -i HEAD~2
(HEAD~2 - на два коммита назад от HEAD)

Откроется редактор со списком коммитов. там с ними можно делать всё что угодно (удалять, сливать, переименовывать, но самое главное - переставлять местами в произвольной последовательности; последовательность сверху вниз)

Было:
pick e3cbda0 C
pick bae8d0c D

Меняем на:
pick bae8d0c D
pick e3cbda0 C

После редактирования списка, сохранения и выхода из редактора git попытается применить изменения и скорее всего выдаст ошибку:
error: could not apply e08371e... D

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Could not apply e08371e... D

При этом не понятно, в чем проблема, но это можно узнать:
$ git rebase --continue 
test.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add

Тут есть важный момент, нужно привести файл в состояние живого сайта, без изменений нашей кустомы. При не аккуратном исправлении коллизий могут пропасть коммиты (не изменения, а записи в последовательности коммитов, то есть git просто их сольёт в один)
После редактирования и сохранения файла, добавляем изменения (git add -u [файл]) и продолжаем процесс rebase
$ git rebase --continue

Если конфликтов больше не будет, то откроется редактор с возможность изменить описание коммита (на данном этапе речь о коммите D).
Процедура повторится с коммитом C.
Всё, коммиты пересавлены.

Другая ситуация, если коммитов больше, то есть кустома состоит из ряда коммитов, плюс с живого сайта обновление тоже пришло несколькими коммитами:
A - B - C - D - E - F - G - H(HEAD,master)
(A-B - старая версия, C-D-E - кустома, F-G-H - новый сайт)

В таком случае удобнее разделить всё на ветки, переставить, а потом обратно перекинуть в master. При этом, скорее всего на ветки всё уже может быть разделено, если кустома и новый сайт коммитались сразу в разные ветки.

Сначала выделяем старый сайт в master, а все остальное в кустому (потом будет понятно почему так)
$ git branch custom
$ git reset --hard HEAD~6

Создается новый бранч который соответсвует master, затем из masetr (так как при создании бранча HEAD не изменился) удаляется 6 коммитов (они всё еще остались в custom!):

A - B(HEAD,master)
     \
      C - D - E - F - G - H(custom)

Далее переходим в custom и отделяем изменения с живого сайта
$ git checkout custom
$ git branch live
$ git reset --hard HEAD~3

A - B(master)
     \
      C - D - E(HEAD,custom)
               \
                F - G - H(live)

Переносим live из custom в master
$ git rebase --onto master custom live
(после --onto первый параметр - откуда переносить, второй - куда переносить, третий - что переносить) Тут как и в первой ситуации могут быть конфликты, решаются так же, но не будет открываться редактор, так как ни чего переименовывать нельзя.

Результат:
      F - G - H(HEAD,live)       
     /
A - B(master)
     \
      C - D - E(custom)

Повторяем перенос, но только уже переносим custom в live
$ git rebase --onto live master custom

                C - D - E(HEAD,custom)
               /
      F - G - H(live)       
     /
A - B(master)


Готово! При необходимости можно всё объединить (не слить!) в master
$ git branch -f master custom
$ git checkout master
$ git branch -d custom
$ git branch -d live

A - B - F - G - H - C - D - E(HEAD,master)

Комментариев нет:

Отправить комментарий