MyTetra Share
Делитесь знаниями!
Устройство для контроля эксплуатационных параметров radek-lab.ru.
Git Wizardry
10.08.2009
23:03
Текстовые метки: Git, разработка, workflow
Раздел: Компьютер - Программирование - Системы контроля версий (VCS) - Git


1 Введение


В своей прошлой заметке я постарался осветить в общих чертах стиль работы с распределенной системой контроля версий git и указать на отличия по сравнению с классическими централизованными СКВ. Целью было прежде всего обобщение опыта работы с системой без упоминания тонкостей синтаксиса отдельных команд.


Данный же топик задумывался как непосредственное введение в работу с git, нечто среднее между tutorial и обобщенной справкой, до которого все же рекомендуется прочитать упомянутое выше введение. Сознательно избегаются технические подробности работы git, употребляются только общие для СКВ термины и ограничивается список упоминаемых команд.



2 Работа с локальным репозитарием


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



2.1 Базовые команды


Базовые команды — те, без которых невозможно обойтись в разработке.



2.1.1 git init — создание репозитария


Команда git init создает в директории пустой репозитарий в виде директория .git, где и будет в дальнейшем храниться вся информация об истории коммитов, тегах — ходе разработки проекта:


mkdir project-dir


cd project-dir


git init


Другой способ создать репозитарий — команда git clone, но о ней чуть позже.



2.1.2 git add и git rm — индексация изменений


Следующее, что нужно знать — команда git add. Она позволяет внести в индекс — временное хранилище — изменения, которые затем войдут в коммит. Примеры использования:


git add EDITEDFILE


— индексация измененного файла, либо оповещение о

создании нового.


git add.


— внести в индекс все изменения, включая новые файлы.


Из индекса и дерева одновременно проекта файл можно удалить командой git rm:


git rm FILE1 FILE2


— удаление отдельных файлов


git rm Documentation/\*.txt


— хороший пример удаления из документации к git, удаляются сразу все файлы txt из папки.


Сбросить весь индекс или удалить из него изменения определенного файла можно командой git reset:


git reset


— сбросить нафиг весь индекс.


git reset - EDITEDFILE


— удалить из индекса конкретный файл.


Команда git reset используется не только для сбрасывания индекса, поэтому дальше ей будет уделено гораздо больше внимания.



2.1.3 git status — состояние проекта, измененные и не добавленные файлы, индексированные файлы


Команда git status, пожалуй, можно считать самой часто используемой наряду с командами коммита и индексации. Она выводит информацию обо всех изменениях, внесенных в дерево директорий проекта по сравнению с последним коммитом рабочей ветки; отдельно выводятся внесенные в индекс и неиндексированные файлы. Использовать ее крайне просто:


git status


Кроме того, git status указывает файлы с неразрешенными конфликтами слияния и файлы, игнорируемые git.



2.1.4 git commit — совершение коммита


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


git commit


Если индекс не пустой, то на его основе будет совершен коммит, после чего пользователя попросят прокомментировать вносимые изменения вызовом команды edit(например, в Ubuntu обычно вызывается простенький текстовый редактор nano, у меня же — emacs). Сохраняемся, и вуала! Коммит готов.


Есть несколько ключей, упрощающих работу с git commit:


  • git commit -a — совершит коммит, автоматически индексируя изменения в файлах проекта. Новые файлы при этом индексироваться не будут! Удаление же файлов будет учтено.
  • git commit -m "commit comment" — комментируем коммит прямо из командной строки вместо текстового редактора.
  • git commit FILENAME — внесет в индекс и создаст коммит на основе изменений единственного файла.



2.1.5 git reset — возврат к определенному коммиту, откат изменений, «жесткий» или «мягкий»


Помимо работы с индексом (см. выше), git reset позволяет сбросить состояние проекта до какого-либо коммита в истории. В git данное действие может быть двух видов: «мягкого»(soft reset) и «жесткого» (hard reset).


«Мягкий» (с ключом "--soft") резет оставит нетронутыми ваши индекс и все дерево файлов и директорий проекта, вернется к работе с указанным коммитом. Иными словами, если вы обнаруживаете ошибку в только что совершенном коммите или комментарии к нему, то легко можно исправить ситуацию:


1. git commit…


— некорректный коммит;


2. git reset --soft HEAD^


— переходим к работе над уже совершенным коммитом, сохраняя все состояние проекта и проиндексированные файлы


3. edit WRONGFILE


4. edit ANOTHERWRONGFILE


5. add.



6.1. git commit -c ORIG_HEAD


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



6.2. git commit -C ORIG_HEAD


Обратите внимание на обозначение HEAD^, оно означает «обратиться к предку последнего коммита». Подробней описан синтаксис такой относительной адресации будет ниже, в разделе «Хэши, тэги, относительная адресация». Соответственно, HEAD — ссылка на последний коммит. Ссылка ORIG_HEAD после «мягкого» резета указывает на оригинальный коммит.


Естественно, можно вернуться и на большую глубину коммитов,


«Жесткий» резет (ключ --hard) — команда, которую следует использовать с осторожностью. Git reset --hard вернет дерево проекта и индекс в состояние, соответствующее указанному коммиту, удалив изменения последующих коммитов:


1. git add.


2. git commit -m «destined to death»


3. git reset --hard HEAD~1


— больше никто и никогда не увидит этот позорный коммит.


4. git reset --hard HEAD~3


— вернее, три последних коммита. Никто. Никогда.



Если команда достигнет точки ветвления, удаления коммита не произойдет.


Для команд слияния или выкачивания последних изменений с удаленного репозитария примеры резета будут приведены в соответствующих разделах.



2.1.6 git revert — отмена изменений, произведенных в прошлом отдельным коммитом


Возможна ситуация, в которой требуется отменить изменения, внесенные отдельным

коммитом. Git revert создает новый коммит, накладывающий обратные изменения:


git revert config-modify-tag


— отменяем коммит, помеченный тегом.


git revert cgsjd2h


— отменяем коммит, используя его хэш.


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



2.1.7 git log — разнообразная информация о коммитах в целом, по отдельным файлам и различной глубины погружения в историю


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


Простейший пример использования, в котором приводится короткая справка по всем коммитам, коснувшимся активной в настоящий момент ветки (о ветках и ветвлении подробно узнать можно ниже, в разделе «Ветвления и слияния»):


git log


Получить подробную информацию о каждом в виде патчей по файлам из коммитов можно, добавив ключ -p (или -u):


git log -p


Статистика изменения файлов, вроде числа измененных файлов, внесенных в них строк, удаленных файлов вызывается ключом --stat:


git log --stat


За информацию по созданиям, переименованиям и правам доступа файлов отвечает ключ --summary:


git log --summary


Для исследования истории отдельного файла достаточно указать в виде параметра его имя (кстати, в моей старой версии git этот способ не срабатывает, обязательно добавлять " — " перед «README»):


git log README


или, если версия git не совсем свежая:


git log


— README


Далее будет приводится только более современный вариант синтаксиса. Возможно указывать время, начиная в определенного момента («weeks», «days», «hours», «s» и так далее):


git log --since=«1 day 2 hours» README


git log --since=«2 hours» README


git log --since=«2 hours» dir/


— изменения, касающиеся отдельной папки.


Можно отталкиваться от тегов:


git log v1…


— все коммиты, начиная с тега v1.


git log v1… README


— все коммиты, включающие изменения файла README, начиная с тега v1.


git log v1..v2 README


— все коммиты, включающие изменения файла README, начиная с тега v1 и заканчивая тегом v2.


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


Интересные возможности по формату вывода команды предоставляет ключ --pretty:


git log --pretty=oneline


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


git log --pretty=short


— лаконичная информация о коммитах, приводятся только автор и комментарий


git log --pretty=full/fuller


— более полная информация о коммитах, с именем автора, комментарием, датой создания и внесения коммита


В принципе, формат вывода можно определить самостоятельно:


git log --pretty=format:'FORMAT'


Определение формата можно поискать в разделе по git log из Git Community Book или справке. Красивый ASCII-граф коммитов выводится с использованием ключа --graph.



2.1.8 git diff — отличия между деревьями проекта; коммитами; состоянием индекса и каким-либо коммитом.


Своего рода подмножеством команды git log можно считать команду git diff,

определяющую изменения между объектами в проекте: деревьями (файлов и

директорий):


git diff


— покажет изменения, не внесенные в индекс.


git diff --cached


— изменения, внесенные в индекс.


git diff HEAD


— изменения в проекте по сравнению с последним коммитом


git diff HEAD^


— предпоследним коммитом


Можно сравнивать «головы» веток:


git diff master..experimental


Ну или активную ветку с какой-либо:


git diff experimental



2.1.9 git show — показать изменения, внесенные отдельным коммитом


Посмотреть изменения, внесенные любым коммитом в истории можно командой git

show:


git show COMMIT_TAG



2.1.10 git blame и git annotate — вспомогательные команды, помогающие отслеживать изменения файлов


При работе в команде часто требуется выяснить, кто именно написал конкретный код. Удобно использовать команду git blame, выводящую построчную информацию о последнем коммите, коснувшемся строки, имя автора и хэш коммита:


git blame README


Можно указать и конкретные строки для отображения:


git blame -L 2,+3 README


— выведет информацию по трем строкам, начиная со второй.


Аналогично работает команда git annotate, выводящая и строки, и информацию о коммитах, их коснувшихся:


git annotate README



2.1.11 git grep — поиск слов по проекту, состоянию проекта в прошлом


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


git grep tst


— поиск слова tst в проекте.


git grep -с tst


— подсчитать число упоминаний tst в проекте.


git grep tst v1


— поиск в старой версии проекта.


Команда позволяет использовать логическое И и ИЛИ:


git grep -e 'first' --and -e 'another'


— найти строки, где упоминаются и первое слово, и второе.


git grep --all-match -e 'first' -e 'second'


— найти строки, где встречается хотя бы одно из слов.



2.2 Ветвление


Операции ветвления и слияния — сердце и душа git, именно эти возможности делают такой удобной работу с системой.



2.2.1 git branch — создание, перечисление и удаление веток


Работа с ветками — очень легкая процедура в git, все необходимые механизмы сконцентрированы в одной команде:


git branch


— просто перечислит существующие ветки, отметив активную.


git branch new-branch


— создаст новую ветку new-branch.


git branch -d new-branch


— удалит ветку, если та была залита (merged) с разрешением возможных конфликтов в текущую.


git branch -D new-branch


— удалит ветку в любом случае.


git branch -m new-name-branch


— переименует ветку.


git branch --contains v1.2


— покажет те ветки, среди предков которых есть определенный коммит.



2.2.2 git checkout — переключение между ветками, извлечение отдельных файлов из истории коммитов


Команда git checkout позволяет переключаться между последними коммитами (если упрощенно) веток:


git checkout some-other-branch



А команда:


git checkout -b some-other-new-branch



создаст ветку, и сразу переключится на нее.



Если в текущей ветке были какие-то изменения по сравнению с последним коммитом в ветке(HEAD), то команда откажется производить переключение, дабы не потерять произведенную работу. Проигнорировать этот факт позволяет ключ -f:


git checkout -f some-other-branch


В случае, когда изменения надо все же сохранить, используют ключ -m. Тогда команда перед переключением попробует залить изменения в текущую ветку и, после разрешения возможных конфликтов, переключиться в новую:


git checkout -m some-other-branch


Вернуть файл (или просто вытащить из прошлого коммита) позволяет команда вида:


git checkout somefile


— вернуть somefile к состоянию последнего коммита


git checkout HEAD~2 somefile


— вернуть somefile к состоянию на два коммита назад по ветке.



2.2.3 git merge — слияние веток (разрешение возможных конфликтов).


Слияние веток, в отличие от обычной практики централизованных систем, в git происходит практически каждый день. Естественно, что имеется удобный интерфейс к популярной операции:


git merge new-feature


— попробует объединить текующую ветку и ветку new-feature.


В случае возникновения конфликтов коммита не происходит, а по проблемным файлам расставляются специальные метки а ля svn; сами же файлы отмечаются в индексе как «не соединенные» (unmerged). До тех пор пока проблемы не будут решены, коммит совершить будет нельзя.


Например, конфликт возник в файле TROUBLE, что можно увидеть в git status:


git merge experiment


— произошла неудачная попытка слияния.


git status


— смотрим на проблемные места.


edit TROUBLE


— разрешаем проблемы.


git add.


— индексируем наши изменения, тем самым снимая метки.


git commit


— совершаем коммит слияния.


Вот и все, ничего сложного. Если в процессе разрешения вы передумали разрешать

конфликт, достаточно набрать:


git reset --hard HEAD


— это вернет обе ветки в исходные состояния.


Если же коммит слияния был совершен, используем команду:


git reset --hard ORIG_HEAD



2.2.4 git rebase — построение ровной линии коммитов


Предположим, разработчик завел дополнительную ветку для разработки отдельной возможности и совершил в ней несколько коммитов. Одновременно по какой-либо причине в основной ветке также были совершены коммиты: например, в нее были залиты изменения с удаленного сервера; либо сам разработчик совершал в ней коммиты.


В принципе, можно обойтись обычным git merge. Но тогда усложняется сама линия разработки, что бывает нежелательно в слишком больших проектах, где участвует множество разработчиков.


Предположим, имеется две ветки, master и топик, в каждой из которых было совершенно несколько коммитов начиная с момента ветвления.


Команда git rebase берет коммиты из ветки topic и накладывает их на последний коммит ветки master:


git-rebase master topic


— вариант, в котором явно указывается, что и куда

прикладывается.


git-rebase master


— на master накладывается активная в настоящий момент ветка.


После использования команды история становится линейной. При возникновении конфликтов при поочередном накладывании коммитов работа команды будет останавливаться, а в проблемные местах файлов появятся соответствующие метки. После редактирования — разрешения конфликтов — файлы следует внести в индекс командой git add и продолжить наложение следующих коммитов командой git rebase --continue. Альтернативными выходами будут команды git rebase --skip (пропустить наложение коммита и перейти к следующему) или git rebase --abort (отмена работы команды и всех внесенных изменений).


С ключом -i (--interactive) команда будет работать в интерактивном режиме. Пользователю будет предоставлена возможность определить порядок внесения изменений, автоматически будет вызывать редактор для разрешения конфликтов и так далее.



2.2.5 git cherry-pick — применение к дереву проекта изменений, внесенных отдельным коммитом


Если ведется сложная история разработки, с несколькими длинными ветками разработками, может возникнуть необходимость в применении изменений, внесенных отдельным коммитом одной ветки, к дереву другой (активной в настоящий момент).


git cherry-pick BUG_FIX_TAG


— изменения, внесенные указанным коммитом будут применены к дереву, автоматически проиндексированы и станут коммитом в активной ветке.


git cherry-pick BUG_FIX_TAG -n


— ключ "-n" показывает, что изменения надо просто применить к дереву проекта без индексации и создания коммита.



2.3 Прочие команды и необходимые возможности


Для удобства работы с git было введено дополнительное понятие: тэг. Кроме того дальше будет пояснена необходимость в хэшах, и его применение; показан способ обращаться к коммитам при помощи относительной адресации.



2.3.1 Хэш — уникальная идентификация объектов


В git для идентификации любых объектов используется уникальный (то есть с огромной вероятностью уникальный) хэш из 40 символов, который определяется хэшируюшей функцией на основе содержимого объекта. Объекты — это все: коммиты, файлы, тэги, деревья. Поскольку хэш уникален для содержимого, например, файла, то и сравнивать такие файлы очень легко — достаточно просто сравнить две строки в сорок символов.


Больше всего нас интересует тот факт, что хэши идентифицируют коммиты. В этом смысле хэш — продвинутый аналог ревизий Subversion. Несколько примеров использования хэшей в качестве способа адресации:


git diff f292ef5d2b2f6312bc45ae49c2dc14588eef8da2


— найти разницу текущего состояния проекта и коммита за номером… Ну сами видите, каким.


git diff f292ef5


— то же самое, но оставляем только шесть первых символов. Git поймет, о каком коммите идет речь, если не существует другого коммита с таким началом хэша.


git diff f292


— иногда хватает и четырех символов.


git log febc32...f292


— читаем лог с коммита по коммит.


Разумеется, человеку пользоваться хэшами не так удобно, как машине, именно поэтому были введены другие объекты — тэги.



2.3.2 git tag — тэги как способ пометить уникальный коммит


Тэг (tag) — это объект, связанный с коммитом; хранящий ссылку на сам коммит, имя автора, собственное имя и некоторый комментарий. Кроме того, разработчик может оставлять на таких тегах собственную цифровую подпись.


Кроме этого в git представленные так называемые «легковесные тэги» («lightweight tags»), состоящие только из имени и ссылки на коммит. Такие тэги, как правило, используются для упрощения навигации по дереву истории; создать их очень легко:


git tag stable-1


— создать «легковесный» тэг, связанный с последним коммитом. Если тэг уже есть, то еще один создан не будет.


git tag stable-2 f292ef5


— пометить определенный коммит.


git tag -d stable-2


— удалить тег.


git tag -l


— перечислить тэги.


git tag -f stable-1.1


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


После создания тэга его имя можно использовать вместо хэша в любых командах вроде git diff, git log и так далее:


git diff stable-1.1...stable-1


Обычные тэги имеет смысл использовать для приложения к коммиту какой-либо информации, вроде номера версии и комментария к нему. Иными словами, если в комментарии к коммиту пишешь «исправил такой-то баг», то в комментарии к тэгу по имени «v1.0» будет что-то вроде «стабильная версия, готовая к использованию»:


git tag -a stable


— создать обычный тэг для последнего коммита; будет вызван текстовый редактор для составления комментария.


git tag -a stable -m «production version»


— создать обычный тэг, сразу указав в качестве аргумента комментарий.


Команды перечисления, удаления, перезаписи для обычных тэгов не отличаются от команд для «легковесных» тэгов.



2.3.3 Относительная адресация


Вместо ревизий и тэгов в качестве имени коммита можно опираться на еще один механизм — относительную адресацию. Например, можно обратиться прямо к предку последнего коммита ветки master:


git diff master^


Если после «птички» поставить цифру, то можно адресоваться по нескольким предкам коммитов слияния:


git diff HEAD^2


— найти изменения по сравнению со вторым предком последнего коммита в master. HEAD здесь — указатель на последний коммит активной ветки.


Аналогично, тильдой можно просто указывать, насколько глубоко в историю ветки нужно погрузиться:


git diff master^^


— что привнес «дедушка» нынешнего коммита.


git diff master~2


— то же самое.


Обозначения можно объединять, чтобы добраться до нужного коммита:


git diff master~3^~2


git diff master~6



2.3.4 файл .gitignore — объясняем git, какие файлы следует игнорировать


Иногда по директориям проекта встречаются файлы, которые не хочется постоянно видеть в сводке git status. Например, вспомогательные файлы текстовых редакторов, временные файлы и прочий мусор.


Заставить git status игнорировать можно, создав в корне или глубже по дереву (если ограничения должны быть только в определенных директория) файл .gitignore. В этих файлах можно описывать шаблоны игнорируемых файлов определенного формата.


Пример содержимого такого файла:


>>>>>>>Начало файла


#комментарий к файлу .gitignore


#игнорируем сам .gitignore

.gitignore


#все html-файлы…

*.html


#… кроме определенного

!special.html


#не нужны объектники и архивы

*.[ao]


>>>>>>>>Конец файла


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



3 «Вместе мы — сила», или основы работы с удаленным репозитарием


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



3.1 Удаленные ветки (remote tracking branches)


Новое понятие здесь — удаленные ветки. Удаленные ветки соответствуют какой-либо ветке (чаще master) на удаленном сервере. Одна такая создается автоматически при создании копии удаленного репозитария; все команды, связанные с удаленной работой, будут по умолчанию использовать именно эту удаленную ветку (обычно называется «origin»).


Рассмотрим эти команды.



3.2 git clone — создание копии (удаленного) репозитария


Для начала работы с центральным репозитарием, следует создать копию оригинального проекта со всей его историей локально:


git clone /home/username/project myrepo


— клонируем репозитарий с той же машины в директорию myrepo.


git clone ssh://user@somehost:port/~user/repository


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


git clone git://user@somehost:port/~user/repository/project.git/


— у git имеется и собственный протокол.



3.3 git fetch и git pull — забираем изменения из центрального репозитария (из удаленной ветки)


Для синхронизации текущей ветки с репозитарием используются команды git fetch и

git pull.


git fetch


— забрать изменения удаленной ветки из репозитария по умолчания, основной ветки; той, которая была использована при клонировании репозитария. Изменения обновят удаленную ветку (remote tracking branch), после чего надо будет провести слияние с локальной ветку командой git merge.


git fetch /home/username/project


— забрать изменения из определенного репозитария.


Возможно также использовать синонимы для адресов, создаваемые командой git remote:


git remote add username-project /home/username/project


git fetch username-project


— забрать изменения по адресу, определяемому синонимом.


Естественно, что после оценки изменений, например, командой git diff, из надо создать коммит слияния с основной:


git merge username-project/master


Команда git pull сразу забирает изменения и проводит слияние с активной веткой:


git pull


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


git pull username-project


— забрать изменения из определенного репозитария.



Как правило, используется сразу команда git pull.



3.4 git push — вносим изменения в удаленный репозитарий (удаленную ветку)


После проведения работы в экспериментальной ветке, слияния с основной, необходимо обновить удаленный репозитарий (удаленную ветку). Для этого используется команда git push:


git push


— отправить свои изменения в удаленную ветку, созданную при

клонировании по умолчанию.


git push ssh://yourserver.com/~you/proj.git master:experimental


— отправить изменения из ветки master в ветку experimental удаленного репозитария.


git push origin :experimental


— в удаленном репозитарии origin удалить ветку experimental.


git push origin master:master


— в удаленную ветку master репозитария origin (синоним

репозитария по умолчанию) ветки локальной ветки master.



4 git-о-день


В этом разделе будут показаны и разобраны подробно несколько обычных и чуть меньше необычных для работы с git ситуаций.



4.1 Обычный workflow при работе с локальным репозитарием


Git обладает необычайной легкостью в использовании не только как распределенная система контроля версий, но и в работе с локальными проектами. Давайте разберем обычный цикл — начиная с создания репозитария — работы разработчика git над собственным персональным проектом:


  1. mkdir git-demo
  2. cd git-demo
  3. git init
  4. git add.
  5. git commit -m «initial commit»
  6. git branch new-feature
  7. git checkout new-feature
  8. git add.
  9. git commit -m «Done with the new feature»
  10. git checkout master
  11. git diff HEAD new-feature
  12. git merge new-feature
  13. git branch -d new-feature
  14. git log --since=«1 day»


Разберем каждое из действий. 1-2 — просто создаем рабочую директорию проекта. 3 — создаем репозитарий в директории. 4 — индексируем все существующие файлы проекта (если, конечно, они вообще были). 5 — создаем инициализирующий коммит. 6 — новая ветка, 7 — переключение в нее (можно сделать в один шаг командой git checkout -b new-feature). Далее, после непосредственной работы с кодом, индексируем внесенные изменения(8), совершаем коммит(9). Переключаемся в основную ветку(10), смотрим отличия между последним коммитом активной ветки и последним коммитом экспериментальной (11). Проводим слияние (12) и, если не было никаких конфликтов, удаляем ненужную больше ветку (13). Ну и на всякий случай оценим проведенную за последний день работу (14).


Почему именно так? Зачем отказываться от линейной модели? Хотя бы даже потому, что у программиста появляется дополнительная гибкость: он может переключаться между задачами (ветками); под рукой всегда остается «чистовик» — ветка master; коммиты становятся мельче и точнее.



4.2 Workflow при работе с удаленным репозитарием


Предположим, что вы и несколько ваших напарников создали общественный репозитарий, чтобы заняться неким общим проектом. Как выглядит самая распространенная для git модель общей работы?


git clone http://yourserver.com/~you/proj.git


… возможно, прошло некоторое время.


1. git pull

2. git diff HEAD^

3. git checkout -b bad-feature


… работаем некоторое время.


4. git commit -a -m «Created a bad feature»

5. git checkout master

6. git pull

7. git merge bad-feature

8. git commit -a

9. git diff HEAD^


… запускаем тесты проекта, обнаруживаем, что где-то произошла ошибка. Упс.


10. git reset --hard ORIG_HEAD

11. git checkout bad-feature


… исправляем ошибку.


12. git -m bad-feature good-feature

13. git commit -a -m «Better feature»

14. git checkout master

15. git pull

16. git merge good-feature

17. git push

18. git branch -d good-feature


Итак, первым делом создаем (1) создаем копию удаленного репозитария (по умолчанию команды вроде git pull и git push будут работать с ним). «Вытягиваем» последние обновления (2); смотрим, что же изменилось(3); создаем новую ветвь и переключаемся в нее (4); индексируем все изменения и одновременно создаем из них коммит (5); переключаемся в главную ветвь (6), обновляем ее (7); проводим слияние с веткой bad-feature(8) и, обнаружив и разрешив конфликт, делаем коммит слияния (9).


После совершения коммита отслеживаем изменения(10), запускаем, например, юнит-тесты и с ужасом обнаруживаем, что после слияния проект валится на большей части тестов.


В принципе, тесты можно было прогнать и до коммита, в момент слияния (между пунктами 8 и 9); тогда бы хватило «мягкого» резета.


Таким образом, приходится совершить «жесткий» (11) сброс произошедшего слияния, ветки вернулись в исходное до состояние. После чего переключаемся в неудачную ветку (12), вносим необходимые изменения и переименовываем ветку (13). Совершаем коммит (14); переходим в главную ветку(15), опять ее обновляем (16). На этот раз бесконфликтно делаем слияние (17), закидываем изменения в удаленный репозитарий (18) и удаляем ненужную теперь ветку (19). Закрываем ноутбук, одеваемся и идем домой под утро.



5 Заключение


В топике не рассмотрено несколько важных вопросов, вроде администрирования общественного репозитария, интеграции с текстовыми редакторами или IDE, использования SSH под Линукс и Windows; приветствуются замечания, и особенно дополнения в раздел «git-о-день».


UPD: замечание по работе с удаленным репозитарием. При работе с git с точки зрения администрирования, создания общественных репозитариев, управления доступом, использования шифрованных соединений и так далее могут возникнуть определенные вопросы; причем в этой заметке они не освещаются никак. Например, выше описана работа с уже готовым удаленным репозитарием; его развертывание никак не освещено.


Это все я сейчас собираю в отдельный топик, которую и выкину сюда через неделю-полторы.


Так же в этом разделе:
← Содержание ...
 
MyTetra Share v.0.35
Яндекс индекс цитирования