воскресенье, 15 сентября 2013 г.

Как пользоваться git: тонкости

Прошла часть туториалов, находящихся вот тут. Разъяснилось несколько вещей (см. ниже).

Во-первых, ветки (бранчи) в Git не занимают много места, т.к. по сути это просто ссылки на конкретный commit и больше ничего. Во-вторых, ...

Merge vs Rebase

Команда merge создает специальный commit, у которого есть два уникальных родителя. Этот commit как бы говорит нам "я хочу включить в себя всю ту работу, которая была проделана при разработке обоих моих родителей и их родителей". Рассмотрим следующий пример.

Введем команду 
git merge bugFix
Получится вот что:



Теперь в master'е содержится вся выполненная работа. Теперь выполним такие команды:

git checkout bugFix
git merge master


Т.к. ветка bugFix находилась в дереве выше (то есть, менее актуальна), чем master, то ссылка bugFix просто передвинулась на тот же commit, на который указывает ветка master.

Команда rebase берет несколько commit'ов, копирует их, и помещает копии вниз под тем commit'ом, который мы укажем. Преимущество rebase в том, что он приводит историю commit'ов к линейному виду. Commit log/history будет выглядеть гораздо более красивым, чем до применения rebase. Рассмотрим следующий пример.


Допустим, мы хотим перенести то, что сделано в bugFix, чтобы в истории commit'ов все выглядело так, как будто мы не параллельно разрабатывали две фичи, а последовательно. Введем команду 

git rebase master

Получится вот что:
Создался новый commit с фичей из ветки bugFix, являющийся продолжением commit'а C2. Теперь у нас красивая линейная история commit'ов. Заметим, что commit C3 до сих пор где-то болтается (где именно, не написано было), а commit C3' как бы является его копией.

Теперь введем команды 

git checkout master
git rebase bugFix

Получится вот что:
Т.к. ветка master находилась в дереве выше, чем bugFix, т.е. была менее актуальна, то она просто передвинулась.

Reset vs Revert

Reset отменяет изменения путем переноса ссылки на предыдущий commit. Это как бы переписывание истории commit'ов. Пусть у нас вот такая история commit'ов:


Наберем команду

git reset HEAD~1

(HEAD это относительная ссылка на commit, на котором мы сейчас находимся. Оператор ~ позволяет прыгать по дереву commit'ов вверх или вниз на указанное количество шагов, в данном случае на 1)

Получится вот что:


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

Пусть у нас опять такая же ситуация, и мы хотим отменить последний commit:


Введем команду

git revert HEAD
И получится вот что:


Т.е. создался новый commit, аналогичный commit'у C1, не содержащий изменений, которые были в commit'е C2.

Cherry-pick

Эта команда позволяет более гибко перемещать commit'ы. Имеет следующий формат: cherry-pick <Commit i1><Commit i2>...<Commit ik>. Рассмотрим пример. Пусть у нас имеется вот такой репозиторий

 И мы хотим перенести в master все фичи, которые есть в commit'ах C3, C4, C7. Наберем команду

git cherry-pick C3 C4 C7

И получим желаемый результат:

И вот еще, про гигиену commit'ов:
  • Коммитить нужно часто, но атомарно (т.е. только законченные функции), также нужно подробно описывать, что в commit'е (иначе будет трудно поймать состояние проекта, будет трудно понять, куда нужно откатиться, если текущая версия не работает).
  • Не использовать git как систему бэкапа!

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

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