Показаны сообщения с ярлыком git rebase. Показать все сообщения
Показаны сообщения с ярлыком git rebase. Показать все сообщения

четверг, 19 февраля 2015 г.

Ветвление в Git - практика перемещения веток (часть 1)

Еще раз попрактикуемся с той же схемой коммитов, что и в прошлом посте.

basic-rebase-1

В коммитах C0, С1 и С2 у нас есть один файл test.txt, в который в каждом коммите мы последовательно добавляли по одной строке.

В коммите С2 этот файл выглядит так:

Rb0001

А история коммитов так:

Rb0002

Теперь в рабочий каталог добавим еще один файл testC3.txt и добавим его в коммит C3.

Rb0003

Сейчас мы уже ближе к блок схеме представленной в самом начале поста

Rb0004

У нас уже есть все коммиты в ветке master с С0 по С3, теперь нам надо как-то сделать ответвление от коммита С2.

Сделаем это так:

Rb0005

Мы переключились на коммит С2, добавили файл testC4.txt в рабочий каталог и сделали коммит С4.

Теперь дерево коммитов выглядит точно так, как на диаграмме в начале этого поста:

Rb0006

Коммиты С3 и С4 различаются только тем что в коммите С3 есть файл test3.txt, а в коммите С4 есть файл testC4.txt. Файл test.txt присутствует в обоих коммитах и абсолютно в них одинаков.

Содержимое рабочего каталога в коммите C4:

Rb0007

Теперь переключимся в ветку master и посмотрим содержимое рабочего каталога в коммите С3:

Rb0008

Надеюсь теперь все более менее понятно. Так что будем делать rebase. А до этого запомним что коммит С4 у нас имеет хэш 4f3c493. А так же что у нас имеется ветвление в истории коммитов.

Переходим в ветку experiment и выполняем там перемещение (rebase):

Rb0009

В этот раз у нас нет ни каких конфликтов и перемещение происходит гладко. Как видим изменения применились в коммите С4 и теперь это АБСОЛЮТНО НОВЫЙ коммит.

Теперь посмотрим рабочий каталог после операции перемещения:

Rb0010

Напомню что перед операцией перемещения мы перешли в ветку С4, и до операции перемещения там были только два файла test.txt и testC4.txt. После операции перемещения появился файл testC3, который приплыл сюда из коммита С3.

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

Все это кажется не особо понятным, но может эта диаграмма внесет ясность:

basic-rebase-3

Коммит С4, как бы перестал сущестовать, а вернее видоизменился и сейчас это абсолютно НОВЫЙ ДРУГОЙ коммит  (у него даже другой хэш) но с именем С4.

Это можно так же посмотреть и в логах коммитов Git:

Rb0011

Из истории коммитов так же видно, что ветвление исчезло. Что у коммита С4 другой хэш (был 4f3c493, а стал d78f51b).

Кроме того, стоит обратить внимание что ветка master по прежнему указывает на коммит С3 (который остался без изменений).

На этом этапе можно переключиться на ветку master и выполнить слияние-перемотку (fast-forward merge), то есть переместить указатель ветки master на коммит С4:

Rb0012

То есть мы пришли к вот такому виду истории коммитов:

basic-rebase-4

То же самое видим в логе коммитов:

Rb0013

Теперь ветку experiment можно вообще удалить, чтобы глаза не мозолила

Rb0014

Теперь у нас снова чистенькая веточка master.

По существу это то же самое, что в предыдущем посте, просто я исключил возникновение конфликтов, чтобы материал был более понятен и ясен.

Ветвление в Git - Перемещение

Перемещение

В Git'е есть два способа включить изменения из одной ветки в другую: merge (слияние) и rebase (перемещение). В этом разделе вы узнаете, что такое перемещение, как его осуществлять, почему это удивительный инструмент и в каких случаях вам не следует его использовать.

Основы перемещения

Если мы вернёмся назад к одному из ранних примеров про слияние, увидим, что мы разделили свою работу на два направления и сделали коммиты на двух разных ветках.

basic-rebase-1

R00001

Наиболее простое решение для объединения веток, как мы уже выяснили, команда merge. Эта команда выполняет трёхходовое слияние между двумя последними снимками состояний из веток (C3 и C4) и последним общим предком этих двух веток (C2), создавая новый снимок состояния (и коммит). Это продемонстрировано на диаграмме ниже:

basic-rebase-2

Однако, есть и другой путь: вы можете взять изменения, представленные в C3, и применить их поверх C4. В Git'е это называется перемещение (rebasing). При помощи команды rebase вы можете взять все изменения, которые попали в коммиты на одной из веток, и повторить их на другой.

Для этого примера надо выполнить следующее:

R00002

Так как у нас опять конфликт слияния то нас просят его разрешить самим.

Конфликт произошел опять из за четвертой строчки в файле test.txt

R00004

Если мы посмотрим сейчас статус то увидим:

R00005

Конфликт при перемещении тоже обычное явление. Я не стал мудрствовать лукаво и сделал просто так:

R00006

Перемещение работает следующим образом: находится общий предок для двух веток (на которой вы находитесь сейчас и на которую вы выполняете перемещение); для каждого из коммитов в текущей ветке берётся его дельта и сохраняется во временный файл; текущая ветка устанавливается на тот же коммит, что и ветка, на которую выполняется перемещение; и, наконец, одно за другим применяются все изменения.

basic-rebase-3

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

Сейчас ветка experiment тоже указывает на коммит C4, который сейчас уже является последним.

Кроме того хоть последний коммит и будет называться C4 это уже не тот же самый коммит что был до этого! У него даже другой хэш.

R00007

Если помните то, до перемещения у коммита C4 был хэш fa5f2e6, а сейчас у коммита С4 хэш cafbd94.

Ветка же master, по прежнему указывает на тот же коммит С3, что и был до перемещения.

И еще один момент, для коммита С4 после перемещения родителем стал коммит С3, а до этого был С2.

На этом этапе можно переключиться на ветку master и выполнить слияние-перемотку (fast-forward merge)

R00008

Эти две команды просто переместили указатель ветки master на тот же коммит С4, на который указывает и ветка experiment.

basic-rebase-4

R00009

Нет никакой разницы в конечном результате объединения и перемещения, но перемещение выполняется для того, чтобы история была более аккуратной.

Как вы видите лог перемещённой ветки выглядит как линейная история работы: кажется, что вся работа выполнялась последовательно, когда в действительности она выполнялась параллельно.

Возможные риски перемещения

Всё бы хорошо, но кое-что омрачает всю прелесть использования перемещения. Это выражается одной строчкой:

Не перемещайте коммиты, которые вы уже отправили в публичный репозиторий.

Если вы будете следовать этому указанию, всё будет хорошо. Если нет — люди возненавидят вас, вас будут презирать ваши друзья и семья.

Если вы рассматриваете перемещение как возможность наведения порядка и работы с коммитами до того, как выложили их, и если вы перемещаете только коммиты, которые никогда не находились в публичном доступе — всё нормально. Если вы перемещаете коммиты, которые уже были представлены для общего доступа, и люди, возможно, основывали свою работу на этих коммитах, тогда вы можете получить наказание за разные неприятные проблемы.

Более подробно почему нельзя перемещать коммиты отправленные в публичный репозиторий можно почитать тут.

Что и как использовать лично вам для работы с историей коммитов в гим вы можете выбрать сами. Тут нет правил. Git мощная штука и одних и тех же вещей можно добиться разными путями. Все решать вам.