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

Git стал настолько неотъемлемой частью работы с кодом, что мы практически никогда не включаем его в свой технологический стек или в резюме. Предполагается, что вы уже освоили Git, или, по крайней мере, достаточно знаете, чтобы справиться с ним. Но так ли это?

Git  —  VCS (version control system  —  система контроля версий)  —  это популярная технология, которая позволяет хранить и изменять код, а также сотрудничать с другими разработчиками.

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

Повседневная жизнь разработчика связана с чтением, написанием и рецензированием кода. Git, пожалуй, один из самых важных инструментов, используемых при этом. Освоение возможностей и функций Git  —  одна из лучших инвестиций в себя как разработчика.


Базовые понятия

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

Ветви

В репозитории Git есть основная линия разработки, обычно называемая “main” или “master” (устаревшее название), от которой расходятся несколько ветвей (branches). Эти ветви представляют собой совместные рабочие процессы, позволяющие разработчикам одновременно выполнять несколько функций или исправлений в рамках одного проекта.

Ветви в Git

Коммиты

Коммиты (commits ) Git служат пакетами обновленного кода, фиксируя снимок кода проекта в определенный момент времени. Каждый коммит фиксирует изменения, сделанные с момента последнего коммита, а все вместе они создают полную историю развития проекта.

Коммиты в Git

При ссылке на коммит обычно используется его уникальный криптографический хэш.

Пример:

git show abc123def456789

Хэш показывает подробную информацию о коммите.

Теги

Теги (tags) Git служат вехами в истории Git, обычно отмечая значительные события в развитии проекта, такие как releases, versions и standout commits (релизы, версии или особые, чем-то примечательные коммиты). Эти теги неоценимы для обозначения определенных моментов времени, часто представляющих собой отправные точки или основные достижения на пути развития проекта.

Теги в Git

HEAD

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

Этапы

Понимание этапов очень важно для навигации по рабочему процессу Git. Они представляют собой логические переходы, на которых происходят изменения файлов до их записи в репозиторий. Разберемся в концепции этапов Git:

Этапы Git

Рабочая директория

Рабочая директория (working directory)  —  место редактирования, изменения и создания файлов проекта. Представляет текущее состояние файлов на локальном компьютере.

Индекс (область подготовленных файлов)

Индекс (staging) является местом хранения/областью перед коммитом, предполагающей подготовку изменений перед записью их в репозиторий.

Полезные команды: git add (для добавления файлов) и git rm (для удаления файлов).

Локальный репозиторий

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

Команда git commit позволит зафиксировать изменения, находящиеся в индексе.

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

Удаленный репозиторий (remote repository)  —  централизованное место, обычно размещенное на сервере (например, GitHub, GitLab или Bitbucket), где можно делиться и сотрудничать с другими участниками проекта.

Используйте такие команды, как git push и git pull, чтобы перенести изменения из локального в удаленный репозиторий.

Начало работы с Git

Отправной точкой в Git является рабочее пространство (workspace). Можете форкнуть (fork) или клонировать (clone) существующий репозиторий и получить копию этого рабочего пространства. Если же начинаете с нуля в новой локальной папке на своем компьютере, сделать ее git-репозиторием поможет команда git init. Следующий шаг, который не стоит упускать из виду,  —  настройка учетных данных.

Источник

Настройка учетных данных

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

git config --global credential.helper store

При первом взаимодействии с удаленным репозиторием Git попросит вас ввести имя пользователя и пароль. После этого запрос повторяться не будет.

Важно отметить, что учетные данные хранятся в формате простого текста в файле .git-credentials.

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

git config --global credential.helper

Работа с ветвями

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

# Отобразит изменения в локальном репозитории:
git branch
# Или же можно создать ветвь напрямую, используя
git branch feature-branch-name

Для перехода между ветвями используйте:

git switch

Перейти на новую ветку можно следующим образом:

git checkout 
# Комбинация для перехода к ветке, которая еще не создана, с помощью флага -b
git checkout -b feature-branch-name

Проверить состояние репозитория позволит команда:

git status

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

Вид терминала

Работа с коммитами

При работе с коммитами используйте git commit -m для записи изменений, git amend для модификации последнего коммита и старайтесь придерживаться соглашений о сообщениях коммитов.

# Обязательно добавьте сообщение к каждому коммиту
git commit -m "meaningful message"

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

# внесите изменения
git add .
git commit --amend
# Это откроет ваш стандартный текстовый редактор для изменения сообщения коммита, если это необходимо.
git push origin your_branch --force

Будьте осторожны при использовании параметра --force, так как он может переписать историю целевой ветви. Следует избегать его применения на основной (main/master) ветви.

В большинстве случаев лучше коммитить чаще, чем реже, чтобы не потерять прогресс и случайно не сбросить неиндексированные изменения. Впоследствии историю можно переписать, объединив несколько коммитов или выполнив интерактивное перебазирование (rebase).

Используйте git log для отображения хронологического списка коммитов, начиная с самого последнего коммита и двигаясь назад по времени.

Манипулирование историей

Манипулирование историей включает в себя несколько мощных команд:

  • Rebase переписывает историю коммитов;
  • Squashing объединяет несколько коммитов в один;
  • Cherry-picking выбирает конкретные коммиты.

Перебазирование и слияние

Имеет смысл сравнить перебазирование со слиянием, поскольку цель у них одна и та же, но достигается она разными способами. Принципиальное различие заключается в том, что при перебазировании переписывается история проекта. Это желательный выбор для сценариев, в которых важна четкая и понятная история проекта. Слияние сохраняет обе истории ветки, генерируя новый коммит слияния.

Во время перебазирования история коммитов функциональной ветки реструктурируется, поскольку переносится в HEAD основной ветки.

Перебазирование в Git

Рабочий процесс здесь довольно прост.

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

git checkout your_branch
git fetch

Теперь выберите ветвь для перебазирования и выполните эту команду:

git rebase upstream_branch

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

git push origin your_branch --force

Будьте осторожны при использовании параметра --force, так как он может переписать историю целевой ветки. Следует избегать его применения на основной ветке.

Сквошинг

Сквошинг (squashing) в Git используется для склеивания нескольких коммитов в один, целостный коммит.

Сквошинг в Git

Эту концепцию легко понять. Особенно она полезна, если в качестве метода унификации кода используется перебазирование. Поскольку история будет изменена, важно помнить о влиянии этого факта на проект. Бывали случаи, когда мне было трудно выполнить сквошинг, особенно при использовании интерактивного перебазирования, но, к счастью, есть инструменты, незаменимые в таких случаях. Мой предпочтительный метод сквошинга включает в себя перемещение указателя HEAD на X количество коммитов назад, сохраняя при этом проиндексированные изменения.

# Измените число после HEAD~ в зависимости от количества коммитов, которые хотите подвергнуть сквошингу
git reset --soft HEAD~X
git commit -m "Your squashed commit message"
git push origin your_branch --force

Будьте осторожны при использовании параметра --force, так как он может переписать историю целевой ветки. Следует избегать его применения на основной ветке.

Черри-пикинг

Выбор определенных коммитов (или черри-пикинг) полезен для избирательного включения изменений из одной ветки в другую, особенно когда слияние целых веток нежелательно или нецелесообразно. Однако важно использовать черри-пикинг с умом, так как при неправильном применении он может привести к дублированию коммитов и расхождению в истории.

Черри-пикинг в Git

Сначала нужно определить хэш коммита, который хотите выбрать. Это можно сделать с помощью git log. После определения хэша коммита выполните команду:

git checkout target_branch
git cherry-pick <commit-hash> # Сделайте это несколько раз, если хотите выбрать несколько коммитов
git push origin target_branch

Продвинутые команды Git

Подписание коммитов

Подписание коммитов (Signing commits)  —  способ проверки подлинности и целостности коммитов в Git. Он позволяет криптографически подписывать коммиты, используя ключ GPG (GNU Privacy Guard  —  программа для шифрования информации и создания электронных цифровых подписей). Таким образом, Git знает, что вы действительно являетесь автором коммита. Можете сделать это, создав ключ GPG и настроив Git на использование этого ключа при записи изменений. Вот шаги:

# Сгенерируйте ключ GPG
gpg --gen-key
# Настройте Git на использование вашего ключа GPG
git config --global user.signingkey <your-gpg-key-id>
# Добавьте открытый ключ в свою учетную запись GitHub
# Подпишите коммиты с помощью флага -S
git commit -S -m "Your commit message"
# Просмотр подписанных коммитов
git log --show-signature

Журнал Git Reflog

Тема, которую мы еще не рассматривали,  —  Git-ссылки. Они представляют собой указатели на различные объекты в репозитории, в первую очередь коммиты, а также теги и ветви. Эти указатели служат именованными точками в истории Git, позволяя пользователям перемещаться по временной шкале репозитория и получать доступ к конкретным снимкам проекта. Знание того, как ориентироваться в Git-ссылках, очень полезно. Для этого и нужен журнал Git Reflog. 

Вот некоторые из преимуществ использования этого журнала:

  • восстановление потерянных коммитов или веток;
  • отладка и устранение неполадок;
  • исправление ошибок.

Интерактивное перебазирование

Интерактивное перебазирование  —  мощная функция Git, позволяющая переписывать историю коммитов в интерактивном режиме. С ее помощью можно изменять, переупорядочивать, комбинировать и удалять коммиты перед применением их к ветви.

Чтобы использовать эту функцию, необходимо ознакомиться с возможными действиями, такими как:

  • Pick (“p“)  —  выбрать;
  • Reword (“r“)  —  перезаписать;
  • Edit (“e“)  —  редактировать; 
  • Squash (“s“)  —  сквошить;
  • Drop (“d“)  —  удалить.
Интерактивное перебазирование в Git

Вот видео, в котором показывается, как выполнить интерактивное перебазирование в терминале. Кроме того, в конце статьи будет ссылка на полезные инструменты.

Сотрудничество с Git

Origin и Upstream

Origin  —  по умолчанию удаленный репозиторий, связывающийся с локальным Git-репозиторием при его клонировании. Если вы форкнули репозиторий, то этот форк по умолчанию становится репозиторием “origin”.

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

Чтобы поддерживать форкнутый репозиторий в актуальном состоянии в соответствии с последними изменениями оригинального проекта, надо извлечь изменения из “upstream”-репозитория с помощью команды git fetch и слить или перебазировать их в локальный репозиторий.

Чтобы увидеть удаленные репозитории, связанные с локальным Git-репозиторием, выполните команду:

git remote -v

Конфликты

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

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

После ручного разрешения конфликтов в конфликтующих файлах удалите маркеры конфликтов <<<<<<<, ======= и >>>>>>> и скорректируйте код по мере необходимости.

Сохраните изменения в конфликтующих файлах, как только будете удовлетворены итогом разрешения.

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

Популярные рабочие процессы Git

Рабочие процессы Git

Git позволяет реализовывать различные рабочие процессы. Однако важно понимать, что не бывает универсального “идеального” рабочего процесса Git. У каждого подхода есть свой набор плюсов и минусов. Рассмотрим различные рабочие процессы, чтобы выяснить преимущества и недостатки каждого из них.

Feature branch workflow

Каждая новая функция или исправление ошибки разрабатывается в отдельной ветви, а затем после завершения объединяется с основной ветвью.

  • Преимущества: изоляция изменений и уменьшение конфликтов.
  • Недостатки: процесс может стать сложным и потребовать тщательного управления ветвями.

Gitflow Workflow

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

Она включает долгоживущие ветви, такие как main (основная), develop (ветвь разработки), feature branches (ветви функциональности), release branches (ветви релизов) и hotfix branches (ветви быстрых исправлений).

  • Преимущества: подходит для проектов с запланированными релизами и долгосрочным сопровождением.
  • Недостатки: может оказаться слишком сложным для небольшой команды.

Forking Workflow

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

Именно такой рабочий процесс мы используем для совместной работы над репозиториями Glasskube с открытым исходным кодом.

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

Pull Request Workflow

Похож на Forking Workflow, но вместо форков разработчики создают ветви функциональности непосредственно в основном репозитории.

  • Преимущества: облегчает изучение кода, сотрудничество и обмен знаниями между членами команды.
  • Недостатки: зависимость от рецензентов кода может привести к задержкам в процессе разработки.

Trunk-Based Development

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

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

Что такое форкинг?

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

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

Изменения, отправленные в исходный репозиторий, будут отображаться и в удаленном.

Шпаргалка по Git

# Клонирование репозитория
git clone <repository_url>

# Индексирование изменений для коммита
git add <file(s)>

# Запись изменений (коммиттинг)
git commit -m "Commit message"

# Передача изменений в удаленный репозиторий
git push

# Передача изменений с помощью force (использовать с осторожностью)
git push --force

# Сброс рабочей директории до последнего коммита
git reset --hard

# Создание новой ветви
git branch <branch_name>

# Переключение на другую ветвь
git checkout <branch_name>

# Слияние изменений из другой ветви
git merge <branch_name>

# Перебазирование изменений на другую ветвь (использовать с осторожностью)
git rebase <base_branch>

# Просмотр состояния рабочей директории
git status

# Просмотр истории коммитов
git log

# Отменить последний коммит (использовать с осторожностью)
git reset --soft HEAD^

# Отмена изменений в рабочей директории
git restore <file(s)>

# Восстановление утраченных ссылок на коммиты
git reflog

# Интерактивное перебазирование для переупорядочивания коммитов
git rebase --interactive HEAD~3

Бонус: инструменты, которые облегчат работу в Git

  • Инструмент для интерактивного перебазирования.
  • Cdiff для просмотра цветных, инкрементальных (с постепенным нарастанием изменений) диффов (текущей и предыдущей версий).
  • Интерактивная экспериментальная площадка для Git-ветвления.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Jake Page: The guide to Git I never had

Предыдущая статьяТоп-10 антипаттернов при использовании микросервисов
Следующая статьяВнедрение зависимостей в Android с помощью Koin