В последних двух выпусках Радио-T ведущие пытались обсудить GIT. Евгений (Umputun) задавался вопросом зачем нужен rebase и очень удивился, когда я спросил, редактирует ли он коммиты. На мой взгляд, чтоб понять GIT, достаточно вникнуть в процесс разработки Linux Kernel, т к создавался он именно для этого.
Давайте проследим, как изменения попадают в основной репозиторий. Разработчик клонирует себе git и начинает разрабатывать новую функциональность. В процессе разработки он пишет код, тестирует, находит баги, фиксит их. Вероятно, делает какое-то количество коммитов. Когда фича готова, то нельзя просто взять и послать все эти коммиты в виде патчей, так же как нельзя послать все это в виде одного патча.
Следующая цель разработчика разбить все изменения таким образом, чтобы они были понятны мейнтейнеру и другим членам команды. В этом процессе есть несколько правил: каждый патч содержит только одно логическое изменение; каждый патч не должен быть деструктивен; коммит месcадж должен максимально подробно описывать изменения.
У этой двойной работы есть своя мотивация. Просмотр патчей (review) — дело не самое увлекательное и интересное, поэтому каждый должен стараться облегчить этот процесс по максимуму. Мейнтейнеру, как и остальным членам команды, не интересно смотеть, как ваша мысль плавала в поисках правильного решения. Им достаточно прочитать коммит месадж, где будет описано, почему именно этот подход был выбран. Еще меньший интерес вызывают баги, которые вы сделали в ходе разработки.
Я чаще всего создаю новый бранч, откатываю все коммиты (git reset) и начинаю разбивку с помощью git commit --interactive. Это команда позволяет выбрать какие изменения идут в какой комит. Когда все готово, патчи можно сформировать командой git format-patch и послать их с помощью git send-email.
Хорошо если патчи сразу приняли, но иногда кто-то находит в них ошибки, просит добавить комментарии или ещё что-то исправить. В этом случае нам пригодится git rebase --interactive, который позволяет поменять порядок коммитов, объединить два и более комита или остановиться на любом коммите для его редактирования. После исправления всех недочетов, формируем и посылаем патчи второй раз и так далее, пока их не примут. Кстати, перед посылкой патчей в рассылку, нужно обновить свой репозиторий, причём таким образом, чтобы все наши изменения остались сверху, это и называется rebase.
Если мейнтейнер принимает патчи, то он коммитит их в свой репозиторий. Когда приходит следующий merge window, он отправляет pull request вышестоящему мейнтейнеру. В идеале можно было бы перенести каждое новое изменение в отдельности и иметь линейную историю. Мы живём в реальном мире, где изменения могут конфликтовать между собой, а мержить каждой отдельное изменение времени нет. Поэтому, на помощь приходит git pull, при котором все изменения коммитятся одним куском, и конфликты фиксятся один раз, хотя в истории (git log) все выглядит линейно.
Так же в подкасте упоминался git bisect, это средство для двоичного поиска комита, который все сломал. Допустим вы знаете коммиты где бага не было и где баг уже есть. Цель — найти коммит, который посадил этот баг за минимальное количество шагов. Откатываемся к коммиту, который точно посередине. Если бага в этой точки нет, то проблемный коммит справа, иначе он слева. Повторяем пока не найдем. Особенность git bisect-а, что он умеет правильно обрабатывать нелинейные куски истории, о которых мы говорили выше.
Автор: avagin