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

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

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

Поэтому, чтобы облегчить сотрудничество между людьми, независимо от того, где они находятся, у нас есть удаленные репозитории. Как следует из названия, это репозитории, которые не существуют в файловой системе пользователя и обычно хранятся в облаке. Если вы цените облачные возможности Документов Google для беспрепятственного сотрудничества по сравнению с работой с автономными файлами Word, удаленные репозитории - это примерно то же самое.

Вы, должно быть, слышали о GitHub. Если вы спросите кого-нибудь, что это такое, они могут сказать, что это место для размещения ваших проектов, для целей совместной работы или просто в качестве облачного хранилища - и это правильное определение для всех практических целей. Но на самом деле GitHub - это просто Google Диск для репозиториев Git. Он позволяет пользователям создавать и управлять репозиториями Git в облаке (с некоторыми дополнительными функциями для упрощения совместной работы). GitHub - это просто центр репозиториев Git.

Поскольку удаленные репозитории (как правило) размещаются таким образом, что они доступны через Интернет (или какую-либо частную сеть), каждый удаленный репозиторий Git имеет URL-адрес, заканчивающийся на .git. Репозиторий, размещенный на GitHub, будет иметь URL-адрес вида https://github.com/johndoe/some-repo.git.

Приступаем к настройке

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

  1. Создайте учетную запись на GitHub. Бесплатный совет: используйте короткое имя пользователя и все строчные буквы. Это не обязательно должно быть ваше имя.
  2. Создайте репозиторий под названием poems. Убедитесь, что репозиторий открыт для всех, и не выбирайте ни один из параметров в разделе «Инициализировать этот репозиторий с помощью».

В дальнейшем я предполагаю, что ваше имя пользователя - «john». Замените его своим именем пользователя в выполняемых командах.

План

Итак, мы фактически создали удаленный репозиторий под названием poems на GitHub, который будет действовать как облачная резервная копия нашей книги. Вот план, которому мы собираемся следовать в этой части:

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

Добавление пультов

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

# Add a remote repository
# Syntax: git remote add <remote-name> <repo-url>
git remote add origin <https://github.com/john/poems.git>

Здесь мы добавили пульт с именем origin в наш локальный репозиторий, который ссылается на удаленный репозиторий, который мы только что создали на GitHub. Используемый нами URL-адрес можно получить в верхнем разделе домашней страницы вашего репозитория (убедитесь, что вы выбрали HTTPS вместо SSH).

Вы также можете удалить пульты с помощью аналогичной команды:

git remote remove <remote-name>

Хотя вы можете назвать ветку как угодно, origin почти повсеместно используется для удаленного репозитория, который действует как облачная версия локального репозитория. Точно так же upstream - это часто используемый термин для обозначения основного репозитория при участии в проекте с открытым исходным кодом.

Продвижение изменений

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

# Push "master" branch to remote "origin"
# Syntax: git push <remote-name> <branch-name>
git push origin master

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

Если с вашей сетью все в порядке, команда должна работать без проблем. Чтобы убедиться, что это сработало, просто зайдите в свой репозиторий, и он должен показать все poem*.txt файлы, которые вы написали. Вы также можете просмотреть свою историю коммитов и прочитать там содержимое файла.

Короткий обход: теги

Теги, как следует из их названия, являются тегами, прикрепленными к определенным коммитам с целью отслеживания ветвей или закладок коммитов. Когда вы выполняете git log, вы могли заметить такие вещи, как master или add-headings в скобках после некоторых коммитов. На самом деле это теги, которые отслеживают, где находится каждая ветвь (помните, ветки - это просто псевдонимы для коммитов - вы видите сходство между тегами и ветвями?)

Совершение коммитов прямо в удаленных репозиториях

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

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

Итак, перейдите на домашнюю страницу вашего репозитория, нажмите «Добавить README» и напишите краткое описание вашего репозитория. Вам также нужно будет написать здесь сообщение о фиксации (и необязательное описание) и проверить возможность фиксации непосредственно в master ветку. Как только вы закончите, ваш удаленный репозиторий должен быть зафиксирован перед вашим локальным репозиторием. Это все, что нам нужно в этом разделе.

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

Получение изменений

Наконец, основная задача. Теперь, когда наш удаленный репозиторий опережает наш локальный репозиторий, мы можем попытаться получить эти изменения в наш локальный репозиторий. Давай сделаем это:

# Fetch changes to local repository
git fetch origin master

Это извлекает изменения из ветки master удаленного репозитория по адресу origin в ваш локальный репозиторий. Обратите внимание, что это только первая часть получения изменений: выборка только сообщает Git о текущем состоянии удаленной ветки и не влияет на фактическое дерево фиксации вашего локального репозитория. На эти выбранные ветки можно ссылаться с помощью синтаксиса remote/branch. Давайте перейдем к фактическому объединению этих изменений в нашу локальную master ветку:

# Merge fetched changes into local branch
git checkout master
git merge origin/master

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

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

# Pull changes from remote repository
git pull origin master

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

Снова конфликты слияния

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

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

Но если ваша локальная работа состоит всего из нескольких не слишком больших коммитов, есть более изящный способ обновить локальную ветку - rebase pulls.

Ребазинг веток

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

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

Давайте разберемся, как работает ребазинг. Предположим, что репозиторий со следующим деревом фиксации имеет две ветви.

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

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

Идея перебазирования состоит в том, чтобы отредактировать ветку функции так, чтобы она выглядела следующим образом:

Намного чище, правда? Поскольку функциональная ветка теперь основана на текущей целевой ветке, слияние - это просто перемотка вперед, и никаких конфликтов слияния не возникает. Вот команда для переназначения ветки функции на целевую ветку:

# Switch to "feature" branch
git checkout feature
# Rebase current branch onto "target" branch
git rebase target
# OR without checkout, simply...
git rebase feature target

Ссылаясь на пример на диаграммах выше, вот три этапа перебазирования:

  1. Некоторое время вырезаем коммиты D и E из ветки функций и держим их в стороне.
  2. Скопируйте коммиты B и C из целевой ветви в функциональную ветку.
  3. Поместите коммиты D и E обратно в функциональную ветку, чтобы они теперь происходили после B и C.

Технически финальные коммиты D и E не являются точными копиями первоначальных коммитов, а имеют только те же изменения файла и метаданные коммитов (сообщение, автор и т. Д.). Это связано с тем, что вычисление хэша фиксации (длинной уникальной шестнадцатеричной строки) также включает предыдущие фиксации. Поскольку предыдущие коммиты D и E меняются после перебазирования, их хэши будут другими, и поэтому финальные коммиты D и E часто представлены как D ’и E’.

Конфликты слияния при перебазировании

Стратегия слияния ветвей rebase также включает конфликты слияния, но здесь все несколько иначе. Конфликты слияния возникают на третьем этапе перебазирования, когда коммиты D и E один за другим заменяются на ветку функции. Поскольку исходное состояние файлов отличается, замена коммитов может иметь или не иметь полного смысла - когда это не так, вы получаете конфликт слияния.

Мы не будем здесь для краткости пробовать, но вам обязательно стоит попробовать это самостоятельно. Он не слишком отличается от обычных конфликтов слияния, но учтите следующие моменты:

  • После внесения изменений для разрешения конфликтных блоков не фиксируйте, как раньше: вместо этого запустите git rebase --continue, чтобы Git продолжил фиксацию с оставшимися фиксациями.
  • Возможно, вам придется разрешить конфликты для каждой фиксации, сделанной в вашей функциональной ветке. Это связано с тем, что коммиты функциональных веток (D и E, выше) заменяются один за другим, и каждая замена может привести к конфликтам. Фактически, это основная причина, по которой стратегия перебазирования-слияния не предпочтительна для крупных слияний.

⚠️ Изменение базы данных часто является необратимым процессом, и его следует выполнять с осторожностью. Если вы что-то испортили в любой момент перебазирования, выполните git rebase --abort, чтобы отменить перебазирование и начать заново. Кроме того, никогда не никогда выполняйте перебазирование общедоступной ветки - перебазирование перезаписывает историю, что очень и очень усложняет работу других людей, работающих над веткой.

Rebase тянет

Возвращаясь к основной теме, давайте посмотрим, как извлекать данные из удаленных веток с помощью стратегии rebase. Вытяжки Rebase - это не что иное, как обычные извлечения, но стратегия слияния, используемая для второго этапа извлечения, - это rebase-merge вместо трехстороннего слияния по умолчанию. Как упоминалось выше, это полезно для обновления вашей локальной ветки с учетом работы, выполненной в удаленной ветке, с возможностью настройки ваших локальных коммитов. Вот как выполнить извлечение данных из ветки master удаленного origin пульта ДУ:

# Pull with rebase
git pull --rebase origin master

Это сделает следующее:

  1. Принеси ветку origin/master
  2. Перебазировать текущую ветку на origin/master

Обратите внимание, что здесь не делается никаких коммитов слияния - ваша ветка обновляется, чтобы включить работу, проделанную над origin/master, вот и все.

Общий рабочий процесс GitHub

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

Давайте представим проект, которым руководит человек X. Этот руководитель имеет полный доступ к репозиторию GitHub для проекта, в частности, включая возможность объединять работы других людей в репозиторий (мы вскоре увидим, как это сделать). Есть и другие участники проекта, у которых нет административного доступа к репозиторию GitHub.

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

Создайте вилку проекта

Во-первых, вы создадите форк репозитория. Это просто означает копирование репозитория GitHub в вашу учетную запись, что очень похоже на «создание копии» в Документах Google. Этот разветвленный репозиторий действует как облачная резервная копия вашей работы над проектом, но, что более важно, он действует как источник ваших запросов на вытягивание - мы увидим это позже.

Репозиторий GitHub можно разветвить, перейдя на страницу репозитория на GitHub и нажав кнопку «Форк» в правом верхнем углу. Это создаст репозиторий в вашей учетной записи, который будет копией основного репозитория.

Клонировать, добавлять пульты и экспериментировать

Клонирование - очень распространенное действие: клонирование репозитория GitHub означает создание локальной копии репозитория GitHub. Это Git-эквивалент загрузки кода проекта.

Чтобы клонировать ваш разветвленный репозиторий:

  1. Щелкните зеленый раскрывающийся список «Код» и выберите HTTPS.
  2. Скопируйте показанную ссылку.
  3. На терминале выполните:
# Clone repository via HTTPS URL 
git clone <copied-url>

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

Затем вы должны добавить несколько пультов для репозиториев GitHub - как основного проекта, так и вашей вилки. Обычно вы называете вилку origin, а главный репозиторий проекта - upstream. Итак, добавьте пульты следующим образом:

# Add remotes for the GitHub repositories
git remote add origin <https://github.com/john/project.git>
git remote add upstream <https://github.com/X/project.git>

Теперь поэкспериментируйте с кодом проекта или выполните любую работу, которую вы хотите проделать с кодом. Если вы заинтересованы в устранении проблемы с проектом, на вкладке «Проблемы» на странице главного репозитория обычно перечислены проблемы, которые в настоящее время существуют в проекте.

Допустим, вы внесли некоторые изменения, которые устраняют существующую проблему в проекте. В идеале любую работу следует выполнять в отдельной ветке, поэтому предположим, что вы выполнили свою работу в ветке fix-issue. Теперь ваш следующий шаг - отправить ваши изменения в основной репозиторий проекта.

Тянуть и толкать

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

# WHILE on branch "fix-issue",
# Normal pull, if your work is large (tens of commits)
git pull origin master
# Rebase pull, if your work is not much (few commits)
git pull --rebase origin master

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

По завершении внесите изменения в ветку fix-issue в вилку:

# Push your changes to origin
git push origin fix-issue

Отличная работа, теперь вы разместили свои изменения в своей вилке на GitHub. Все, что осталось, - это отправить «пул-реквест».

Запросы на вытягивание

У запросов на вытягивание ужасные названия, и действительно, это название часто сбивает с толку новичков в понимании их работы. Лучшее название - «запрос на слияние» - это, по сути, запросы к владельцу или руководителю проекта с просьбой объединить некоторую работу с проектом. Запрос на вытягивание состоит из сделанных вами коммитов и изменений файла, а также описания проделанной работы. GitHub также позволяет людям комментировать и просматривать запрос на перенос, решая, можно ли объединить выполненную работу.

Чтобы сделать запрос на вытягивание:

  1. Перейдите на страницу основного репозитория и откройте вкладку «Запросы на вытягивание».
  2. Нажмите зеленую кнопку «Новый запрос на вытягивание», а затем нажмите «сравнить по вилкам» (в тексте справа под заголовком «Сравнить изменения»).
  3. В правой части выберите свою вилку и ветку fix-issue. Нажмите зеленую кнопку «Создать запрос на перенос».
  4. Введите заголовок и описание запроса на извлечение и создайте запрос на извлечение. Хорошая практика - дать подробное описание проделанной работы.

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

Следующая иллюстрация хорошо резюмирует вышесказанное:

Резюме

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

  • Удаленные репозитории - это просто репозитории Git, размещенные в облаке. Самый популярный облачный провайдер для репозиториев Git - GitHub.
  • Вы можете push и pull работать в удаленных репозиториях и из них, чтобы синхронизировать работу между локальными и удаленными репозиториями.
  • Rebasing - это мощный инструмент, который позволяет обновлять вашу ветку работой, проделанной в основной ветке, так что результирующее дерево фиксации является линейным и простым в управлении.
  • GitHub имеет функции, которые облегчают совместную работу над проектами между множеством людей.

Это последняя часть руководства. Мы рассмотрели множество тем, и я надеюсь, что это руководство было полезно для людей, плохо знакомых с Git и программированием в целом. Git - это гораздо больше, чем описано в этом руководстве - Изучение ветвления Git - это отличный способ изучить это и получить практический опыт. (Спасибо, Абхишек Шри за предложение!)

Не стесняйтесь предлагать любые исправления и улучшения!