Git. Урок 6.
Работа с удаленным репозиторием. Модель ветвления.
Команды: clone, fetch, push, pull.

Разберемся, что такое удаленный репозиторий, и как настроить работу с ним. А также узнаем о наиболее удачной модели ветвления.

Git. Урок 6.
Работа с удаленным репозиторием.
Модель ветвления.
Команды: clone, fetch, push, pull.

Разберемся, что такое удаленный репозиторий, и как настроить работу с ним. А также узнаем о наиболее удачной модели ветвления.
Smartiqa Git cover
  • Урок: 6
  • Команды: clone, fetch, push, pull

Оглавление

1
Теоретический блок

1. Что такое удаленный репозиторий.
2. Настройка подключения удаленного репозитория. Группа команд git remote.

2.1. Добавление удаленного репозитория к существующему локальному. Команда git remote add.
2.2. Настройка подключения по HTTPS.
2.3. Настройка подключения по SSH.
2.4. Отключение удаленного репозитория от локального. Команда git remote remove.
2.5. Изменение имени удаленного репозитория. Просмотр всех удаленных репозиториев. Команды git remote rename, git remote show.
3. Клонирование удаленного репозитория. Команда git clone.
4. Получение изменений из удаленного репозитория. Команда git fetch.
5. Получение изменений из удаленного репозитория. Команда git pull.
6. Отправка изменений в удаленный репозиторий. Команда git push.
7. GitHub. Работа с репозиторием, создание форков и пулл-реквестов

7.1 Создание репозитория на GitHub
7.2 Страница репозитория на GitHub.
7.3. Создание форка репозитория на GitHub. Пулл-реквесты.
8. Модель ветвления Git
8.1. Центральный репозиторий
8.2. Основные ветки
8.3. Вспомогательные ветки
8.4. Feature-ветки.
8.5. Release-ветки.
8.6. Hotfix-ветки.

Перейти
2
Практический блок
1. Задание
2. Решение
Перейти

ТЕОРЕТИЧЕСКИЙ БЛОК

1

Что такое удаленный репозиторий

Сегодня мы познакомимся с новым понятием: удаленный репозиторий. В прошлых уроках, преимущественно в практических частях, мы уже не раз затрагивали некоторые команды для работы с удаленным репозиторием, но не говорили о них подробно. Пора это исправить!
Важно
Отметим, что здесь и далее, в качестве примера, мы будем использовать сервис хостинга удаленных репозиториев GitHub. Мы предпочитаем этот сервис за его популярность и множество дополнительных функций, о которых будет рассказано ниже. Тем не менее, если вам больше нравится другой сервис, процесс работы не будет сильно отличаться.
    Для начала давайте повторим информацию из предыдущих уроков.
    1. Распределенная система контроля версий – такая система, в которой участники хранят у себя на компьютере полную копию всех версий проекта. Такой принцип делает их независимыми от рабочего сервера.
    2. Git относится к распределенным системам контроля версий.
    Чтобы вы точно вспомнили, приведем диаграмму из первого урока:
    Распределенная система контроля версий
    Распределенная система контроля версий
    Возможно у вас возникнет вопрос: при чем здесь удаленные репозитории? Все просто: сервер по центру диаграммы и есть удаленный репозиторий. Дадим более точное определение.
    Удаленный (иногда говорят "внешний") репозиторий – это версии вашего проекта, сохраненные на удаленном сервере. Доступ к репозиторию на таком сервере может осуществляться по интернету или по локальной сети.
    Удаленный репозиторий – полноценный репозиторий, ничем не отличающийся от локального. У удаленного репозитория есть собственные ветки, собственный указатель HEAD, своя история коммитов и так далее.

    Если мы подключим удаленный репозиторий к своему локальному, то у нас появятся копии всех ссылочных объектов удаленного репозитория. То есть, например, у удаленного репозитория есть ветка main, а у нас будет копия этой ветки – origin/main. Все такие ссылочные объекты (указатели, ветки и теги) удаленного репозитория хранятся почти там же, где и у локального – в директории .git/refs/remotes/<имя_удаленного_репозитория>.
    Кстати
    Принято называть удаленные ветки (то есть ветки удаленных репозиториев), приписывая к их названию имя удаленного репозитория. Например, если у нас есть удаленный репозиторий с именем origin и веткой main, то мы будем называть такую ветку origin/main. То же мы будем делать и со всеми остальными ссылочными объектами. Это может показаться излишним, но на самом деле это добавляет определенности и позволяет не запутаться в многочисленных названиях веток.
      Как мы уже говорили в первом уроке, один из плюсов распределенной системы контроля версий заключается в том, что у вас может быть сколь угодно много удаленных репозиториев. Какие-то из них могут быть доступны только на чтение, а какие-то – на чтение и запись.

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

      Настройка подключения удаленного репозитория. Группа команд git remote.

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

      Для управления подключением удаленных репозиториев в Git предусмотрена целая группа команд – git remote. Мы рассмотрим самые частоиспользуемые команды из этой группы.

      2.1. Добавление удаленного репозитория к существующему локальному. Команда git remote add.

      Давайте разберемся, как добавить удаленный репозиторий к вашему локальному репу. Для этого в Git есть команда git remote add.

      Команда git remote add

      Формат
      git remote add <название удаленного репозитория> <ссылка на удаленный репозиторий>
      Что делает
      Подключает удаленный репозиторий к вашему под переданным именем.
      Пример
      # Подключим удаленный репозиторий под именем origin $ git remote add origin git@github.com:smartiqaorg/geometric_lib.git
      Возможно у вас возникнут вопросы: что такое имя удаленного репозитория, и откуда взять ссылку на него. Ответим на них по порядку.

      Имя удаленного репозитория в команде git remote add вы можете придумать сами. Впоследствии, при работе с этим удаленным репозиторием, вы будете обращаться к нему по придуманному имени. Принято называть удаленный репозиторий origin, но строго говоря, никаких ограничений здесь нет.

      Со ссылкой
      на удаленный репозиторий тоже все просто. Мы работаем с GitHub, поэтому эту ссылку можно взять, нажав на большую зеленую кнопку Code на странице репозитория на GitHub.
      Получение ссылки на удаленный репозиторий
      Получение ссылки на удаленный репозиторий
      Вам предложат выбрать одну из трех ссылок: для протоколов https и ssh и для клиента GitHub на компьютер. Вот примеры этих трех ссылок для репозитория geometric_lib известного вам по практическим занятиям этого курса:

      1. HTTPS-ссылка: https://github.com/smartiqaorg/geometric_lib.git
      2. SSH-ссылка: git@github.com:smartiqaorg/geometric_lib.git
      3. GitHub CLI ссылка: gh repo clone smartiqaorg/geometric_lib
      Давайте разберемся, в чем отличие. Начнем с последней - эта ссылка используется в клиенте GitHub, который нужен для упрощения работы с Git. Этот клиент можно поставить отдельно, но его возможности значительно ограничены по сравнению с консольным вариантом Git.

      Итак, с последней ссылкой все понятно: ее нужно использовать в специальной программе для компьютера с графическим UI от создателей GitHub. Но в чем разница между первыми двумя?

      Дело в том, что существует два основных протокола подключения к git-серверу: HTTPS и SSH. SSH считается более надежным, но он немного сложнее в настройке. Давайте разберемся, как настроить подключение для каждого из них. А окончательный выбор протокола оставим на вкус читателя.

      2.2. Настройка подключения по HTTPS

      Раньше можно было подключаться по HTTPS, используя имя пользователя и пароль от аккаунта GitHub. Но потом эту возможность отключили в целях безопасности. Сейчас вместо пароля нужно использовать персональный токен. Давайте разберемся, как создать такой токен.

      Итак, чтобы создать токен персонального доступа, следуйте инструкции:
      1. Подтвердите свой email-адрес, который вы использовали при регистрации аккаунта GitHub (если он не подтвержден
      2. Кликните на свою аватарку в правом верхнем углу, в открывшемся окне выберите Settings (Настройки):
      3. Перед вами откроются настройки. В меню слева выберите Developer settings (Настройки разработчика)
      4. Перед вами откроются Настройки разработчика. В меню слева выберите Personal access tokens (токены персонального доступа).
      5. Нажмите Generate new token (сгенерировать новый токен)
      6. Придумайте имя для своего токена. Имя должно описывать, зачем токен был создан.
      7. Дайте токену разрешения. Пользователь токена сможет выполнять с удаленным репозиторием только то, что вы указали в этих разрешениях. Чтобы дать токену доступ к управлению удаленным репозиторием из командной строки, выберите repo.
      8. Нажмите Generate token (сгенерировать токен).
      Пример токена
      
      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
      
      
      9. Скопируйте токен. В целях безопасности, как только вы покинете страницу создания токена, вы больше не сможете просмотреть этот токен.
      Отлично, ваш токен готов! При первой загрузке/скачивании изменений из удаленного репозитория, вас попросят ввести имя пользователя на GitHub и пароль. Нужно будет ввести свое имя пользователя, а вместо пароля вставить этот токен.

      2.3. Настройка подключения по SSH

      Чтобы настроить подключение по SSH, вам нужно на своем компьютере сгенерировать два SSH-ключа: публичный (public) и секретный (private).
      Немного про SSH
      Как работает SSH протокол и зачем ему ключи? Если коротко, то публичный ключ передается на удаленный сервер, а секретный все время остается с вами. Удаленный сервер использует публичный ключ, чтобы удостовериться, что у вас действительно есть секретный ключ. Как только сервер убеждается в наличии у вас секретного ключа, он понимает, что вы – это вы, ведь секретный ключ нельзя подделать.
      После создания пары ключей, надо добавить секретный ключ в SSH-агента.
      Про SSH агента
      SSH-агент – это специальная программа, которая сохраняет пароль от файла с секретным ключом и помогает удаленному серверу удостовериться, что вы действительно владеете секретным ключом. Благодаря SSH-агенту, вам не потребуется при каждом подключении к удаленному серверу вводить пароль от файла с приватным ключом.
      После останется только загрузить наш публичный ключ на GitHub и готово. Давайте рассмотрим этот процесс подробнее:

      1. Откройте Git Bash (или терминал, если вы работаете на Linux/MacOS)
      2. Выполните в нем команду ssh-keygen -t rsa 4096 -C "<ваша-почта>@example.com"
      2.1. Вам предложат ввести путь к директории, в которой будет сохранен ключ, а также будет выведена директория для сохранения по умолчанию. Нажмите Enter, чтобы выбрать директорию по умолчанию, либо введите любую другую директорию и тоже нажмите Enter.
      2.2. Затем вам предложат ввести пароль для файла с секретным ключом. Нажмите Enter, чтобы оставить файл без пароля, либо введите пароль и нажмите Enter.
      3. Теперь нужно добавить ключ в SSH-агента. Запустим агента командой eval `ssh-agent -s`
      4. Теперь выполните команду ssh-add <путь до приватного ключа>. Если вы оставили путь по умолчанию, ваша команда будет выглядеть так: ssh-add ~/.ssh/id_ed25519
      5. Отлично, последний этап: добавляем публичный ключ на GitHub. Для этого откройте файл с публичным ключом (он должен иметь расширение .pub). Если вы оставили путь по умолчанию, то ваш ключ будет располагаться по адресу ~/.ssh/id_ed25519.pub.
      6. Скопируйте содержимое файла.
      7. Перейдите в настройки GitHub
      8. Откройте раздел SSH and GPG keys (ssh и gpg ключи)
      Раздел “SSH and GPG keys” и кнопка “New SSH key”
      Раздел "SSH and GPG keys" и кнопка "New SSH key"
      9. Нажмите New SSH key (новый ssh-ключ)
      10. В поле Title (заголовок) введите содержательное название ключа, например ключ для ноутбука или ключ рабочего компьютера
      Заполнение полей SSH ключа
      Заполнение полей SSH ключа
      11. Скопированный ключ вставьте в раздел Key (ключ)
      12. Нажмите Add SSH key (добавить ssh-ключ)
      13. Возможно потребуется ввести пароль для подтверждения действия.

      Теперь SSH-ключ добавлен. Вам больше не нужно вводить имя пользователя и пароль при каждой загрузке или скачивании изменений из удаленного репозитория.

      2.4. Отключение удаленного репозитория от локального. Команда git remote remove.

      Иногда возникает необходимость забыть удаленный репозиторий. Для этого существует команда git remote remove.

      Команда git remote remove

      Формат
      git remote remove <название удаленного репозитория>
      Что делает
      Отключает переданный удаленный репозиторий от вашего.
      Пример
      # Отключим удаленный репозиторий с именем origin
      $ git remote remove origin

      Данная команда предельно проста в использовании. В качестве имени репозитория нужно передавать то имя, которое вы указывали в команде git remote add. Заметьте, данная команда не удаляет удаленный репозиторий с сервера, она удаляет только подключение вашего репозитория к удаленному.

      2.5. Изменение имени удаленного репозитория. Просмотр всех удаленных репозиториев. Команды git remote rename, git remote show.

      Иногда возникает необходимость переименовать удаленный репозиторий. Для этого существует команда git remote rename.

      Команда git remote rename

      Формат
      git remote rename <старое имя удаленного репозитория> <новое имя удаленного репозитория>
      Что делает
      Меняет имя переданного удаленного репозитория
      Пример
      # Переименуем удаленный репозиторий с origin на upstream
      $ git remote rename origin upstream

      Еще более частая задача – просмотреть список всех подключенных удаленных репозиториев и получить информацию о каждом из них. Для этого существует команда git remote show.

      Команда git remote show

      Формат
      git remote show [имя удаленного репозитория]
      Что делает
      Выводит список всех подключенных удаленных репозиториев. Если передано имя репозитория, то выводит информацию об этом репозитории.
      Пример
      # Выведем список всех удаленных репозиториев
      $ git remote show
      origin
      upstream

      # Выведем информацию про репозиторий origin
      $ git remote show origin
      * remote origin
      Fetch URL: git@github.com:smartiqaorg/geometric_lib.git
      Push URL: git@github.com:smartiqaorg/geometric_lib.git
      HEAD branch: develop
      Remote branch:
      develop new (next fetch will store in remotes/origin)
      Local ref configured for 'git push':
      dev pushes to develop (up to date)

      Таким образом можно просмотреть информацию о каждом из подключенных удаленных репозиториев.
      3

      Клонирование удаленного репозитория.
      Команда git clone.

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

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

      Команда git clone

      Формат
      git clone <ссылка на удаленный репозиторий>
      Что делает
      Клонирует переданный репозиторий на ваш компьютер.
      Пример
      # Склонируем себе репозиторий geometric_lib
      $ git сlone https://github.com/smartiqaorg/geometric_lib.git

      Ссылку на удаленный репозиторий можно получить тем же способом, что мы разбирали выше. Нужно нажать на зеленую кнопку Code на главной странице репозитория на GitHub.

      Заметьте, что клонирование по https возможно вообще всегда, а по ssh – нет. Чтобы клонировать репозитории по ssh, нужно, чтобы владелец удаленного репозитория на GitHub добавил к себе публичный ssh-ключ из пары, в то время, как секретный ssh-ключ от той же пары хранится у вас на компьютере, с которого вы выполняете git clone. Таким образом, если вы настроили ssh в своем аккаунте, то вы сможете беспрепятственно клонировать свои репозитории и по https, и по ssh. Но если вы пытаетесь клонировать чужой репозиторий по ssh, то скорее всего получите ошибку доступа.
      Важно
      Окончательный выбор протокола для клонирования, конечно, остается за читателем. Работать по https проще и быстрее, зато он считается менее защищенным, чем ssh, который в свою очередь труднее в настройке.
      Давайте на примере разберем, как происходит клонирование. Клонируем уже знакомый нам репозиторий geometric_lib. При выполнении команды git сlone https://github.com/smartiqaorg/geometric_lib.git произойдет следующее:

      1. В директории, откуда вы запустили команду git clone, создается директория с именем репозитория. В нашем случае, если мы выполнили команду из директории пользователя, будет создана папка C:\users\smartiqa\geometric_lib\.
      2. В созданную директорию копируется репозиторий, все его ветки и коммиты.
      3. В новосозданный локальный репозиторий добавляется удаленный репозиторий с именем origin и ссылкой, которую мы передавали в git clone. Это избавляет нас от необходимости вручную писать git remote add origin https://github.com/smartiqaorg/geometric_lib.git. На этом процесс клонирования заканчивается.
      Кстати
      Вместо git clone можно было бы создать пустой локальный git-репозиторий, выполнив команду git init. Затем подключить наш удаленный репозиторий командой git remote add origin https://github.com/smartiqaorg/geometric_lib.git. После чего вручную загрузить изменения с удаленного репозитория командой git pull, которую мы рассмотрим ниже. Но зачем делать что-то вручную, если для этого есть автоматизированный инструмент из коробки.
      4

      Получение изменений из удаленного репозитория. Команда git fetch

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

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

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

        Команда git fetch

        Формат
        git fetch [ключи] [имя удаленного репозитория]
        Ключи
        --all
        Получает изменения из всех подключенных удаленных репозиториев.
        Что делает
        Получает изменения из переданного удаленного репозитория. Если не было передано ни одного удаленного репозитория, ни ключа --all, команда пытается получить изменения из репозитория с именем origin.
        Пример
        # Получим изменения из удаленного репозитория
        $ git fetch origin

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

        Давайте рассмотрим пример, чтобы разобраться, что на самом деле делает git fetch. Допустим, у нас есть репозиторий, к которому подключен удаленный репозиторий. Структура рабочих копий и логи выглядят следующим образом:
        Локальный репозиторий
        
        ├── alpha.txt
        └── num.txt
        
        * 47573c7 | 2021-05-10 | Initial commit | [Smartiqa] |  (HEAD -> dev, origin/develop)
        
        Удаленный репозиторий
        
        ├── alpha.txt
        ├── new_file.txt
        └── num.txt
        
        * b9ad22e | 2021-05-10 | New commit | [Smartiqa] |  (HEAD -> develop, origin/develop)
        * 47573c7 | 2021-05-10 | Initial commit | [Smartiqa] |
        
        Как видно, в удаленном репозитории есть один коммит, которого нет у нас. В этом коммите был добавлен файл new_file.txt. Кроме того видно, что наша копия удаленной ветки origin/dev находится на первом коммите, хотя должна быть на втором. Чтобы обновить информацию для этой ветки, нам и понадобится git fetch. Выполним команду git fetch origin:
        Git Bash
        
        $ git fetch origin
        remote: Enumerating objects: 4, done.
        remote: Counting objects: 100% (4/4), done.
        remote: Compressing objects: 100% (2/2), done.
        remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
        Unpacking objects: 100% (3/3), 287 bytes | 143.00 KiB/s, done.
        From github.com:smartiqaorg/test-repo
           47573c7..b9ad22e  develop -> origin/develop
        
        В выводе команды видно, что она скачала несколько объектов, а из последней строчки мы узнаем, что ветка develop удаленного репозитория была записана в ветку origin/develop на нашем компьютере.

        Давайте посмотрим, как теперь выглядит история и рабочая копия локального репозитория.
        Локальный репозиторий
        
        ├── alpha.txt
        └── num.txt
        
        * b9ad22e | 2021-05-10 | New commit | [Smartiqa] |  (origin/develop)
        * 47573c7 | 2021-05-10 | Initial commit | [Smartiqa] |  (HEAD -> develop)
        
        
        На первый взгляд может показаться, что произошло что-то очень странное: новый коммит появился, а файл, который он добавляет – нет. На самом деле, файл тоже появился, просто рабочая копия не была обновлена. Это видно и из истории репозитория: у нас есть две отдельные ветки: develop и origin/develop. Причем указатель HEAD, который, как мы помним, отвечает за состояние рабочей копии, находится на ветке develop. Что ж, давайте попробуем выполнить самое очевидное: переключим HEAD на ветку origin/develop.
        Git Bash
        
        $ git checkout origin/develop
        Note: switching to 'origin/develop'.
        
        You are in 'detached HEAD' state. You can look around, make experimental
        changes and commit them, and you can discard any commits you make in this
        state without impacting any branches by switching back to a branch.
        
        If you want to create a new branch to retain commits you create, you may
        do so (now or later) by using -c with the switch command. Example:
        
          git switch -c <new-branch-name>
        
        Or undo this operation with:
        
          git switch -
        
        Turn off this advice by setting config variable advice.detachedHead to false
        
        HEAD is now at b9ad22e New commit
        
        Вот это да, мы как-то оказались в состоянии detached HEAD, хотя вроде бы переключались на ветку. Сейчас разберемся с этим, но сначала давайте проверим, обновилась ли наша рабочая копия:
        Локальный репозиторий
        
        ├── alpha.txt
        ├── new_file.txt
        └── num.txt
        
        Все как мы и ожидали, новый файл появился в рабочей копии. Но почему мы оказались в состоянии detached HEAD, если переключались на ветку? Все просто: хоть origin/develop и считается веткой, это ветка не нашего, а удаленного репозитория. Если вы сделаете какие-то коммиты или как-то еще попытаетесь изменить ветку origin/develop, все эти изменения будут потеряны при следующем git fetch. Файл .git/refs/remotes/origin/develop, в котором хранится хэш коммита, на который указывает ветка origin/develop, будет просто переписан. В него запишется тот хэш, на который указывает ветка удаленного репозитория. Все коммиты, которые вы самостоятельно сделали на этой ветке, будут утеряны: на них не останется ссылок. Отсюда и состояние detached HEAD.

        Но что же делать, – спросите вы, – как объединить две ветки в одну? В прошлом уроке мы изучили специально созданную для этого команду – git merge.
        Git Bash
        
        # Переключимся обратно на ветку develop
        $ git checkout develop
        Switched to branch 'develop'
        Your branch is behind 'origin/develop' by 1 commit, and can be fast-forwarded.
          (use "git pull" to update your local branch)
        
        # Сольем ветку origin/develop в ветку develop
        $ git merge origin/develop
        Updating 47573c7..b9ad22e
        Fast-forward
         new_file.txt | 1 +
         1 file changed, 1 insertion(+)
         create mode 100644 new_file.txt
        
        После выполнения git checkout даже сам Git напомнил нам, что наша ветка отстает от origin/develop на 1 коммит. Правда, он посоветовал выполнить git pull вместо git merge, но уже в следующем разделе мы поймем, что это одно и то же.

        Кстати, в выводе команды git merge можно заметить, что слияние прошло в fast-forward режиме. Именно поэтому не было создано merge-коммита. На самом деле, слияние удаленной ветки очень часто можно выполнить в fast-forward режиме, но иногда все-таки приходится разрешать конфликты и создавать merge-коммиты.
        Подведем итог
        Команда git fetch используется для синхронизации локальных ссылочных объектов с этими же объектами в удаленном репозитории. Рабочую копию она не меняет.
        Чтобы синхронизировать локальную рабочую копию с удаленным репозиторием, нужно слить удаленные ветки в локальные. Сделать это можно уже знакомой командой git merge.
        5

        Получение изменений из удаленного репозитория. Команда git pull

        Связкой git fetch && git merge мы получили изменения из удаленного репозитория и обновили свою рабочую копию. Часто вместо этого хочется получать изменения и сразу обновлять рабочую копию так, чтобы она соответствовала удаленному репозиторию. И для этого в Git существует отдельная команда. Называется она git pull.

        Команда git pull

        Формат
        git pull [ключи] [имя удаленного репозитория]
        Ключи
        --ff
        --no-ff
        --ff-only

        Эти ключи определяют стратегию слияния. --ff – включить fast-forward, если это возможно, --no-ff – отключить fast-forward, а --ff-only – остановить pull, если его невозможно сделать в fast-forward.
        Что делает
        Получает изменения из переданного удаленного репозитория и обновляет рабочую копию в соответствии с удаленным репозиторием. По умолчанию слияние удаленной ветки с локальной происходит именно в fast-forward режиме, так что включать его специально не требуется
        Пример
        # Обновим нашу рабочую копию в соответствии с удаленным репозиторием
        $ git fetch origin

        На самом деле, новых команд здесь нет. Команда git pull это просто сокращение последовательного применения git fetch и git merge. Но используется git pull намного чаще.
        Подведем итог
        Команда git pull используется для синхронизации локальной рабочей копии и всех ссылочных объектов с удаленным репозиторием.
        По сути, git pull - это то же самое, что git fetch + git merge.
        6

        Отправка изменений в удаленный репозиторий. Команда git push

        Мы знаем почти все про удаленный репозиторий. Осталось изучить, как загружать в него свои локальные изменения. Для этого в Git существует команда git push.

        Команда git push

        Формат
        git push [ключи] [имя удаленного репозитория] [имя ветки]
        Ключи
        --all
        Пушит все имеющиеся ветки

        -f, --force
        Перезаписывает удаленную ветку, вне зависимости от ее содержимого. Старайтесь не использовать этот флаг без крайней необходимости.

        --force-with-lease
        Удаляет все коммиты, которых нет в локальном репозитории. Если коммит, который команда соберется удалять был создан другим пользователем, то выполнение закончится с ошибкой.
        Что делает
        Загружает изменения в удаленный репозиторий. Если слияние изменений в удаленном репозитории нельзя сделать в режиме fast-forward, и при этом не был передан ключ force, выполнение закончится с ошибкой.
        Пример
        # Загрузим все изменения с текущей ветки в удаленный репозиторий
        $ git push origin develop

        По факту данная команда аналогична связке git fetch + git merge, но выполненной из удаленного репозитория (это просто аналогия, на самом деле так сделать не получится).

        Давайте более подробно разберем, как работает эта команда. Допустим, мы выполнили git push origin develop в нашем локальном репозитории. Возможны три варианта развития событий.

        Если изменения с нашей ветки можно слить с удаленной веткой в режиме fast-forward, то есть на удаленной ветке нет коммитов сделанных после наших, то все пройдет нормально.

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

        Но если вы вдруг передали флаг --force, то все коммиты, которых нет в вашем локальном репозитории, будут удалены. То есть удаленный репозиторий станет точной копией вашего локального. Есть более щадящая версия этого флага – --force-with-lease. Он будет делать в точности то же самое, но если вдруг нужно будет удалить коммит, созданный не вами, выполнение немедленно прекратится и вернется ошибка. Таким образом, вы не попадете в ситуацию, когда вы случайно удалили чужой коммит.
        7

        GitHub. Работа с репозиторием,
        создание форков и пулл-реквестов

        Научившись работать с локальным репозиторием, освоим основы работы с GitHub. Итак, если коротко, то GitHub – это, наверное, самый популярный сервис бесплатного хостинга удаленных репозиториев с множеством дополнительных функций. Среди них есть, например, создание issue – запросов, в которых можно сообщить разработчикам об ошибках, создание репозиториев-форков и пулл-реквестов. Кроме того, на GitHub можно подписаться на обновления какого-то конкретного пользователя или включить отслеживание репозитория вашего любимого проекта. Все это превращает GitHub в настоящую социальную сеть для разработчиков по всему миру. Давайте приступим к изучению основ работы с этим сервисом.

        7.1 Создание репозитория на GitHub

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

        Чтобы создать свой репозиторий, нажмите на зеленую кнопку New, как показано на рисунке.
        Создание репозитория - кнопка “New”
        Создание репозитория - кнопка "New"
        Перед вами откроется страница создания репозитория. Давайте разберем, что за поля нам предлагают заполнить.

        1. Итак, первое поле Repository name – имя репозитория. Здесь все просто, вам нужно придумать имя, которое будет отображаться на странице вашего репозитория. Здесь нет никаких ограничений, но старайтесь давать как можно более содержательные имена своим репозиториям.
        2. Второе поле – Description – описание. Его заполнять необязательно. Но другим пользователям, которые попали на страницу вашего репозитория, будет проще понять, что перед ними, если вы заполните графу описания.
        3. Затем вы можете выбрать, будет ли репозиторий открытым, то есть доступным абсолютно всем пользователям GitHub, или закрытым, то есть доступным только вам и людям, которым вы предоставите доступ.
        4. Последние три поля предлагают нам добавить, соответственно, README-файл, .gitignore файл и выбрать лицензию для нашего проекта.

        После заполнения полей страница выглядит примерно так.
        Заполненная страница создания репозитория
        Заполненная страница создания репозитория
        Заметьте, мы не стали вводить описание репозитория, поскольку решили добавить в него README-файл, хотя иногда и можно продублировать самую основную информацию из README в описании.

        Завершим процесс создания репозитория, нажав кнопку Create repository.

        7.2 Страница репозитория на GitHub.

        После создания репозитория, мы попадем на его страницу на GitHub. В нашем случае эта страница будет выглядеть так.
        Страница репозитория на GitHub
        Страница репозитория на GitHub
        Как видно из рисунка, GitHub автоматически создал первый коммит, добавив в него файл .gitignore и файл README.

        Кстати, можно заметить, что содержимое файла README выводится под рабочей копией репозитория. Это одна из особенностей GitHub. Вы в любое время можете создать файл с именем README.md и запушить его в свой удаленный репозиторий на GitHub. Тогда содержимое этого файла будет отображаться прямо на странице вашего репозитория.

        В верхнем меню мы видим 9 разных вкладок. Давайте разберем их по порядку.

        1. Вкладка Code. Сейчас открыта именно она. В ней содержится рабочая копия нашего репозитория (по центру), описание (справа), вывод файла README (под рабочей копией), история коммитов, а также кнопки для клонирования репозитория и просмотра файлов.
        2. Вкладка Issues. В этой вкладке будут отображаться все запросы, сделанные другими пользователями. Как правило, пользователи используют запрос, чтобы сообщить о найденном баге, либо чтобы задать какой-то вопрос о вашем приложении.
        3. Вкладка Pull-requests. На этой вкладке будут отображаться все пулл-реквесты, сделанные другими пользователями. О том, что такое пулл-реквесты, мы поговорим ниже.
        4-5. Вкладки Actions и Project относятся скорее к системе CI/CDI, которую предоставляет GitHub, в этом курсе мы не будем затрагивать их.
        6. Вкладка Wiki открывает вам доступ к созданию и размещению документации о собственном проекте.
        7. На вкладке Security содержатся различные настройки безопасности вашего проекта. Там же можно включить инспекцию вашего кода, чтобы узнать, если вы случайно загрузите какой-нибудь секретный токен на GitHub.
        8. Вкладка Insight содержит различную информацию и статистические данные об активности репозитория. Там вы сможете посмотреть на зависимость количества коммитов в репозитории от времени или на процент коммитов, сделанных вами.
        9. Последняя вкладка – Settings. В ней находятся различные настройки вашего репозитория. Там вы можете поменять видимость репозитория, сделав его частным, или вовсе удалить репозиторий.

        7.3. Создание форка репозитория на GitHub. Пулл-реквесты.

        Итак, одной из самых важных частей GitHub является создание форков.
        Форк (от англ. fork – вилка) – точная копия репозитория, но в вашем аккаунте. Форки нужны, чтобы вносить свои изменения в проект, к репозиторию которого у вас нет прямого доступа.
        Пулл-реквест (от англ. pull-request – запрос pull) – функция GitHub, позволяющая попросить владельца репозитория, от которого мы сделали форк, загрузить наши изменения обратно в свой репозиторий.
        Если коротко, форки и пулл-реквесты нужны, чтобы любой пользователь мог внести свой вклад в любой открытый проект, репозиторий которого есть на GitHub. Кроме того, перед тем как влить ваши изменения в основной репозиторий, ответственные обязательно проверят ваш код на наличие ошибок и уязвимостей. Таким образом, даже если ваши изменения не примут, вы получите первоклассный code-review с указанием всех неточностей.

        Теперь давайте рассмотрим пайплайн контрибуции (англ. contribution – внесение вклада) на примере реального репозитория. То есть научимся вносить свой вклад в разработку проектов с открытым исходным кодом на GitHub.

        1. Для начала зайдем на страницу репозитория проекта. Нажимаем на кнопку Fork, как показано на картинке. После этого Git создаст точную копию этого репозитория в вашем аккаунте.
        Кнопка Fork
        Кнопка Fork
        Fork-нутый репозиторий
        Fork-нутый репозиторий
        2. Клонируем репозиторий к себе на компьютер командой git clone. Создадим файл README.md с описанием проекта, чтобы другим пользователям было понятно, в чем отличие этой реализации от остальных.

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

        4. Теперь GitHub подсказывает нам, что наша ветка опережает ветку исходного репозитория на один коммит и предлагает сделать пулл-реквест.
        Подсказка GitHub
        Подсказка GitHub
        5. Нажимаем на кнопку Compare на подсказке GitHub, либо переходим на вкладку Pull Requests и нажимаем New pull request.
         Создание пулл-реквеста
        Создание пулл-реквеста
        6. Перед нами откроется страница создания пулл-реквеста.
        Страница пулл-реквеста
        Страница пулл-реквеста
        Здесь мы можем просмотреть внесенные изменения и выбрать две ветки: одну в исходном репозитории, на нее будут залиты наши изменения, вторую – в нашем репозитории, с нее будут скачаны изменения. Как только мы выбрали ветки и убедились, что не внесли никаких лишних изменений, нажимаем кнопку Create pull request.

        7. Теперь мы попадаем на страницу описания наших изменений.
        Описание пулл-реквеста
        Описание пулл-реквеста
        Здесь необходимо описать, что за изменения вы внесли и почему они были необходимы. Сообщение, которое оставили мы, видно на картинке. Оно отражает суть и необходимость внесенных изменений. Как только мы закончили с описанием, можно нажимать кнопку Create pull request.

        8. Теперь мы попадаем на страницу уже созданного пулл-реквеста в изначальном репозитоии. В нашем случае он выглядит так.
        Страница созданного пулл-реквеста
        Страница созданного пулл-реквеста
        Именно так будет выглядеть наш пулл-реквест и для владельца репозитория. На этой странице он сможет писать комментарии, указывая на ошибки или задавая вопросы. После того, как владелец репозитория просмотрит наши изменения и убедится, что они не имеют вредоносный характер, он сможет принять наш пулл-реквест. Тогда все изменения, добавленные в этот пулл-реквест нами, будут залиты в исходный репозиторий.
        Подытожим
        Таким образом, вы можете вносить свой вклад в абсолютно любые приложения с открытым программным кодом. Даже репозиторий самого Git хранится на GitHub, и вы в любой момент можете сделать форк и придумать новую команду (правда не факт, что ответственный примет ваш пулл-реквест). Вы можете внести свой вклад в разработку ядра Linux, в популярный редактор Visual Studio Code, в ядро криптовалюты Bitcoin, в языки программирования Python, Go, Ruby – все эти проекты имеют открытые репозитории на GitHub.
        8

        Модель ветвления Git

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

        8.1. Центральный репозиторий

        Итак, основой нашей модели будет центральный репозиторий. Строго говоря, в Git не может быть никаких центральный репозиториев, поскольку это распределенная система контроля версий. Поэтому центральный репозиторий является таковым только с точки зрения логики его использования, с технической же точки зрения – это точно такой же репозиторий, как и все остальные. У каждого из разработчиков в команде есть копия основного репозитория. Схематически ситуация выглядит так.
        Основной репозиторий проекта (origin) и репозитории разработчиков
        Основной репозиторий проекта (origin) и репозитории разработчиков
        Центральный репозиторий на картинке назван origin. Как мы уже упоминали выше, это одно из общепринятых наименований в Git.

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

        8.2. Основные ветки

        В нашей модели существуют две главные ветки:
        1. main – ветка, в которой содержится только код, готовый к релизу.
        2. develop – ветка, в которой содержатся изменения, готовые ко включению в последующий релиз.

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

        Как только в ветке develop появляется достаточно изменений для создания нового релиза, она вливается в ветку main (напрямую или посредством создания специальной ветки release-*, о которой мы поговорим позже). После чего соответствующий коммит слияния в ветке main помечается тегом с указанием версии релиза (напомним, что тег – это статический указатель, нужный для удобства переключения между коммитами).

        Таким образом, коммит в ветке origin/main означает выпуск нового релиза. Кстати, если строго придерживаться этого правила, можно организовать непрерывную интеграцию при помощи как встроенных средств GitHub, так и сторонних инструментов, специализирующихся на CI/CDI.

        8.3. Вспомогательные ветки

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

        Наша модель предполагает существование следующих групп вспомогательных ветвей:
        1. Ветви для разработки новых функций. Они же feature branches.
        2. Ветви релизов, то есть release branches.
        3. Ветви срочных исправлений – hotfix branches.

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

        8.4. Feature-ветки

        Могут порождаться от: develop
        Могут вливаться в: develop
        Правило именования: любое имя, кроме main, develop, release-*, hotfix-*.

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

        Feature-ветки существуют в основном только в репозиториях разработчиков, но могут на некоторое время появиться и в центральном репозитории.

        Графически взаимодействие разработчика с feature-веткой выглядит примерно так:
        Работа с feature-веткой в репозитории разработчика
        Работа с feature-веткой в репозитории разработчика
        Создать feature-ветку можно следующим образом:
        Git Bash
        
        # Переключимся на главную ветвь develop
        $ git checkout develop
        # Создадим feature-ветку
         $ git checkout -b new-feature
        
        После завершения работы над функцией, вы можете выполнить слияние и Push:
        Git Bash
        
        # Переключимся на главную ветвь develop
        $ git checkout develop
        # Сольем нашу feature-ветку явным образом
         $ git merge --no-ff new-feature
        # Удалим нашу feature-ветку
         $ git branch -d new-feature
        # Выполним пуш изменений в основной репозиторий
         $ git push origin develop
        
        Заметьте, мы специально выполнили merge в режиме non-fast-forward. Дело в том, что хоть fast-forward и удобнее в некоторых случаях, в данном все же лучше использовать явное слияние. Явное слияние позволяет сохранить информацию о том, что ветка new-feature существовала, и объединяет все ее коммиты в один merge-коммит. Впоследствии это позволит разобраться, какие коммиты отвечают за добавление одних и тех же функций. Кроме того, сливая ветку явным образом, мы оставляем себе обходной путь: отменить такое слияние намного проще, чем отменять слияние fast-forward.

        8.5. Release-ветки

        Могут порождаться от: develop
        Могут вливаться в: develop, main
        Правило именования: release-*

        Ветки релизов необходимы для подготовки к выпуску новых релизов вашего продукта. Их главное назначение – внести финальные штрихи перед выпуском новой версии. В этих ветках можно вносить небольшие изменения и подготавливать файлы с метаданными о версии вашего продукта. Release-ветку следует создавать в тот момент, когда ваш проект готов или почти готов к выпуску очередной версии. По крайней мере не раньше, чем вся функциональность, предназначенная к выходу в этом релизе, будет влита в ветку develop.

        Решение о номере версии релиза принимается только после создания release-ветки и опирается на принятые в компании правила нумерации версий. До тех пор неясно, будет ли новый релиз иметь версию 4.1.5, 4.2 или 5.0. Создать release-ветку можно следующим образом.
        Git Bash
        
        # Переключимся на главную ветвь develop
        $ git checkout develop
        # Создадим release-ветку
         $ git checkout -b release-4.2
        
        Заметьте, мы приняли решение, что новая версия будет иметь номер 4.2, а потому создали ветку с именем release-4.2. Работая в этой ветке, мы можем исправить незначительные ошибки и внести метаинформацию о версии проекта в соответствующие файлы. Обратите внимание, что на этой ветви запрещено вносить какие-то крупные изменения или исправлять серьезные ошибки, ее предназначение не в этом.

        Как только все файлы вашего проекта будут готовы к выпуску релиза, данную ветвь можно слить в основную ветку main, что и будет соответствовать выпуску релиза. После чего нужно пометить релиз соответствующим тегом, чтобы впоследствии к нему было проще обращаться. Важно не забыть слить изменения с release-ветки в ветку develop, чтобы вернуть наши незначительные изменения в процесс разработки следующего релиза.
        Git Bash
        
        # Переключимся на основную ветвь main
        $ git checkout main
        # Сольем в нее нашу release-ветку
        $ git merge --no-ff release-4.2
        # Присвоим коммиту тег
        $ git tag -a v4.2
        # Переключимся на основную ветку develop
        $ git checkout develop
        # Сольем в нее нашу release-ветку, чтобы вернуть внесенные изменения в разработку
        $ git merge --no-ff release-1.2
        # Теперь можно удалить release-ветку
        $ git branch -d release-1.2
        

        8.6. Hotfix-ветки

        Могут порождаться от: main
        Могут вливаться в: develop, main
        Правило именования: hotfix-*

        Ветки срочных исправлений или hotfix-ветки, нужны для внесения срочных исправлений в уже вышедший релиз. Такую ветку необходимо создать в ситуации, когда в недавно вышедшем релизе был обнаружен серьезный баг. Предназначение этой ветки – исправить ошибку в последнем вышедшем релизе, а затем выпустить новый релиз, слив ветку hotfix в main и develop. Смысл создания отдельной ветки в том, что работа большей части команды может продолжаться над выходом нового стабильного релиза на ветке develop, пока bugfix-команда работает над исправлением ошибки в последнем релизе в ветке hotfix.

        Чтобы создать hotfix-ветку, выполните:
        Git Bash
        
        # Переключимся на главную ветвь main
        $ git checkout main
        # Создадим hotfix-ветку для последнего релиза
         $ git checkout -b hotfix-4.2.1
        
        Последний релиз имеет номер 4.2, поэтому мы приняли решение, что релиз с исправлением бага в релизе 4.2 будет иметь версию 4.2.1.

        После внесения всех необходимых исправлений, нужно слить hotfix-ветку в ветку main, чтобы выпустить новый релиз, и в ветку develop, чтобы наши изменения сохранились в следующем релизе. Сделаем это.
        Git Bash
        
        # Переключимся на основную ветвь main
        $ git checkout main
        # Сольем в нее нашу hotfix-ветку
        $ git merge --no-ff hotfix-4.2.1
        # Присвоим коммиту тег
        $ git tag -a v4.2.1
        # Переключимся на основную ветку develop
        $ git checkout develop
        # Сольем в нее нашу hotfix-ветку, чтобы сохранить исправление бага в следующем релизе 
        $ git merge --no-ff hotfix-4.2.1
        # Теперь можно удалить hotfix-ветку
        $ git branch -d hotfix-4.2.1
        
        Подытожим
        Модель, показанная нами выше, не является абсолютно новой. Тем не менее, в проект, разработка которого ведется в соответствии с данной моделью ветвления, очень легко вникнуть. У каждой ветки здесь есть свое строго регламентированное назначение, благодаря чему и достигается интуитивное понимание процесса разработки.

        ПРАКТИЧЕСКИЙ БЛОК

        1

        Задание

        В теоретической части урока мы с вами научились работать с удаленными репозиториями и, в частности, сервисом хостинга удаленных репозиториев GitHub. Пора закрепить эти знания на практике. Как и в предыдущих уроках работать будем с уже знакомым нам репозиторием geometric_lib.
        Условие

        1. Зарегистрируйтесь на GitHub и подтвердите свою почту.

        2. Настройте SSH или HTTPS подключение (на ваш выбор). Мы будем работать по HTTPS.

        3. Теперь перейдите на страницу https://github.com/smartiqaorg/geometric_lib/ и создайте свой форк.

        4. Склонируйте к себе свой форк репозитория geometric_lib.

        5. Настройте локального пользователя Git

        6. Измените файл docs/README.md. Сделайте коммит.

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

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

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

        Разбор задания

        На странице Задания и Ответы по курсу Git мы даем подробный разбор текущего задания.
        Приводим в нем не только команды Git, но и их консольный вывод, а также даем комментарии к каждой команде.
        Как вам материал?

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