Git для разработчика SS14

Материал из Starshine Wiki

Предисловие

В тексте будет часто упоминаться GitLab - аналог GitHub, которым также пользуется Workbench Team. Принципиальной разницы нет, все шаги возможны и на GitHub, но лично мне удобнее работать с GitLab. Если Вам не ясны какие-либо термины из текста ниже, обратитесь к разделу Словарь: Внутренние операции Git.

Установка Git

Для работы с Git для SS14 Вам понадобятся:

  • Git
    • Если Вы хотите использовать Git только в консоли, поставьте галочку при установке:
GitBash.png

Если Вы работаете в Linux, то, скорее всего, будете использовать Git через терминал или выбранную Вами IDE, и, возможно, он у Вас уже установлен.

Некоторые IDE имеют в себе интеграцию Git, но этом руководстве будет информация только об использовании приложений Git Bash и Fork.

Fork

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

Налаживание репозиториев Git

Репозиторий - это просто база кода. Репозитории содержат branch'и, а эти branch'и содержат различные commit'ы. Возможно, Вы слышали об этих двух понятиях - подробнее о них будет рассказано позже.

Удаленный репозиторий - это просто репозиторий на GitLab. Локальный репозиторий - это тот, который находится на Вашем компьютере.

Создание Вашего remote репозитория

Сперва давайте создадим собственный Fork удаленного репозитория Space Station 14. Для этого, конечно же, потребуется учетная запись GitLab. Forking означает, что Вы копируете всю историю и изменения репозитория в свой собственный удаленный репозиторий, чтобы иметь возможность свободно работать с кодом.

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

Перейдите в наш репозиторий Space Station 14(GitHub, GitLab) и нажмите здесь:

ForksButton.png

Затем Вас спросят как назвать Fork - просто назовите его как угодно! Но если Вы хотите просто помочь в разработке, я бы выбрал space-station-14.

Создание Вашего локального репозитория

Теперь нам нужно загрузить наш удаленный репозиторий на компьютер (клонировать), чтобы мы могли внести в него некоторые изменения. Технически, Вы можете изменять репозиторий удалённо (на GitLab есть неплохие инструменты), но наличие его на Вашем компьютере означает, что Вы используете IDE, такие как Visual Studio или Rider, для сборки игры и запуска тестов, а также легко работаете с Git.

Для каждого шага будут приведены скриншоты и инструкции для Git Bash и Fork для Windows.

GitBash:

Перейдите в то место на Вашем компьютере, где Вы хотите разместить локальный репозиторий, и:

GitBashHere.png

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

GitBashCloneCommand.png

Проделайте команду git remote add upstream с https://git.arumoon.ru/Workbench-Team/space-station-14, чтобы у Вас была возможность обновлять свои branch'и новыми обновлениями upstream'а.

Fork:

Нажмите Ctrl + N в программе, или File => Clone..., а затем введите адрес репозитория с припиской .git в конце.

ForkCloneRepositoryButton.png

Добавьте удалённый репозиторий, нажав следующую кнопку:

ForkAddRemoteButton.png

Введите https://git.arumoon.ru/Workbench-Team/space-station-14.git, чтобы у Вас была возможность обновлять свои branch'и новыми обновлениями upstream'а.

ForkCreateBranchMenuText.png

Подмодули

Обратите на это внимание! Если этого не сделать, то при попытке сборки игры вы получите множество странных ошибок о недоступности тех или иных модулей.

В Space Station 14 есть много подмодулей - в первую очередь, движок RobustToolbox. Подмодули - это просто репозитории внутри репозитория, и их нужно обновлять вручную. А нужно ли?

У нас есть автоматическая программа обновления подмодулей, так что Вам не нужно постоянно выполнять git submodule update --init --recursive (команда для ручного обновления подмодулей).

Запустите RUN_THIS.py внутри репозитория, который Вы скачали, с помощью Python. Желательно, из терминала (python RUN_THIS.py или python3 RUN_THIS.py). Это должно занять несколько секунд, так что если все мгновенно прекратится, то, вероятно, Вы не используете Python 3.7+ или что-то в этом роде.

Если Вы работаете в Windows и при попытке выполнить приведенную выше команду Вас перенаправляет в Microsoft Store или Вы получаете сообщение в терминале о том, что Python не установлен, необходимо отключить shortcut Microsoft, который может вызывать эту проблему. Это можно сделать, найдя в поиске Windows команду Manage App Execution Aliases, а затем отключив две точки привязки Python.

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

Если по каким-либо причинам, Вам понадобится вручную обновить RobustToolbox, Вы можете использовать cd RobustToolbox; git checkout v0.4.87 (замените v0.4.87 на последнюю версию RobustToolbox), затем Вы можете использовать cd..\, чтобы вернуться в репозиторий SS14. Это также пример использования cd для навигации по файлам, не выходя из командной строки.

Branching & Commits (Ветки и коммиты)

Что такое branch?

Branch'и очень и очень важны. По сути, они представляют собой лист изменений в коде (commit'ов). По умолчанию используется branch master.

При работе с кодом Вы всегда находитесь в branch'е, и Вы можете легко менять branch, в котором работаете.

Как правило, branch'и называются по имени того, над чем Вы собираетесь в них работать, но на самом деле не имеет значения, как они называются.

Branch'ей можно создавать сколько угодно. Когда Вы создаете branch, он ответвляется от текущего branch'а и становится самостоятельным объектом, в который можно добавлять commit'ы.

Каждый маленький узел - это отдельный commit, а каждый цвет - отдельный branch.

Зачем это нужно?

Технически, конечно, можно просто делать всю работу в одном branch'е и отправлять Merge Request'ы оттуда. Но создание различных branch'ей позволяет легко понять, где Вы находитесь, сколько изменений внесли, и дает возможность работать над несколькими особенностями(новым содержимым) одновременно.

Создание и работа с branch'ами

Создавать branch'и довольно просто. Давайте создадим новый branch под названием funny-feature:

Git Bash
GitBashNewBranchCommand.png

Параметр -b в git checkout здесь означает "проверь этот branch, и создай его, если он не существует".

Fork

Ctrl + Shift + B или кнопка сверху откроет меню создания branch'а:

Кнопка создания branch'а
Меню создания branch'а

Создайте branch с именем funny-feature.

Переключаться между branch'ами довольно просто: это называется проверкой branch'а. При этом локальные файлы и папки будут изменены в соответствии с веткой, поэтому Git будет кричать на Вас, если у Вас есть локальные изменения, а Вы пытаетесь выполнить проверку.

Git Bash
GitBashCheckoutBranchCommand.png
Fork

Два раза нажмите на имя branch'а слева.

ForkCheckoutBranchButton.png

Ну а затем внесите любые локальные изменения! Это не имеет значения. Создайте новый файл, удалите всё, измените одну строку в файле и т.д. Это не повлияет на Ваш главный branch, потому что теперь это территория funny-feature!

Совмещение branch'ей

Branche'и важны, поскольку их можно объединять. Так происходит интеграция функций в основную ветку. Merge означает "взять особые commit'ы из этого branch'а и применить их к другому branch'у". Вы можете объединить любые два branch'а.

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

GitLab Merge Request - это, по сути, "запрос на объединение": Вы говорите, что хотите объединить commit'ы своего branch'а с другим branch'ом, обычно главным. Подробнее об этом позже.

Merge Request'ы очень хорошо отображают всю эту информацию:

MergeRequestExampleImage.png
MergeRequestExampleCommitsImage.png

Что такое commit?

Commit'ы - это просто упакованные изменения в коде. Как разработчик, Вы выбираете, какие изменения войдут в commit и когда их вносить в branch. Commiting - это создание commit'а, который, по сути, является точкой сохранения, к которой можно вернуться в любое время.

Commit'ы имеют автора, временную метку, сообщение и некоторые изменения кода, прикрепленные к ним. Они также имеют очень длинный "commit hash" - уникальный идентификатор, используемый для ссылки на различные коммиты.

Благодаря commit'ам строится история - Вы можете просмотреть историю каждого коммита, сделанного в репозитории SS14 с самого начала, что очень здорово.

Отправка commit'ов в branch'и

Один важный момент: прежде чем отправлять изменения в commit, необходимо добавить их в область staging'а. Это означает, что Вы указываете, какие файлы хотите добавить в commit. Это полезно, поскольку Вы почти никогда не захотите commit'ить изменения подмодулей, так что Вы просто не добавляете их в область staging'а.

Commit'ы всегда сопровождаются сообщением, которое представляет собой краткое, содержательное описание того, что было сделано в данном commit'е. Или Вы можете быть "Чадом"(страна) и называть каждый коммит "меняет всякое" - на Ваше усмотрение.

Если Вы хотите посмотреть, что Вы изменили в данный момент, а что находится в области staging'а, то это довольно просто:

Git Bash
GitBashCheckStatusCommand.png
Fork

Откройте меню локальных изменений, нажав на кнопку сверху слева:

ForkCheckStatusCommand.png

Теперь, когда Вы убедились, что все эти изменения выглядят хорошо, мы добавим их в область staging'а и сделаем commit с ними:

Git Bash
GitBashStashAndCommitCommand.png
Fork

Добавляйте и убирайте изменения(выделите их) с помощью двух кнопок.

ForkStashAndCommitMenu.png

Напишите название и описание commit'а, а затем подтвердите отправку:

ForkCommitMenu.png

Теперь, когда изменения были добавлены в commit и отправлены в branch, они навсегда (вроде как) остаются в истории branch'а. Теперь мы можем сделать многое: объединить(merge) нашу funny-feature с нашим локальным мастер-branch'ем (если захотим, по какой-то причине), загрузить (push) наш branch funny-feature в наш удалённый репозиторий, или полностью удалить ветку. Мы выберем push и сделаем Merge Request.

Pushing и создание Merge Request'ов

Merge Request означает, что Вы хотите, чтобы кодовая база объединила Ваши изменения в одного из Ваших branch'ей в один из их branch'ей. Прежде чем мы сможем это сделать, наш удаленный репозиторий GitLab (upstream) должен знать о красивых branch'ах и commit'ах, которые мы создали локально, поэтому мы push'им эти изменения на удаленный репозиторий.

Проталкивание commit'ов

Имейте в виду, что при использовании этих команд Git, скорее всего, запросит Ваши учетные данные GitLab, чтобы убедиться в том, что Вы имеете право выполнять push на этот удаленный репозиторий.

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

Push'им наш branch в удалённый репозиторий (upstream):

Git Bash
GitBashPushCommand.png
Fork
ForkPushCommandButton.png

Создание Merge Request'ов

Весёлая часть. Отправляемся на GitLab и создаём наш Merge Request:

GitLabFunnyFeatureMergeRequestButton.png

Добавьте описание, красивое название, несколько скриншотов, и, надеюсь, оно будет merge'нуто.

Обновление репозитория

Возможно, прошло уже много времени, неделя или две, с момента Вашего последнего Merge Request'а, и Вы хотите сделать еще один. Прежде чем что-либо делать, необходимо загрузить (pull) изменения кода из основного репозитория SS14 в свой локальный репозиторий. В противном случае Вы получите устаревший код, а Ваши локальные изменения могут не соответствовать тому, как игра будет работать на самом деле - Вы даже можете получить конфликты слияния при попытке MR.

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

Первый способ, fetch+merge, дает больше возможностей для контроля, но может быть запутанным. Второй метод, pull, прост и удобен, но не дает большого контроля. Однако, как правило, pull - это все, что вам нужно.

Метод pull

Pulling означает получение (fetching) новых веток и commit'ов из удаленного репозитория, а затем их слияние с branch'ем. Pulling часто проще, поскольку Git имеет хорошую систему автоматического определения того, из какого удаленного репозитория Вы хотите получить изменения (но она не всегда работает корректно).

Мы будем pull'ить с нашего удалённого репозитория upstream и попросим его объединиться с нашим локальным branch'ем.

Сначала, Вам надо сделать checkout Вашего branch'а. Об этом мы рассказывали ранее. Затем:

Git Bash
GitBashPullUpstreamCommand.png

Делайте это регулярно и всегда до начала работы над новым branch'ем.

Fork
ForkPullUpstreamCommandButton.png

Приложения

Что следует помнить

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

  • При создании новой функциональности всегда создавайте новый branch от главного, прежде чем commit'ить что-либо. Если Вы случайно за-commit'ите изменения физики в branch с велосипедным клаксоном, Вам не поздоровится, но это поправимо.
  • Никогда, никогда не фиксируйте RobustToolbox или подмодули типа Lidgren.Network, если Вы не знаете, что делаете. В локальном репозитории верхнего уровня эти подмодули считаются "файлами", поэтому их легко случайно отправить на staging и сделать commit с ними. Не делайте этого. О том, как исправить свои ошибки, если это произошло, см. ниже.


Словарь: Внутренние операции Git

В качестве справочного материала здесь приведен небольшой глоссарий понятий и терминов Git, объясняющий их более подробно и в одном месте.

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

Репозитории - это папки, в которых с помощью Git можно вносить изменения и отслеживать их. Локальные репозитории - это репозитории, которые находятся у Вас на компьютере, а удаленные репозитории - это репозитории, расположенные на таких сайтах, как GitLab Репозитории состоят из множества веток.

Remotes - это названия и ссылки на удаленные репозитории, которые может использовать Ваш локальный репозиторий.

Подмодули - это репозитории, которые находятся внутри другого репозитория.

Forks - это репозитории, основанные на другом репозитории. Если Вы собираетесь сделать Merge Request для SS14, Вам необходимо сначала сделать Fork.

The working tree - это все файлы, папки и т.п., находящиеся в репозитории.

Staging означает добавление (с помощью git add) изменений в 'staging area', где с ними могут быть выполнены некоторые действия.

Commits - это изменения рабочего дерева репозитория в определенный момент времени. По сути, это точка сохранения. Commit - это просто список файлов, которые были изменены с момента последнего коммита, а изменения, которые были commit'нуты, - это изменения, которые Вы отправили в staging area.

Checking out - это переключение на другой branch, чтобы работать с ним или просматривать его изменения локально.

Merging - это интеграция изменений из одного branch'а в другой.

Конфликты merge'а возникают, когда интеграция изменений из одного branch'а в другой не может быть выполнена автоматически, поскольку они оба изменяют одну и ту же область в файле, или их изменения взаимоисключают друг друга каким-либо другим способом.

Fetching означает получение branch'ей и commit'ов удаленного репозитория, но на самом деле... еще ничего с ними не делая. Они будут просто обновлены, если вы захотите проверить или объединить их позже.

Pulling - это акт интеграции изменений из branch'а удаленного репозитория в Ваш локальный branch.

Merge Requests - это действие, позволяющее запросить слияние Вашего локального branch'а и всех его изменений с branch'а другого репозитория.

Pushing - это действие по интеграции локальных изменений в удаленный репозиторий.

Примечание: Полезные советы и рекомендации

Некоторые вещи я не рассмотрел, но они почти неизбежно понадобятся Вам в какой-то момент. Я расскажу обо всем этом исключительно как о командах git в Git Bash, но в других программах разобраться несложно (те же ключевые слова, просто ищите их).

Одно замечание, поскольку оно часто встречается здесь: HEAD - это модное название commit'а, на котором Вы сейчас находитесь.

Разрешение конфликтов при merge

Вредный маленький maintainer сказал вам "разрешить конфликты", иначе ваш MR "не будет merge'нут". Вот ведь сволочь! К счастью, это не так уж сложно.

Сначала нужно обновить главный локальный branch. Как это сделать, см. выше.

Когда Вы выполните команду git merge master [локальный branch], она либо сделает это без ошибок ("ура"), либо сообщит Вам, что необходимо разрешить конфликты (ужас).

Для разрешения конфликтов вручную достаточно зайти в конфликтующие файлы, удалить всю ерунду типа >>>>HEAD и ===== <<<<master (просто указывает, откуда произошли изменения), а затем отредактировать файл так, чтобы он правильно объединял оба набора изменений. Иногда это легко, иногда трудно. Если это сложно, то Вы, вероятно, знаете, что делаете. После этого просто выполните команду git commit.

У Atlassian есть очень хорошее руководство по этому вопросу.

Проверка истории

git log --oneline - это Ваш друг. Он показывает короткие hashe'и commit'ов (уникальные идентификаторы), их сообщения, а также их branch'и и tag'и.

В Fork эта функция встроена в UI:

ForkCommitHistory.png

Очистка локальных изменений

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

git reset --hard HEAD Это означает "изменить working tree на текущий commit, до внесения любых локальных изменений. Вы не сможете восстановить локальные изменения, если сделаете это, так что будьте осторожны.

Откат сделанного Вами commit'а

Вот черт, Ваша эротика про ксеноморфа попала в commit или Вы случайно commit'нули подмодуль! Что теперь? Есть решения:

git revert HEAD Это создаст новый commit, отменяющий текущий commit, и затем commit'нет его. Хе-хе, commit.