git что это такое и как им пользоваться

Что такое Git: объясняем на схемах

Команды разработчиков пользуются системой контроля версий. Чаще всего это Git. Разбираемся, что это значит, зачем нужно и как устроено.

git что это такое и как им пользоваться

git что это такое и как им пользоваться

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

Git — это система коммитов

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

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

git что это такое и как им пользоваться

git что это такое и как им пользоваться

Автор статей о программировании. Изучает Python, разбирает сложные термины и объясняет их на пальцах новичкам. Если что-то непонятно — возможно, вы ещё не прочли его следующую публикацию.

Git — это комплекс связанных веток

Коммиты располагаются на master-ветке — основной версии проекта, которая после завершения работы превратится в продукт.

Система контроля версий позволяет создавать ответвления от master-ветки и экспериментировать с проектом, не мешая другим участника команды.

Возьмём предыдущую схему, где мы обнаружили ошибку и откатились на один коммит назад. Чтобы поправить код, создадим несколько дополнительных веток и в каждой протестируем разные варианты решения проблемы. Когда решение найдено, ветку с правильным кодом переносим в master-ветку и сохраняем коммит. Лишние ветки оставляем или удаляем, поскольку они не влияют на проект и скрыты от других разработчиков — это ваш личный черновик.

git что это такое и как им пользоваться

Git — это инструмент совместного создания кода

Часто бывает так: разработчики отделяются от master-ветки и работают над частью проекта самостоятельно — например, чтобы протестировать дополнительные функции. Но не могут продолжить, пока кто-то из команды не допишет код.

Система контроля версий позволяет не ждать обновления master-ветки и разрешает всем участникам команды свободно перемещаться между ветками других разработчиков для копирования нужных фрагментов кода.

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

git что это такое и как им пользоваться

Git — это распределённая система версий

Системы контроля версий бывают локальными, централизованными или распределёнными.

Из-за удобства и гибкости распределённая система версий Git считается современным форматом. Это стандарт для большинства ИТ-команд.

git что это такое и как им пользоваться

git что это такое и как им пользоваться

Git — это не GitHub

Git — это программа, которую нужно установить и подключить к проекту для управления системой контроля версий. GitHub — это сайт-хранилище для историй версий проектов: вы подключаете Git, регистрируетесь на GitHub, создаёте онлайн-репозиторий и переносите файлы с Git на GitHub.

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

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

git что это такое и как им пользоваться

git что это такое и как им пользоваться

Зачем новичку учить Git

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

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

Знание Git и знание правил использования Git в команде — это два разных навыка, которые можно сравнить с умением ездить на автомобиле и знанием правил дорожного движения. Если умеете управлять автомобилем — вам проще сконцентрироваться и быстро выучить правила. С Git аналогичная ситуация: если вы умеете управлять системой контроля версий, то можете сразу влиться в проект, не отвлекаться на второстепенные вещи и сосредоточиться на качестве кода.

С чего начать: 3 шага, чтобы освоить Git

1. Посмотрите наш вебинар по основам работы с Git:

Источник

Git за полчаса: руководство для начинающих

В последние годы популярность git демонстрирует взрывной рост. Эта система контроля версий используется различными проектами с открытым исходным кодом.

Новичков часто пугает большое количество замысловатых команд и сложных аргументов. Но для начала все они и не нужны. Можно начать с изучения наиболее часто используемых команд, и после этого постепенно расширять свои знания. Именно так мы и поступим в этой статье. Поехали!

Основы

Git — это набор консольных утилит, которые отслеживают и фиксируют изменения в файлах (чаще всего речь идет об исходном коде программ, но вы можете использовать его для любых файлов на ваш вкус). С его помощью вы можете откатиться на более старую версию вашего проекта, сравнивать, анализировать, сливать изменения и многое другое. Этот процесс называется контролем версий. Существуют различные системы для контроля версий. Вы, возможно, о них слышали: SVN, Mercurial, Perforce, CVS, Bitkeeper и другие.

Git является распределенным, то есть не зависит от одного центрального сервера, на котором хранятся файлы. Вместо этого он работает полностью локально, сохраняя данные в папках на жестком диске, которые называются репозиторием. Тем не менее, вы можете хранить копию репозитория онлайн, это сильно облегчает работу над одним проектом для нескольких людей. Для этого используются сайты вроде github и bitbucket.

Установка

Установить git на свою машину очень просто:

Если вы новичок, клиент с графическим интерфейсом(например GitHub Desktop и Sourcetree) будет полезен, но, тем не менее, знать команды очень важно.

Настройка

Итак, мы установили git, теперь нужно добавить немного настроек. Есть довольно много опций, с которыми можно играть, но мы настроим самые важные: наше имя пользователя и адрес электронной почты. Откройте терминал и запустите команды:

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

Создание нового репозитория

Командная строка должна вернуть что-то вроде:

Это значит, что наш репозиторий был успешно создан, но пока что пуст. Теперь создайте текстовый файл под названием hello.txt и сохраните его в директории git_exercise.

Определение состояния

status — это еще одна важнейшая команда, которая показывает информацию о текущем состоянии репозитория: актуальна ли информация на нём, нет ли чего-то нового, что поменялось, и так далее. Запуск git status на нашем свежесозданном репозитории должен выдать:

Сообщение говорит о том, что файл hello.txt неотслеживаемый. Это значит, что файл новый и система еще не знает, нужно ли следить за изменениями в файле или его можно просто игнорировать. Для того, чтобы начать отслеживать новый файл, нужно его специальным образом объявить.

Подготовка файлов

В git есть концепция области подготовленных файлов. Можно представить ее как холст, на который наносят изменения, которые нужны в коммите. Сперва он пустой, но затем мы добавляем на него файлы (или части файлов, или даже одиночные строчки) командой add и, наконец, коммитим все нужное в репозиторий (создаем слепок нужного нам состояния) командой commit.
В нашем случае у нас только один файл, так что добавим его:

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

Проверим статус снова, на этот раз мы должны получить другой ответ:

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

Коммит(фиксация изменений)

Коммит представляет собой состояние репозитория в определенный момент времени. Это похоже на снапшот, к которому мы можем вернуться и увидеть состояние объектов на определенный момент времени.
Чтобы зафиксировать изменения, нам нужно хотя бы одно изменение в области подготовки (мы только что создали его при помощи git add), после которого мы может коммитить:

Удаленные репозитории

1. Подключение к удаленному репозиторию

Чтобы загрузить что-нибудь в удаленный репозиторий, сначала нужно к нему подключиться. В нашем руководстве мы будем использовать адрес https://github.com/tutorialzine/awesome-project, но вам посоветуем попробовать создать свой репозиторий в GitHub, BitBucket или любом другом сервисе. Регистрация и установка может занять время, но все подобные сервисы предоставляют хорошую документацию.
Чтобы связать наш локальный репозиторий с репозиторием на GitHub, выполним следующую команду в терминале. Обратите внимание, что нужно обязательно изменить URI репозитория на свой.

Проект может иметь несколько удаленных репозиториев одновременно. Чтобы их различать, мы дадим им разные имена. Обычно главный репозиторий называется origin.

2. Отправка изменений на сервер

В зависимости от сервиса, который вы используете, вам может потребоваться аутентифицироваться, чтобы изменения отправились. Если все сделано правильно, то когда вы посмотрите в удаленный репозиторий при помощи браузера, вы увидите файл hello.txt

3. Клонирование репозитория

Сейчас другие пользователи GitHub могут просматривать ваш репозиторий. Они могут скачать из него данные и получить полностью работоспособную копию вашего проекта при помощи команды clone.

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

4. Запрос изменений с сервера

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

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

Ветвление

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

1. Создание новой ветки

Основная ветка в каждом репозитории называется master. Чтобы создать еще одну ветку, используем команду branch

Это создаст новую ветку, пока что точную копию ветки master.

2. Переключение между ветками

Сейчас, если мы запустим branch, мы увидим две доступные опции:

master — это активная ветка, она помечена звездочкой. Но мы хотим работать с нашей “новой потрясающей фичей”, так что нам понадобится переключиться на другую ветку. Для этого воспользуемся командой checkout, она принимает один параметр — имя ветки, на которую необходимо переключиться.

3. Слияние веток

Наша “потрясающая новая фича” будет еще одним текстовым файлом под названием feature.txt. Мы создадим его, добавим и закоммитим:

Изменения завершены, теперь мы можем переключиться обратно на ветку master.

Теперь, если мы откроем наш проект в файловом менеджере, мы не увидим файла feature.txt, потому что мы переключились обратно на ветку master, в которой такого файла не существует. Чтобы он появился, нужно воспользоваться merge для объединения веток (применения изменений из ветки amazing_new_feature к основной версии проекта).

Теперь ветка master актуальна. Ветка amazing_new_feature больше не нужна, и ее можно удалить.

Дополнительно

В последней части этого руководства мы расскажем о некоторых дополнительных трюках, которые могут вам помочь.

1. Отслеживание изменений, сделанных в коммитах

У каждого коммита есть свой уникальный идентификатор в виде строки цифр и букв. Чтобы просмотреть список всех коммитов и их идентификаторов, можно использовать команду log:
[spoiler title=’Вывод git log’]

[/spoiler]
Как вы можете заметить, идентификаторы довольно длинные, но для работы с ними не обязательно копировать их целиком — первых нескольких символов будет вполне достаточно. Чтобы посмотреть, что нового появилось в коммите, мы можем воспользоваться командой show [commit]
[spoiler title=’Вывод git show’]

[/spoiler]
Чтобы увидеть разницу между двумя коммитами, используется команда diff (с указанием промежутка между коммитами):
[spoiler title=’Вывод git diff’]

[/spoiler]
Мы сравнили первый коммит с последним, чтобы увидеть все изменения, которые были когда-либо сделаны. Обычно проще использовать git difftool, так как эта команда запускает графический клиент, в котором наглядно сопоставляет все изменения.

2. Возвращение файла к предыдущему состоянию

3. Исправление коммита

Если вы опечатались в комментарии или забыли добавить файл и заметили это сразу после того, как закоммитили изменения, вы легко можете это поправить при помощи commit —amend. Эта команда добавит все из последнего коммита в область подготовленных файлов и попытается сделать новый коммит. Это дает вам возможность поправить комментарий или добавить недостающие файлы в область подготовленных файлов.
Для более сложных исправлений, например, не в последнем коммите или если вы успели отправить изменения на сервер, нужно использовать revert. Эта команда создаст коммит, отменяющий изменения, совершенные в коммите с заданным идентификатором.
Самый последний коммит может быть доступен по алиасу HEAD:

Для остальных будем использовать идентификаторы:

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

4. Разрешение конфликтов при слиянии

Помимо сценария, описанного в предыдущем пункте, конфликты регулярно возникают при слиянии ветвей или при отправке чужого кода. Иногда конфликты исправляются автоматически, но обычно с этим приходится разбираться вручную — решать, какой код остается, а какой нужно удалить.
Давайте посмотрим на примеры, где мы попытаемся слить две ветки под названием john_branch и tim_branch. И Тим, и Джон правят один и тот же файл: функцию, которая отображает элементы массива.
Джон использует цикл:

Тим предпочитает forEach:

Они оба коммитят свой код в соответствующую ветку. Теперь, если они попытаются слить две ветки, они получат сообщение об ошибке:

Система не смогла разрешить конфликт автоматически, значит, это придется сделать разработчикам. Приложение отметило строки, содержащие конфликт:
[spoiler title=’Вывод’]

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

Как вы можете заметить, процесс довольно утомительный и может быть очень сложным в больших проектах. Многие разработчики предпочитают использовать для разрешения конфликтов клиенты с графическим интерфейсом. (Для запуска нужно набрать git mergetool).

Вот хорошие примеры файлов, которые нужно игнорировать:

Символ слэша в конце некоторых линий означает директорию (и тот факт, что мы рекурсивно игнорируем все ее содержимое). Звездочка, как обычно, означает шаблон.

Заключение.

Вот и все! Наше руководство окончено. Мы очень старались собрать всю самую важную информацию и изложить ее как можно более сжато и кратко.
Git довольно сложен, и в нем есть еще много функций и трюков. Если вы хотите с ними познакомиться, вот некоторые ресурсы, которые мы рекомендуем:

Источник

Git изнутри и на практике

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

Команде AppsCast, конечно, захотелось узнать больше, и за консультацией по практическому применению всех возможностей Git ребята обратились к Егору Андреевичу из Square.

git что это такое и как им пользоваться

Даниил Попов: Всем привет. Сегодня к нам присоединился Егор Андреевич из Square.

Егор Андреевич: Всем привет. Я живу в Канаде и работаю в компании Square, которая занимается разработкой software и hardware для финансовой индустрии. Начинали с терминалов для приема платежей кредитными картами, сейчас же делаем сервисы для владельцев бизнесов. Я работаю над продуктом Cash App. Это мобильный банк, который позволяет обмениваться деньгами с друзьями, заказывать дебетовую карту для оплаты в магазинах. У компании множество офисов по всему миру, а в канадском офисе порядка 60 программистов.

Даниил Попов: В среде андроид-разработчиков Square известна благодаря своим open-source проектам, которые стали стандартами индустрии: OkHttp, Picasso, Retrofit. Логично, что разрабатывая такие открытые для всех инструменты, вы много работаете с Git. Об этом мы бы и хотели поговорить.

Что такое Git

Егор Андреевич: Я давно использую Git как инструмент, и в какой-то момент мне стало интересно узнать о нем больше.

Git — это упрощенная файловая система, поверх которой находится набор операций для работы с контролем версий.

Git позволяет сохранять файлы в определенном формате. Каждый раз при записи файла Git возвращает ключ к вашему объекту — hash.

Даниил Попов: Многие замечали, что в репозитории есть магическая скрытая директория .git. Зачем она нужна? Могу ли я ее удалить или переименовать?

Егор Андреевич: Создание репозитория возможно через команду git init. Она создает директорию .git, которую Git использует для контроля файлов. В .git хранится все, что вы делаете в своем проекте, только в сжатом формате. Поэтому из этой директории можно восстановить репозиторий.

Алексей Кудрявцев: Получается, что твоя папка с проектом — это одна из версий разжатой папки Git?

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

Алексей Кудрявцев: Что лежит внутри папки?

Есть директории — этакие папки с подпапками, т.е. у Git есть тип объекта tree, который содержит ссылки на blob, на другие trees.

В принципе, один tree — это snapshot, описывающий состояние вашей директории на определенный момент.

При создании коммита (commit) фиксируется ссылка на рабочую директорию — tree.

Коммит — это ссылка на tree с информацией о том, кто его создал: email, имя, время создания, ссылка на parent (родительскую ветку) и сообщение. Коммиты Git также сжимает и записывает в директорию object.

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

Преимущества работы с Git

Даниил Попов: Как Git работает? Почему алгоритм действий такой сложный?

Егор Андреевич: Если сравнивать Git с Subversion (SVN), то в первой системе есть ряд функций, которые нужно понимать. Начну с staging area, которую не стоит считать ограничением Git, а скорее фичей.

Прекрасно известно, что при работе с кодом не все сразу идет по маслу: где-то надо поменять layout, где-то пофиксить баги. В итоге после сессии работы появляется ряд затронутых файлов, которые между собой не связаны. Если все изменения занести в один коммит, то это будет неудобно, так как изменения разные по характеру. Тогда на выход приходит серия коммитов, которую можно создать как раз благодаря staging area. В одну серию, например, отправляются все изменения layout-файла, в другую — фикс unit-тестов. Мы берем несколько файлов, перемещаем в staging area и создаем коммит только с их участием. Остальные файлы из рабочей директории в него не попадают. Таким образом, вы разбиваете всю работу, проведенную в рабочей директории, на несколько коммитов, каждый из которых представляет определенную работу.

Алексей Кудрявцев: Чем Git отличается от других систем контроля версий?

Егор Андреевич: Лично я начинал с SVN и после сразу перешел на Git. Важно, что Git — децентрализованная система контроля версий. Все копии репозитория Git абсолютно одинаковы. В каждой компании есть сервер, где лежит основная версия, но она ничем не отличается от той, что лежит у разработчика на компьютере.

SVN имеет центральный репозиторий и локальные копии. Значит, любой разработчик может в одиночку сломать центральный репозиторий.

В Git такого не произойдет. Если центральный сервер потеряет данные репозитория, его можно будет восстановить с любой локальной копии. Git по-другому устроен, и это дает преимущества скорости работы.

Даниил Попов: Git славится своим ветвлением, которое работает заметно быстрее чем SVN. Как ему это удается?

Егор Андреевич: В SVN ветка (branch) — это полная копия предыдущей ветки. В Git физического представления ветки нет. Это ссылка на последний коммит в определенной линии разработки. Когда Git сохраняет объекты, при создании коммита он создает файл с определенной информацией о коммите. Git создает символический файл — symlink со ссылкой на другой файл. Когда у вас много веток, то вы ссылаетесь на разные коммиты в репозитории. Чтобы отследить историю ветки, нужно переходить из каждого коммита по ссылке назад на родительский коммит.

Мерджим ветки

Даниил Попов: Есть два способа как слить две ветки в одну — это merge и rebase. Как вы ими пользуетесь?

Егор Андреевич: У каждого способа свои преимущества и недостатки. Merge — самый простой вариант. Например, есть две ветки: master и выделенная из нее feature.

Для merge можно использовать fast forward. Это возможно, если с того момента, как была начата работа в feature-ветке, в master не было сделано новых коммитов. То есть первый коммит в feature — это последний коммит в master.

В таком случае указатель фиксируется на ветке master и перемещается на самый последний коммит в ветке feature. Таким образом ветвление устраняется через соединение feature-ветки с основным потоком master и удаление ненужной ветки. Получается линейная история, где все коммиты следуют друг за другом. На практике такой вариант случается нечасто, так как постоянно кто-то сливает коммиты в master.

Можно иначе. Git создает новый коммит — merge commit, у которого две ссылки на родительские коммиты: один в master, другой в feature. С помощью нового коммита происходит соединение двух веток и feature снова можно удалять.

После merge commit можно посмотреть историю и увидеть, что она раздвоилась. Если вы используете tool, который графически рендерит коммиты, то визуально это будет похоже на «ёлочку». Это не ломает Git, но разработчику смотреть такую историю сложно.

Другой инструмент — rebase. Концептуально вы берете все изменения с feature-ветки и перебрасываете поверх ветки master. Первый коммит feature становится новым коммитом поверх наиболее позднего коммита master.

Тут есть загвоздка — Git не может менять коммиты. Был коммит в feature и мы не можем просто перенести поверх master, так как в каждом коммите есть time stamp.

В случае с rebase Git считывает все коммиты в feature, временно сохраняет, а затем пересоздает в том же порядке в master. После rebase изначальные коммиты пропадают, а поверх master появляются новые коммиты с тем же контентом. Тут возникают проблемы. При попытке сделать rebase ветки, с которой работают другие люди, можно поломать репозиторий. Например, если кто-то начал свою ветку из коммита, который был в feature, а вы этот коммит уничтожили и пересоздали. Rebase подходит больше для локальных веток.

Даниил Попов: Если ввести ограничения, что над одной feature-веткой работает строго один человек, договориться, что нельзя отпочковывать одну feature-ветку от другой, то такой проблемы не возникает. Но какой подход практикуете вы?

Егор Андреевич: Мы не используем feature-ветки в прямом понимании этого термина. Каждый раз, когда мы производим изменение, создаем новую ветку, работаем в ней и сразу вливаем в master. Нет долгоиграющих веток.

Это решает большое количество проблем с merge и rebase, особенно конфликты. Ветки существуют один час и высока вероятность использования fast forward, так как никто ничего не добавил в master. Когда же мы делаем merge в pull request, то только merge c созданием merge commit

Даниил Попов: Как вы не боитесь сливать master неработающую фичу, ведь декомпозировать задачу на часовые интервалы часто нереально?

Егор Андреевич: Мы используем подход feature flags. Это динамические флаги, определенная фича с разными состояниями. Например, функция отправлять платежи друг другу либо включена, либо выключена. У нас есть сервис, который динамически доставляет это состояние клиентам. Вы с сервера получаете значение выключена фича или нет. Это значение вы можете использовать в коде — выключить кнопку, которая идет в скрин. Сам код есть в приложении, и его можно зарелизить, но доступа в этот функционал нет, потому что он за feature flag.

Даниил Попов: Часто новичкам в Git говорят, чтобы после rebase нужно делать push с force. Откуда это?

Егор Андреевич: Когда вы делаете просто push, другой репозиторий может выкинуть ошибку: вы пытаетесь запушить ветку, но у вас на этой ветке абсолютно другие коммиты. Git проверяет всю информацию, чтобы вы случайно не поломали репозиторий. Когда вы говорите git push force, то выключаете этот чекинг, считая, что знаете лучше него, и требуете переписать ветку.

Почему это нужно после rebase? Rebase пересоздает коммиты. Получается, что ветка называется также, но коммиты в ней с другими хэшами, и Git на вас ругается. В этой ситуации абсолютно нормально сделать force push, так как вы контролируете ситуацию.

Даниил Попов: Еще есть понятие interactive rebase, и многие его боятся.

Егор Андреевич: Страшного ничего нет. За счет того, что Git пересоздает историю при rebase, он временно ее хранит перед тем как перекинуть. Когда у него есть временный storage, он может с коммитами делать все, что угодно.

Rebase в интерактивном режиме предполагает, что Git перед rebase выкидывает окошко текстового редактора, в котором можно указать, что надо сделать с каждым отдельным коммитом. Это выглядит как несколько линий текста, где каждая линия — один из коммитов, которые есть в ветке. Перед каждым коммитом есть указание операции, которую стоит выполнить. Самая простая операция по умолчанию — pick, т.е. взять и включить в rebase. Самая распространенная — squash, тогда Git возьмет изменения из этого коммита и объединит с изменениями предыдущего.

Часто встречается такой сценарий. Вы работали локально в своей ветке и создавали коммиты для сейва. Получилась длинная история коммитов, которая для вас интересна, но в таком же варианте ее в основную историю не стоит заливать. Тогда вы даете squash для переименования в общий коммит.

Список команд длинный. Можно выбросить коммит — drop и он исчезнет, можно поменять сообщение коммита и т.д.

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

Егор Андреевич: Я очень далек от того, чтобы постичь всю мудрость интерактивного rebase, но это мощный инструмент и сложный.

Практическое применение Git

Даниил Попов: Перейдем к практике. На собеседовании я часто спрашиваю: «У тебя есть тысяча коммитов. На первом все хорошо, на тысячном сломался тест. Как с помощью гита можно найти изменение, которое к этому привело?»

Егор Андреевич: В этой ситуации нужно использовать bisect, хотя проще брать blame.

Начнем с интересного. Git bisect применим к ситуации, когда у вас есть regression — был функционал, работал, но вдруг перестал. Чтобы найти, когда сломался функционал, можно теоретически наугад откатиться на предыдущую версию приложения, посмотреть в код, но есть инструмент, который позволит структурировано подойти к проблеме.

Git bisect — интерактивный инструмент. Есть команда git bisect bad, через которую вы сообщаете о наличии поломанного коммита и git bisect good — для рабочего коммита. Каждый раз при релизе приложения мы запоминаем hash коммита, с которого сделан релиз. Этот hash также можно использовать для указания плохих и хороших коммитов. Bisect получает информацию о промежутке, где какой-то из коммитов поломал функционал, и запускает сессию binary search, где постепенно выдает коммиты на проверку, работают они или нет.

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

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

Blame — это более простой инструмент, который исходя из своего названия позволяет найти «виновника» поломки функционала. За счет этого негативного определения многие в коммьюнити blame недолюбливают.

Что он делает? Если вы даете git blame определенный файл, то он полинейно в этом файле покажет, какой коммит менял ту или иную линию. Я никогда не использовал git blame с командной строки. Как правило это делают в IDEA или Android Studio — кликаете и видите, кто какую линию файла поменял и в каком коммите.

Даниил Попов: Кстати в Android Studio это назвали Annotate. Убрали негативную коннотацию blame.

Алексей Кудрявцев: Точно, в xCode они переименовали его в Authors.

Егор Андреевич: Еще я читал, что есть утилита git praise — найти того, кто написал этот отличный код.

Даниил Попов: Нужно заметить что по blame работают предложения ревьюеров на pull request. Он смотрит, кто больше всего трогал тот или иной файл, и предполагает, что этот человек сможет хорошо поревьюить ваш код.
В случае с примером про тысячу коммитов blame в 99% случаев покажет, что пошло не так. Bisect — это уже last resort.

Егор Андреевич: Да, к bisect я прибегаю крайне редко, а вот annotate использую регулярно. Хотя иногда по линии кода нельзя понять, почему там null checked, зато по всему коммиту ясно, что хотел сделать автор.

Как правильно работать с Stacked PRs?

Даниил Попов: Я слышал, что в Square применяется Stacked pull requests (PRs).

Егор Андреевич: Как минимум в нашей андроид-команде мы часто их используем.
Мы очень много времени уделяем тому, чтобы каждый pull request было легко ревьюить. Иногда есть соблазн накодить, быстро закоммить, и пусть ревьюеры разбираются. Мы стараемся создавать небольшие pull request’ы и краткое описание — код должен говорить сам за себя. Когда pull request’ы маленькие — их легко и быстро заревьюить.

Здесь возникает проблема. Вы работаете над функционалом, который потребует большого количества изменений в code base. Что вы можете сделать? Можно положить в один pull request, но тогда он будет огромным. Можно работать постепенно создавая pull request, но тогда проблема будет в том, что вы создали branch, добавили несколько изменений и засабмитили pull request, вернулись на master и тот код, который был у вас в pull request, недоступен в master до того момента, пока не произойдет merge. Если вы зависите от изменений в этих файлах, то сложно продолжать работу, потому что этого кода нет.

Как мы это обходим? После того, как мы создали первый pull request, продолжаем работу, создаем новую ветку из существующей ветки, которую мы использовали до pull request. Каждая ветка идет не из master, а из предыдущей ветки. Когда заканчиваем работу над этим куском функционала, сабмитим еще один pull request и опять же указываем, что при merge он мержится не в master, а в предыдущий branch. Получается такая цепочка pull request’ов — stacked prs. Когда человек ревьюит, он видит изменения, которые были внесены только этой фичей, но не предыдущей.

Задача в том, чтобы каждый pull request был как можно меньше и понятней, чтобы не возникало необходимости изменять. Потому что если придется менять код в ветках, которые находятся в середине stacked, все, что сверху, поломается, так как придется делать rebase. Если pull request’ы маленькие, мы стараемся как можно быстрее из замержить, тогда весь stacked пошагово сливается в master.

Даниил Попов: Правильно я понимаю, что в итоге будет какой-то последний pull request, который содержит в себе все маленькие pull request’ы. Вы эту ветку не глядя вливаете?

Егор Андреевич: Merge происходит из истока stacked: сначала в master мержится самый первый pull request, в следующем меняется base из ветки в master и, соответственно, Git вычисляет, что в master уже какие-то изменения есть, snapshot получается меньше.

Алексей Кудрявцев: Бывают ли у вас состояния гонок, когда первая ветка уже замерджилась, а только после этого вторая в первую замержилась, потому что ей не поменяли таргет на master?

Егор Андреевич: Мы мержим вручную, поэтому таких ситуаций не бывает. Я открываю pull request, отмечаю коллег, от которых я хочу получить ревью и, когда они заапрувили, иду на bitbucket, нажимаю merge.

Алексей Кудрявцев: А как же проверки на CI, что ничего не сломано?

Егор Андреевич: Такого мы не делаем. CI работает на ветке, которая является базой для pull request и после проверки мы меняем base. Технически он не меняется, так как таргетишь тоже количество изменений.

Даниил Попов: А вы прямо в master пушите или все же develop? И при релизе явно указываете коммит, с которого собирать?

Егор Андреевич: У нас нет develop, только master. Мы обязательно релизим каждые две недели. Когда мы начинаем готовить релиз, открываем релиз-ветку и какие-то последние фиксы идут и в master, и в эту ветку. Используем tags — перманентные ссылки на определенный коммит опционально с какой-то информацией. Если какой-то коммит — это релиз-коммит, то хорошо бы сохранить в истории, что с этого коммита мы сделали релиз. Создается тэг, Git сохраняет информацию с версией, и позже к нему можно вернуться.

Алексей Кудрявцев: Где поучить Git, что почитать?

Егор Андреевич: У Git есть официальная книга. Мне нравится, как она написана, есть хорошие примеры. Есть глава про внутренности, можно ее досконально изучить. На StackOverflow можно найти множество эзотерических ситуаций и решений. Ими тоже можно пользоваться.

На предстоящей Saint AppsConf про Git говорить не собираемся. Но зато мы решились на эксперимент и добавили в плотную программу конференции доклады из серии Introductory, в которых спикеры из смежных отраслей разработки делятся знаниями для расширения кругозора мобильного разработчика. Советуем обратить внимание на выступление Николая Голова из Avito про базы данных: как не ошибиться и выбрать правильную базу, как подготовиться к росту и что актуально в 2019 году.

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *