Робочий процес запиту на отримання
Так званий «робочий процес PR», який використовує Godot, є загальним для багатьох проектів, що використовують Git, і повинен бути знайомий ветеранам вільного програмного забезпечення. Ідея полягає в тому, що лише невелика кількість (якщо така є) приєднується безпосередньо до гілки master. Замість цього учасники розгалужують проект (тобто створюють його копію, яку вони можуть змінювати за своїм бажанням), а потім використовують інтерфейс GitHub, щоб запитати витягування з однієї з гілок свого форка до однієї гілки оригіналу ( часто називають сховищем вгорі).
Отриманий запит на витягування (PR) потім може бути переглянуто іншими учасниками, які можуть його схвалити, відхилити або найчастіше вимагати внесення змін. Після схвалення PR може бути об’єднаний одним із основних розробників, а його коміти стануть частиною цільової гілки (зазвичай гілки master).
Ми разом розглянемо приклад, щоб показати типовий робочий процес і відповідні команди Git. Але спочатку давайте швидко розглянемо організацію репозиторію Godot's Git.
Git вихідний репозиторій
Репозиторій на GitHub — це Git сховище коду разом із вбудованим відстеженням проблем і системою PR.
Примітка
Якщо хочете взяти участь у написанні документації, сховище її коду розташовано тут.
Система контролю версій Git — це інструмент, який використовується для відстеження послідовних редагувань вихідного коду. Для ефективного внеску в Godot настійно рекомендується вивчити основи командного рядка Git. Існують деякі графічні інтерфейси для Git, але вони зазвичай спонукають користувачів до шкідливих звичок щодо робочого процесу Git і PR, тому ми рекомендуємо не використовувати їх. Зокрема, ми радимо не використовувати онлайн-редактор GitHub для додавання коду (хоча він допускається для невеликих виправлень або змін у документації), оскільки він вимагає одного коміту для кожного файлу та кожної модифікації, що швидко призводить до PR із нечитабельною історією Git (особливо після однорангового огляд).
Дивись також
Перші розділи «Книги» Git є хорошим вступом до філософії інструменту та різноманітних команд, які вам потрібно освоїти у щоденному робочому процесі. Ви можете прочитати їх онлайн на веб-сайті Git SCM. Ви також можете спробувати інтерактивний посібник GitHub.
Гілки в репозиторії Git організовані таким чином:
Гілка
master- це місце, де відбувається розробка наступної основної версії. Як гілка розробки, вона може бути нестабільною і не призначена для використання у виробництві. Саме тут PR має бути в першу чергу.Стабільні гілки називаються за їх версією, напр.
3.1і2.1. Вони використовуються для резервного портування виправлень помилок і покращень із гілкиmasterдо поточної стабільної версії (наприклад, 3.1.2 або 2.1.6). Як правило, остання стабільна гілка зберігається до наступної проміжної версії (наприклад, гілка3.0підтримувалася до випуску Godot 3.1). Якщо ви хочете зробити PR проти стабільної гілки, будь ласка, спочатку перевірте, чи ваші зміни також стосуються гілкиmaster, і якщо так, зробіть PR для гілкиmasterпріоритетною. Менеджери випусків можуть потім вибрати виправлення для стабільної гілки, якщо це необхідно.Час від часу можуть існувати гілки функцій, які, як правило, мають бути об’єднані в гілку
master.
Створення відгалуження і клонування
Першим кроком є форк репозиторію godotengine/godot на GitHub. Для цього вам потрібно буде мати обліковий запис GitHub і ввійти в систему. У верхньому правому куті сторінки GitHub сховища ви повинні побачити кнопку «Форк», як показано нижче:
Клацніть його, і через деякий час вас буде перенаправлено до власного форка репозиторію Godot із вашим іменем користувача GitHub як простором імен:
Потім ви можете клонувати свій форк, тобто створити локальну копію онлайн-репозиторію (у Git — віддалений вихідний файл). Якщо ви ще цього не зробили, завантажте Git з його веб-сайту, якщо ви використовуєте Windows або macOS, або встановіть його через менеджер пакетів, якщо ви використовуєте Linux.
Примітка
Якщо ви використовуєте Windows, відкрийте Git Bash, щоб вводити команди. Користувачі macOS і Linux можуть використовувати відповідні термінали.
Щоб клонувати свій форк із GitHub, скористайтеся такою командою:
git clone https://github.com/USERNAME/godot
Через деякий час у вашому поточному робочому каталозі має бути каталог godot. Перейдіть до нього за допомогою команди cd:
cd godot
Ми почнемо з налаштування посилання на оригінальний репозиторій, який ми роздвоїли:
git remote add upstream https://github.com/godotengine/godot
git fetch upstream
Це створить посилання під назвою upstream, яке вказує на оригінальне сховище godotengine/godot. Це буде корисно, коли ви хочете отримати нові коміти з гілки master, щоб оновити свій форк. У вас є інше віддалене посилання під назвою origin, яке вказує на ваше розгалуження (USERNAME/godot).
Вам потрібно виконати описані вище кроки лише один раз, доки ви зберігаєте локальну папку godot (яку ви можете переміщувати, якщо хочете, відповідні метадані приховані в її підпапці .git).
Примітка
Branch it, pull it, code it, stage it, commit, push it, rebase it... technologic.
Цей поганий погляд на Technologic від Daft Punk демонструє загальне уявлення початківців Git про його робочий процес: багато дивних команд, які можна вивчати шляхом копіювання та вставлення, сподіваючись, що вони працюватимуть, як очікувалося. І це насправді непоганий спосіб навчитися, якщо вам цікаво і не соромтеся запитувати свою пошукову систему, коли ви її загубили, тому ми дамо вам основні команди, які потрібно знати під час роботи в Git.
Далі, як приклад, ми припустимо, що ви хочете реалізувати функцію в Godot's Project Manager, яка закодована у файлі editor/project_manager.cpp.
Створення гілки
За замовчуванням git clone мав розмістити вас у master гілці вашого форка (origin). Щоб розпочати власну розробку функцій, ми створимо гілку функцій:
# Create the branch based on the current branch (master)
git branch better-project-manager
# Change the current branch to the new one
git checkout better-project-manager
Ця команда є еквівалентною до такої:
# Change the current branch to a new named one, based on the current branch
git checkout -b better-project-manager
Якщо ви хочете повернутися до гілки master, скористайтеся:
git checkout master
Ви можете побачити, на якій гілці ви зараз перебуваєте, за допомогою команди git branch:
git branch
2.1
* better-project-manager
master
Обов’язково завжди повертайтеся до гілки master перед створенням нової гілки, оскільки ваша поточна гілка буде використана як основа для нової. Крім того, ви можете вказати спеціальну базову гілку після назви нової гілки:
git checkout -b my-new-feature master
Оновлення вашої гілки
Це не знадобиться з першого разу (відразу після того, як ви розгалужите вихідний репозиторій). Однак наступного разу, коли ви захочете над чимось попрацювати, ви помітите, що master вашого форка містить кілька комітів позаду верхньої гілки master: запити на отримання від інших учасників були б тим часом об’єднані.
Щоб переконатися, що не буде конфліктів між функцією, яку ви розробляєте, і поточною гілкою master, вам доведеться оновити свою гілку, витягнувши гілку вище за течією.
git pull --rebase upstream master
Аргумент --rebase гарантує, що будь-які локальні зміни, які ви зафіксували, будуть повторно застосовані поверх витягнутої гілки, що зазвичай і є тим, чого ми хочемо в нашому робочому процесі PR. Таким чином, коли ви відкриваєте запит на вилучення, ваші власні коміти будуть єдиною відмінністю від гілки master вище за течією.
Під час перебазування можуть виникнути конфлікти, якщо ви фіксуєте модифікований код, який тим часом було змінено у верхній гілці. Якщо це станеться, Git зупиниться на конфліктному коміті та попросить вас вирішити конфлікти. Ви можете зробити це за допомогою будь-якого текстового редактора, потім внести зміни (детальніше про це пізніше) і продовжити за допомогою git rebase --continue. Повторіть операцію, якщо пізніші коміти також мають конфлікти, доки операція rebase не завершиться.
Якщо ви не впевнені, що відбувається під час перебазування, і панікуєте (не хвилюйтеся, ми всі це робимо перші кілька разів), ви можете перервати перебазування за допомогою git rebase --abort. Після цього ви повернетеся до початкового стану вашої гілки перед викликом git pull --rebase.
Примітка
Якщо ви опустите аргумент --rebase, замість цього ви створите комміт злиття, який повідомляє Git, що робити з двома різними гілками. Якщо виникнуть будь-які конфлікти, вони будуть вирішені всі одразу за допомогою цього коміту злиття.
Хоча це дійсний робочий процес і типова поведінка git pull, коміти злиття в PR не сприймаються в нашому робочому процесі PR. Ми використовуємо їх лише під час об’єднання PR у галузь upstream.
Філософія полягає в тому, що PR має представляти останній етап змін, внесених до кодової бази, і ми не зацікавлені в помилках і виправленнях, які були б зроблені на проміжних етапах перед злиттям. Git надає нам чудові інструменти, щоб «переписати історію» і зробити так, ніби ми зробили все правильно з першого разу, і ми раді використовувати його, щоб гарантувати, що зміни легко переглядати та розуміти ще довго після їх об’єднання.
Якщо ви вже створили комміт злиття без використання rebase, або внесли будь-які інші зміни, які призвели до небажаної історії, найкращим варіантом є використання інтерактивного перебазування у гілці вище. Інструкції див. у dedicated section.
Порада
Якщо в будь-який момент ви захочете скинути локальну гілку до певного коміту або гілки, ви можете зробити це за допомогою git reset --hard <ідентифікатор коміту> або git reset --hard <remote>/ <гілка> (наприклад, git reset --hard upstream/master).
Майте на увазі, що це призведе до видалення будь-яких змін, які ви могли внести в цю гілку. Якщо ви помилково втратите коміти, скористайтеся командою git reflog, щоб знайти ідентифікатор фіксації попереднього стану, який ви хотіли б відновити, і використовуйте його як аргумент git reset --hard для переходу повернутися до того стану.
Внесення змін
Потім ви повинні внести зміни у файл editor/project_manager.cpp нашого прикладу за допомогою свого звичайного середовища розробки (текстовий редактор, IDE тощо).
За замовчуванням ці зміни є непоетапними. Проміжна область — це шар між вашим робочим каталогом (де ви вносите свої зміни) і локальним сховищем Git (коміти та всі метадані в папці .git). Щоб перенести зміни з робочого каталогу до репозиторію Git, вам потрібно помістити їх за допомогою команди git add, а потім зафіксувати їх за допомогою команди git commit.
Існують різні команди, які вам слід знати, щоб переглянути свою поточну роботу перед її інсценуванням, під час її інсценування та після її виконання.
git diffпокаже вам поточні непрограшовані зміни, тобто відмінності між вашим робочим каталогом і проміжною областю.git checkout -- <files>скасує непоетапні зміни в наведених файлах.git add <files>внесе зміни у перелічені файли.git diff --stagedпокаже поточні поетапні зміни, тобто відмінності між проміжною областю та останнім комітом.git reset HEAD <files>скасує зміни в перелічених файлах.git statusпокаже вам, які поточні та непроведені модифікації.git commitзафіксує поетапні файли. Він відкриє текстовий редактор (ви можете визначити той, який ви бажаєте використовувати, за допомогою змінної середовищаGIT_EDITORабо налаштуванняcore.editorу вашій конфігурації Git), щоб ви могли писати журнал фіксації. Ви можете використовувати git commit -m "Cool commit log" для безпосереднього запису журналу.git commit --amendдозволяє вносити зміни до останнього коміту поточними змінами (доданими за допомогоюgit add). Це найкращий варіант, якщо ви хочете виправити помилку в останньому коміті (помилка, опечатка, проблема стилю тощо).git logпокаже вам останні коміти вашої поточної гілки. Якщо ви зробили локальні коміти, вони повинні бути показані вгорі.git showпокаже вам зміни останнього коміту. Ви також можете вказати хеш коміту, щоб побачити зміни для цього коміту.
Це дуже багато для запам'ятовування! Не хвилюйтеся, просто перевірте цю шпаргалку, коли вам потрібно внести зміни, і вчіться на практиці.
Ось як може виглядати історія оболонки на нашому прикладі:
# It's nice to know where you're starting from
git log
# Do changes to the Project Manager with the nano text editor
nano editor/project_manager.cpp
# Find an unrelated bug in Control and fix it
nano scene/gui/control.cpp
# Review changes
git status
git diff
# We'll do two commits for our unrelated changes,
# starting by the Control changes necessary for the PM enhancements
git add scene/gui/control.cpp
git commit -m "Fix handling of margins in Control"
# Check we did good
git log
git show
git status
# Make our second commit
git add editor/project_manager.cpp
git commit -m "Add a pretty banner to the Project Manager"
git log
Таким чином, ми повинні мати два нових коміти в нашій гілці better-project-manager, яких не було в гілці master. Хоча вони все ще є лише локальними, віддалений форк не знає про них, а також репозиторій угорі.
Надсилання змін до віддаленого сховища
Ось тут у гру вступить git push. У Git фіксація завжди виконується в локальному сховищі (на відміну від Subversion, де фіксація безпосередньо змінює віддалений репозиторій). Вам потрібно надіслати нові коміти у віддалену гілку, щоб поділитися ними зі світом. Синтаксис для цього:
git push <remote> <local branch>[:<remote branch>]
Частину про віддалену гілку можна опустити, якщо ви хочете, щоб вона мала таку саму назву, як і локальна гілка, як у нашому випадку в цьому прикладі, тому ми зробимо:
git push origin better-project-manager
Git запитає у вас ім’я користувача та пароль. У якості пароля введіть особистий маркер доступу GitHub (PAT). Якщо у вас немає особистого маркера доступу GitHub або його немає з належними дозволами для вашого щойно розгалуженого сховища, вам потрібно буде його створити. Перейдіть за цим посиланням, щоб створити свій особистий маркер доступу: Створення особистого маркера доступу.
Після того, як ви успішно підтвердите свій обліковий запис за допомогою PAT, зміни буде надіслано до вашого віддаленого сховища. Якщо ви перевірите сторінку форка на GitHub, ви побачите нову гілку з доданими комітами.
Надсилання запиту щодо злиття
Коли ви завантажуєте гілку форка на GitHub, ви маєте побачити рядок "Ця гілка на 2 коміти випереджає godotengine:master." (і, можливо, деякі коміти відстають, якщо ваша гілка master не синхронізована з верхня гілка master).
У цьому рядку є посилання «Pull request». Натиснувши його, ви відкриєте форму, яка дозволить вам надіслати запит на витяг у вихідному сховищі godotengine/godot. Він повинен показати вам два ваші коміти та вказати «Можливий для злиття». Якщо ні (наприклад, він має набагато більше комітів або говорить про конфлікти злиття), поки не створюйте PR, щось пішло не так. Перейдіть до нашого чату співавторів Godot і попросіть підтримки :)
Використовуйте чіткий заголовок для PR і розмістіть необхідні деталі в області коментарів. Ви можете перетягувати знімки екрана, GIF-файли або заархівовані проекти, якщо це необхідно, щоб продемонструвати те, що реалізовано у вашій роботі. Натисніть «Створити запит на отримання», і тоді!
Змінення запиту на отримання
Хоча його перевіряють інші учасники, вам часто доведеться вносити зміни до свого ще не об’єднаного PR, або тому, що учасники вимагали їх, або тому, що ви самі виявили проблеми під час тестування.
Хороша новина полягає в тому, що ви можете змінити запит на отримання, просто діючи на гілці, з якої ви зробили запит на отримання. Ви можете напр. зробіть нову фіксацію на цій гілці, перемістіть її у свій форк, і PR буде оновлено автоматично:
# Check out your branch again if you had changed in the meantime
git checkout better-project-manager
# Fix a mistake
nano editor/project_manager.cpp
git add editor/project_manager.cpp
git commit -m "Fix a typo in the banner's title"
git push origin better-project-manager
Однак майте на увазі, що в нашому робочому процесі PR ми віддаємо перевагу комітам, які переводять базу коду з одного функціонального стану в інший, без проміжних комітів, які виправляють помилки у вашому власному коді чи проблеми стилю. У більшості випадків ми надаємо перевагу одному коміту в даному PR (якщо немає вагомих причин зберігати зміни окремо). Замість створення нового коміту, розгляньте можливість використання git commit --amend, щоб змінити попередній коміт своїми виправленнями. Тоді наведений вище приклад стане таким:
# Check out your branch again if you had changed in the meantime
git checkout better-project-manager
# Fix a mistake
nano editor/project_manager.cpp
git add editor/project_manager.cpp
# --amend will change the previous commit, so you will have the opportunity
# to edit its commit message if relevant.
git commit --amend
# As we modified the last commit, it no longer matches the one from your
# remote branch, so we need to force push to overwrite that branch.
git push --force origin better-project-manager
Інтерактивне перебазування
Якщо ви не виконали наведених вище кроків, щоб змінити зміни у коміті замість створення комітів виправлення, або якщо ви створили свої зміни, не знаючи про наш робочий процес і поради щодо використання Git, рецензенти можуть попросити вас перебазувати свій розгалуження, щоб зтиснути деякі або всі коміти в одне.
Дійсно, якщо деякі коміти були зроблені після переглядів для виправлення помилок, друкарських помилок тощо в оригінальному коміті, вони не мають відношення до майбутнього читача журналу змін, який хотів би знати, що сталося в кодовій базі Godot, або коли і як заданий файл був востаннє змінений.
Щоб стиснути ці сторонні коміти в основні, нам доведеться переписати історію. Так, у нас є така влада. Ви можете прочитати, що це погана практика, і це правда, коли справа доходить до гілок апстрім-репо. Але у вашому форку можна робити все, що завгодно, і все дозволено, щоб отримати акуратний піар :)
Для цього ми використаємо інтерактивну перебазу git rebase -i. Ця команда приймає ідентифікатор коміту або назву гілки як аргумент і дозволить вам змінювати всі коміти між цим комітом/гілкою та останньою у вашій робочій гілці, так званій HEAD.
Хоча ви можете вказати будь-який ідентифікатор коміту для git rebase -i і переглянути все між ними, найпоширеніший і зручний робочий процес передбачає перебазування у верхній гілці master, яку ви можете зробити за допомогою:
git rebase -i upstream/master
Примітка
Посилання на гілки в Git є дещо складним через різницю між віддаленими та локальними гілками. Тут upstream/master (з /) є локальною гілкою, яка була отримана з master гілки віддаленого upstream.
Інтерактивне перебазування можна виконувати лише на локальних гілках, тому / тут важливий. Оскільки віддалений вихідний канал часто змінюється, ваша локальна гілка upstream/master може застаріти, тому ви можете оновити його за допомогою git fetch upstream master. На відміну від git pull --rebase upstream master, який оновить вашу поточну вилучену гілку, fetch оновить лише посилання upstream/master (яке відрізняється від вашого локального master гілка... так, це заплутано, але ви потроху з цим познайомитеся).
Це відкриє текстовий редактор (vi за замовчуванням, перегляньте Git docs, щоб налаштувати ваш улюблений) з чимось, що може виглядати так:
pick 1b4aad7 Add a pretty banner to the Project Manager
pick e07077e Fix a typo in the banner's title
Редактор також покаже інструкції щодо того, як ви можете діяти з цими комітами. Зокрема, у ньому має бути вказано, що «вибрати» означає використовувати цей комміт (нічого не робити), а «сквош» і «виправити» можна використовувати для змішування коміту в його батьківському коміті. Різниця між «squash» і «fixup» полягає в тому, що «fixup» видаляє журнал фіксації зі здавленого коміту. У нашому прикладі ми не зацікавлені у збереженні журналу коміту «Виправити помилку», тому ми використовуємо:
pick 1b4aad7 Add a pretty banner to the Project Manager
fixup e07077e Fix a typo in the banner's title
Після збереження та виходу з редактора відбудеться перебазування. Другий коміт буде об’єднано з першим, а git log і git show тепер повинні підтвердити, що у вас є лише один коміт зі змінами від обох попередніх комітів.
але! Ви переписали історію, і тепер ваші локальні та віддалені гілки розійшлися. Дійсно, фіксація 1b4aad7 у наведеному вище прикладі буде змінена, і, отже, отримано новий хеш фіксації. Якщо ви спробуєте надіслати до вашої віддаленої гілки, це викличе помилку:
git push origin better-project-manager
To https://github.com/akien-mga/godot
! [rejected] better-project-manager -> better-project-manager (non-fast-forward)
error: failed to push some refs to 'https://[email protected]/akien-mga/godot'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.
Це розумна поведінка, Git не дозволить вам внести зміни, які перевизначать віддалений вміст. Але насправді це те, що ми хочемо зробити тут, тому нам доведеться примусово це:
git push --force origin better-project-manager
І тадаа! Git із задоволенням замінить вашу віддалену гілку на те, що було у вас локально (тому переконайтеся, що це те, що ви хотіли, використовуючи git log). Це також оновить PR відповідно.
Перебазування на іншу гілку
Якщо ви випадково відкрили свій PR не на тій гілці або з якоїсь причини вам потрібно націлити іншу гілку, можливо, вам доведеться відфільтрувати багато комітів, які відрізняються між старою гілкою (наприклад, 4.2) і новою гілкою. гілка (наприклад master). Це може зробити перебазування складним і виснажливим. На щастя, у git є команда саме для цієї ситуації, git rebase --onto.
Якщо ваш PR було створено з гілки 4.2 і ви хочете оновити його, щоб натомість починатися з master, наступні кроки мають виправити це за один крок:
git rebase -i --onto master 4.2
Це візьме всі коміти у вашій гілці після гілки 4.2, а потім з’єднає їх поверх master, ігноруючи будь-які коміти з гілки 4.2, що не є master `` гілка. Можливо, вам все одно доведеться виконати деякі виправлення, але ця команда заощадить вам багато виснажливої роботи з видалення комітів.
Так само, як і вище, для інтерактивного перебазування вам потрібно змусити вашу гілку обробляти різні зміни:
git push --force origin better-project-manager
Вилучення гілки git
Після того, як ваш запит на отримання об’єднано, ви повинні зробити ще одне: видалити свою гілку Git для PR. Не виникне проблем, якщо ви не видалите свою гілку, але це добре робити. Вам потрібно буде зробити це двічі, один раз для локальної гілки та другий для віддаленої гілки на GitHub.
Щоб локально видалити нашу кращу гілку Project Manager, скористайтеся цією командою:
git branch -d better-project-manager
Крім того, якщо гілку ще не об’єднано, і ми все одно хочемо її видалити, замість -d ви б використовували -D.
Далі, щоб видалити віддалену гілку на GitHub, скористайтеся цією командою:
git push origin -d better-project-manager
Ви також можете видалити віддалену гілку з самого GitHub PR, після її об’єднання або закриття має з’явитися кнопка.