У врачей есть стетоскопы. У механиков — гаечные ключи. А у нас, разработчиков, — Git.
Git стал настолько неотъемлемой частью работы с кодом, что мы практически никогда не включаем его в свой технологический стек или в резюме. Предполагается, что вы уже освоили Git, или, по крайней мере, достаточно знаете, чтобы справиться с ним. Но так ли это?
Git — VCS (version control system — система контроля версий) — это популярная технология, которая позволяет хранить и изменять код, а также сотрудничать с другими разработчиками.
В качестве дисклеймера отмечу, что Git — обширная тема. Ей посвящаются учебники и посты в блогах, похожие на научные статьи. Но это не то, к чему я стремлюсь. Я не эксперт по Git. Моя цель — изложить основные сведения о Git, которых мне самому не хватало при изучении Git.
Повседневная жизнь разработчика связана с чтением, написанием и рецензированием кода. Git, пожалуй, один из самых важных инструментов, используемых при этом. Освоение возможностей и функций Git — одна из лучших инвестиций в себя как разработчика.
Базовые понятия
Не изучив как следует Git, вы рискуете постоянно впадать в раздумья, застревать на одних и тех же проблемах и жалеть о том дне, когда в вашем терминале появится очередной конфликт слияния. Чтобы этого не произошло, определим основополагающие понятия Git.
Ветви
В репозитории Git есть основная линия разработки, обычно называемая “main” или “master” (устаревшее название), от которой расходятся несколько ветвей (branches). Эти ветви представляют собой совместные рабочие процессы, позволяющие разработчикам одновременно выполнять несколько функций или исправлений в рамках одного проекта.
Коммиты
Коммиты (commits ) Git служат пакетами обновленного кода, фиксируя снимок кода проекта в определенный момент времени. Каждый коммит фиксирует изменения, сделанные с момента последнего коммита, а все вместе они создают полную историю развития проекта.
При ссылке на коммит обычно используется его уникальный криптографический хэш.
Пример:
git show abc123def456789
Хэш показывает подробную информацию о коммите.
Теги
Теги (tags) Git служат вехами в истории Git, обычно отмечая значительные события в развитии проекта, такие как releases
, versions
и standout commits
(релизы, версии или особые, чем-то примечательные коммиты). Эти теги неоценимы для обозначения определенных моментов времени, часто представляющих собой отправные точки или основные достижения на пути развития проекта.
HEAD
Самый последний коммит в текущей проверенной ветке обозначается HEAD
и служит указателем на любую ссылку в репозитории. Когда вы находитесь в определенной ветви, HEAD
указывает на последний коммит в этой ветви. Иногда, вместо того чтобы указывать на вершину ветви, HEAD
может напрямую указывать на конкретный коммит (состояние detached HEAD
).
Этапы
Понимание этапов очень важно для навигации по рабочему процессу 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 checkout your_branch
git fetch
Теперь выберите ветвь для перебазирования и выполните эту команду:
git rebase upstream_branch
После перебазирования может потребоваться принудительно отправить изменения, если ветвь уже была отправлена в удаленный репозиторий:
git push origin your_branch --force
Будьте осторожны при использовании параметра
--force
, так как он может переписать историю целевой ветки. Следует избегать его применения на основной ветке.
Сквошинг
Сквошинг (squashing) в Git используется для склеивания нескольких коммитов в один, целостный коммит.
Эту концепцию легко понять. Особенно она полезна, если в качестве метода унификации кода используется перебазирование. Поскольку история будет изменена, важно помнить о влиянии этого факта на проект. Бывали случаи, когда мне было трудно выполнить сквошинг, особенно при использовании интерактивного перебазирования, но, к счастью, есть инструменты, незаменимые в таких случаях. Мой предпочтительный метод сквошинга включает в себя перемещение указателя HEAD на X количество коммитов назад, сохраняя при этом проиндексированные изменения.
# Измените число после HEAD~ в зависимости от количества коммитов, которые хотите подвергнуть сквошингу
git reset --soft HEAD~X
git commit -m "Your squashed commit message"
git push origin your_branch --force
Будьте осторожны при использовании параметра
--force
, так как он может переписать историю целевой ветки. Следует избегать его применения на основной ветке.
Черри-пикинг
Выбор определенных коммитов (или черри-пикинг) полезен для избирательного включения изменений из одной ветки в другую, особенно когда слияние целых веток нежелательно или нецелесообразно. Однако важно использовать черри-пикинг с умом, так как при неправильном применении он может привести к дублированию коммитов и расхождению в истории.
Сначала нужно определить хэш коммита, который хотите выбрать. Это можно сделать с помощью 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
Origin и Upstream
Origin — по умолчанию удаленный репозиторий, связывающийся с локальным Git-репозиторием при его клонировании. Если вы форкнули репозиторий, то этот форк по умолчанию становится репозиторием “origin”.
Upstream — исходный репозиторий, из которого был сделан форк репозитория.
Чтобы поддерживать форкнутый репозиторий в актуальном состоянии в соответствии с последними изменениями оригинального проекта, надо извлечь изменения из “upstream”-репозитория с помощью команды git fetch и слить или перебазировать их в локальный репозиторий.
Чтобы увидеть удаленные репозитории, связанные с локальным Git-репозиторием, выполните команду:
git remote -v
Конфликты
Не паникуйте, если при попытке слияния или перебазирования ветви обнаруживаются конфликты. Это означает только то, что в репозитории есть конфликтующие изменения между разными версиями одного и того же файла или файлов. Их можно легко разрешить (в большинстве случаев).
Обычно они указываются в затронутых изменениями файлах, где 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-ветвления.
Читайте также:
- Как реализовать простой контроль версий с помощью JavaScript, чтобы лучше разобраться в Git
- Команда Git Rerere — автоматизируйте решения для устранения конфликтов слияния
- Владеешь merge - освой и rebase
Читайте нас в Telegram, VK и Дзен
Перевод статьи Jake Page: The guide to Git I never had