Historical Branches Вместо использования только одной master ветки, этот workflow использует две ветки, для записи истории проекта. Master хранит официальную историю релизов, в development же ветке ведется активная разработка. Также важно тагать комиты в master ветки номерами версий.
Feature Branches Каждая новая фича должна разрабатываться отдельно - в своей ветке, которая должна пушиться в центральный репозиторий для сохранения работы или коллаборации с другими разработчиками. Для создания фичебранча используется development ветка. Когда разработка фичи закончена, она сливается в development. Фичи никогда не должны сливаться напрямую с master веткой.
Release Branches Как только development наберет достаточно фич для релиза (или в заранее определенную дату) создается release ветка из development ветки.
Создание этого бранча начинает новый релиз-цикл, поэтому в эту ветку уже не должно покадать никаких новых фич - только баг-фиксы, генерация документации и другие таски, ориентированные на релиз.
Как только релиз-ветка подготовлена, ее сливают с master и тагают новой версией. Также она должна быть слита и с development веткой, которая уже скорее всего убежала вперед, с момента инициализации релиза.
Использование отдельной ветки для релиза позволяет одной команде готовить релиз, в том время когда другая команда будет продолжать разрабатывать новые фичи в development для последующих релизов.
Hotfix Branches Hotfix ветки используются для быстрого патчинга релизов. Это единственная ветка, которая создается из master. Как только фикс готов, он должен быть слит как в master, так и в development (или в новый release, если она есть) и master должен быть тегирован новой версией (инкрементирована patch цифра. v.1.0.1, например)
Это позволяет исправлять ошибки не прерывая весь воркфлоу или не дожидаясь следующего релиза, для выкатывания исправлений.
Итак git работает с комитами. Каждый комит — набор изменений. У каждого комита есть уникальный hash. Когда происходит слияние веток посредством merge:
$ git merge "another_branch"
то все комиты сохраняются — сохраняются комментарии комита, его hash + как правило добавляется еще один искусственный комит. При этом комиты могут чередоваться друг с другом. Это не всегда удобно. Допустим ваш комит решили откатить — выискивать в общем списке где ваш комит, а где не ваш не очень приятно. И вообще — в общей истории хочется видеть действительно важные изменения, а не «ой, я забыл поставить ;». Для того, чтобы несколько комитов склеивать в один можно использовать rebase. Хотя в интерфейсе GitHub есть кнопочка squash & commit — это когда вы создаете pull request (PR) из одной ветки в другую (как правило из вашей рабочей ветки в основную) и после прохождения всех формальностей можно нажать squash & commit, обновить комментарий и ваши изменения появятся в основной ветке как один комит.
Хочу написать о двух случаях использования rebase:
$ git rebase "another_branch"
Это позволяет ваши локальные комиты поставить после всех комитов, которые были внесены в ветку «another_branch». Хэши ваших комитов изменятся.$ git rebase -i {HEAD~_commit_count_|commit_hash}
Итак вы все сделали в своей уютненькой веточки и решили поделиться этим комитом с миром, но мир хочет от вас только один комит. git rebase -i
запустит редактор и предложит отредактировать комиты (порядок следования комитов — сверху вниз в отличие от git log). Можно оставить комит как есть, можно изменить комментарий, можно склеить с предыдущим. Как правило ваш первый комит надо оставить как есть, а все остальные изменить на pick "commit_hash" "comment" → fixup "commit_hash" "comment"
.
При этом все комментарии, которые были в fixup комитах потеряются и будет использоваться комментарий от первого комита. Если вам были дороги комментарии, то стоит использовать squash вместо fixup.
Но если процесс разработки был долог, то скорее всего вам приходилось делать merge основной ветки. И все ваши комиты перемешаются с общими комитами и склеивать ваши с не вашими будет задачей непростой. Поэтому перед тем, как делать git rebase -i <>
стоит сделать git rebase
. git rebase
поставит все ваши комиты в конец списка всех комитов (в чем можно убедиться запустив git log
) и после этого запустиь git rebase -i <HEAD~Количесво_ваших_комитов>
, во всех строчках кроме первой заменить pick → {fixup|squash} и вуаля — у вас один комит.
Если в процессе редактирования комитов git rebase -i <>
вы как-то накосячили, то не стоит жать Control+C — exit code выхода из редактора git не волнует. Он просто возьмет файл и сделает все по нему. Просто удалите или закомментируйте все строчки в файле. git поймет, что вы ничего не хотели.
После манипуляций с rebase потребуется push с опцией -F. Все это потому, что мы переписываем меняем историю комитов и git нас об этом честно предупреждает. $ git push -f
Команда git cherry-pick
используется для перенесения отдельных коммитов из одного места репозитория в другое, обычно между ветками разработки и обслуживания. Этот механизм отличается от привычных команд git merge
и git rebase
, которые переносят коммиты целыми цепочками.
git cherry-pick <commit-hash>
Если вы поправили какие-нибудь старые коммиты в истории git, например: исправили имя автора или e-mail, или отменили последний коммит или воспользовались amend или revert, то при попытке push-а git справедливо «ругнётся»
Чтобы нам всё же запушить наши изменения, нам нужно выполнить либо
git push --force origin <имя_ветки>
Но в этом случае мы рискуем перетереть чьи-нибудь изменения, если с тех пор, как мы забирали изменения с сервера, кто-то успел запушить свои коммиты. Поэтому лучше использовать более безопасную команду:
git push --force-with-lease origin <имя_ветки>
Такой вариант лучше тем, что если кто-то успел запушить свои коммиты после того, как мы забирали изменения с сервера, то он не будет их перетирать, а выдаст нам ошибку, после чего мы сможем интегрировать чужие коммиты со своими изменениями и попытаться сделать push --force-with-lease
ещё раз.
Как и во многих других системах контроля версий, в Git’е есть возможность запускать собственные сценарии в те моменты, когда происходят некоторые важные действия. Существуют две группы подобных перехватчиков (hook): на стороне клиента и на стороне сервера. Перехватчики на стороне клиента предназначены для клиентских операций, таких как создание коммита и слияние. Перехватчики на стороне сервера нужны для серверных операций, таких как приём отправленных коммитов. Перехватчики могут быть использованы для выполнения самых различных задач. О некоторых из таких задач мы и поговорим.
Pre-commit check можно использовать например так: