Перейти до змісту
Увійти

Теорія

Перша зміна в браузері і як її відкотити через revert

Невелика зміна повністю у вебінтерфейсі GitHub: знайти файл, відредагувати його у вебредакторі GitHub, закомітити в нову гілку, бо main захищена, відкрити pull request, пройти перевірки й рев'ю, змерджити й викласти. А потім зробити git revert змердженої зміни кнопкою Revert на GitHub, розібратися, коли відкочувати, а коли виправляти вперед, і що продакту варто й не варто редагувати самостійно.

~10 хв читання · 11 вправ · 250 балів

Перед початком

Виправ власноруч

Середа четвертого тижня в продуктовій команді Котокорму, і проблема знайома: підтримка втретє пересилає ту саму нотатку від клієнта про друкарську помилку на сторінці доставки. Цього разу хочеться виправити її власноруч, а Daniel охоче зробить рев'ю.

У цьому фінальному уроці ти внесеш невелику зміну повністю в браузері, від редагування файлу до злиття й деплою, а потім дізнаєшся, як скасувати вже змерджену зміну і що продуктовій людині варто й не варто редагувати.

Що редагує продакт, а що лишається за інженерами

Підтримка втретє пересилає ту саму скаргу клієнта: на сторінці доставки Котокорму написано, що кур'єри дзвонять «30 minutes before arival». Це текст на сторінці, а тексти сторінок належать продуктовій команді, тож виправити його можеш ти.

Перед першим кліком проведи межу.

Продакт-менеджерка впорядковує вітрину крамниці, а за задніми дверима зі значком шестерні інженери працюють біля механізмів.
  • Тексти й документацію продакт може безпечно редагувати: тексти сторінок у файлах .md, відповіді FAQ, README, шаблони issues у .github/ISSUE_TEMPLATE/. Це слова для людей.
  • Код і конфігурація лишаються за інженерами: компоненти на кшталт CheckoutButton.tsx, налаштування на кшталт config/prices.json, усе в .github/workflows/. Вони змінюють поведінку сайту. Одна пропущена кома в конфігураційному файлі може зупинити збирання всього сайту.
Продакт редагує тексти сторінок, FAQ, README і шаблони issues через pull request; код і конфігурація лишаються за інженерами.

Ціна в конфігурації здається «просто числом», але код читає її під час оформлення замовлення. Попроси про зміну в issue, а інженер зробить її з тестами й рев'ю.

Хай там як, звичний шлях не оминає ніщо. Навіть виправлення одного слова йде через pull request, з перевірками й рев'юером.

  • Так
    Виправити одрук у pages/delivery.md власноруч, через pull request, який перегляне Daniel.

    Слова для людей, з рев'ю.

  • Не так
    Змінити freeDeliveryFrom у config/prices.json у браузері, бо «це ж просто число».

    Його читає оформлення замовлення; попроси інженера змінити його з тестами.

Знайди файл, відкрий вебредактор

Усе відбувається в браузері.

  1. На сторінці репозиторію, у вкладці Code, відкрий папку pages, а потім delivery.md. Або натисни t і набери «delivery», щоб знайти файл за назвою.
  2. Подивись на перемикач гілок над файлом: там main, тобто версія, яка зараз на сайті.
  3. Угорі праворуч від файлу натисни іконку олівця, станом на 2026 рік це Edit this file. Вебредактор GitHub відкриється просто у вкладці.
  4. Виправ слово, а потім відкрий вкладку Preview, щоб побачити текст так, як він виглядатиме на сторінці, а не як сирий Markdown.

Поки друкуєш, нічого не зберігається й нічого не може зламатися. Доки не натиснеш Commit changes…, редактор — лише чернетка у вкладці браузера; ні гілки, ні коміту ще немає. Закриєш вкладку — правка зникне.

Коли дивитимешся на зміну, пам'ятай, як її показує Git: змінилося одне слово, а diff показує весь рядок двічі — стару версію видалено з -, нову додано з +.

  • Так
    Виправити «arival», а тоді перевірити примітку про кур'єрів у Preview, перш ніж комітити.

    Побач те, що побачать клієнти.

  • Не так
    Хвилюватися, що кожне натискання клавіші в редакторі вже змінює живу сторінку.

    Доки не закомітиш, нічого не існує.

Чому коміт іде в нову гілку

Натисни зелену кнопку Commit changes…, і діалог запитає, куди піде коміт. У репозиторії без правил варіант «Commit directly to the main branch» спрацював би, і зміна з'явилася б на сайті після наступного деплою.

У Котокормі main має захист гілки (branch protection): зміни потрапляють у неї лише через pull request, з одним схваленням і пройденими перевірками (build, test). Тож прямий варіант тобі недоступний, і ти вибираєш «Create a new branch for this commit and start a pull request». Створювати коміти твій акаунт може, просто не одразу в main.

Далі pull request проходить ті самі правила, що й у інженерів. Одне з них дивує: власний pull request схвалити не можна. GitHub не дає авторам схвалювати, тож «одне схвалення» завжди означає, що подивився хтось інший.

І річ не в часі. У Котокормі кожен мердж у main викладають за кілька хвилин, а щотижневий реліз лише позначає версію. Виправлення одруку чекає не на четвер, а на рев'юера.

  • Так
    «Create a new branch for this commit and start a pull request», а потім попросити Daniel про рев'ю.

    Захищений шлях у main.

  • Не так
    Схвалити власний pull request, щоб заощадити Daniel час.

    GitHub цього не дозволяє, а сенс рев'ю — друга пара очей.

Діалог коміту: повідомлення, гілка, Propose changes

Діалог Commit changes… питає про три речі.

Повідомлення коміту. GitHub заздалегідь пише «Update delivery.md». Це правда, але марна: в історії з двох тисяч комітів воно нікому не скаже, що сталося. Напиши кількома словами, що змінилося: «Fix typo in courier note». У необов'язковому розширеному описі нижче можна додати, навіщо.

Куди йде коміт. Оскільки main захищена, вибери «Create a new branch for this commit and start a pull request».

Назва гілки. GitHub пропонує щось на кшталт catchow-sofia-patch-1, складене з імені користувача. Це працює, але перейменуй гілку за звичкою команди, content/… для текстів і fix/… для багів: content/delivery-typo. Добра назва ще до відкриття каже дошці й рев'юеру, що всередині.

Потім натисни Propose changes. Коміт потрапить у нову гілку, а main не зміниться зовсім. Нічого ще не на сайті, нічого не переглянуто, і GitHub одразу веде тебе до створення pull request.

  • Так
    Повідомлення «Fix typo in courier note», гілка content/delivery-typo.

    Каже, що змінилося, і відповідає назвам команди.

  • Не так
    Повідомлення «Update delivery.md», гілка catchow-sofia-patch-1.

    Правда, але за місяць нікому нічого не скаже.

Від pull request до живої сторінки

Propose changes веде до «Open a pull request»: base main, compare content/delivery-typo. Назва береться з повідомлення коміту, а опис пишеш ти. Нехай він буде коротким і корисним: що (виправляє «arival» на сторінці доставки), навіщо (підтримка пересилала скаргу тричі), як перевірити (відкрити preview і прочитати примітку про кур'єрів) і хто переглядає (Daniel).

Натисни Create pull request. Він стане #168, і перевірки запустяться одразу: build, test і preview з власним посиланням на змінену сторінку.

Pull request #168, середа, 11:20
  • Fix courier typo and mention loyalty points#168

    Злито в main через squash · мердж: Sofia · гілку content/delivery-typo видалено

  • Daniel

    Схвалено

  • build

  • test

  • preview

  • deploy (production)

    Завершився за чотири хвилини після мерджу

Гілка лишається відкритою для подальшої роботи. Якщо попросять ще одну правку в тому самому файлі, відкрий його в content/delivery-typo і закоміть просто в цю гілку; pull request сам підхопить новий коміт. Онови назву, якщо обсяг змінився.

Коли перевірки зелені, а рев'юер схвалив, натисни Squash and merge: коміти гілки стануть одним комітом у main, а гілку можна видалити. Деплой завершиться за кілька хвилин. Останній крок за тобою: відкрий живу сторінку й сам прочитай рядок.

  • Так
    Опис: «Що: виправляє ‘arival’ на сторінці доставки. Навіщо: підтримка пересилала тричі. Перевірка: відкрити preview, прочитати примітку про кур'єрів. Рев'юер: Daniel.»

    Рев'юер за десять секунд розуміє, на що дивитися.

  • Не так
    Змерджити, закрити вкладку й так і не відкрити живу сторінку.

    Зміна не завершена, доки ти не побачиш її на сайті.

Змерджено й викладено — отже, показано

Через десять хвилин після мерджу підтримка пише знову. На прохання контент-маркетологині Emma #168 додав ще й рядок: «Отримуй бали лояльності за кожне замовлення й витрачай їх під час оформлення». Клієнтка прочитала цей рядок на сторінці доставки й питає, де знайти свої бали. Не знайде: бали лояльності для клієнтів досі вимкнені.

Фіча-флаг приховує лише ті частини сайту, які його перевіряють. Сторінка програми від Emma перевіряє loyalty-points, бо Daniel вбудував цю перевірку в #157. Код балансу й оформлення теж її мають. Речення в pages/delivery.md жодної перевірки довкола не має, тож щойно його змерджили й виклали, його побачив кожен відвідувач.

Це та сама помилка, що й посилання в меню від Daniel перед v1.4.1: фічу сховали, а один вхід до неї — ні. І рев'ю цього не помітило, бо рев'юер шукав у diff одруки, а не обіцянки.

Тож коли редагуєш тексти довкола прихованої фічі, перед мерджем постав ще одне запитання: чи не згадує цей текст щось, чим клієнти ще не можуть користуватися? Якщо згадує, текст чекає на запуск в окремому pull request. Squash-мердж, деплой і сторінки релізів флагів не чіпають узагалі.

  • Так
    Перед мерджем тексту: «Чи не згадує цей рядок щось, що ще сховано за флагом?»

    Одне запитання ловить витік.

  • Не так
    «Лояльність вимкнено флагом, тож і будь-який текст про неї схований.»

    Сховано лише те, що перевіряє флаг.

Що робить revert

Щоб скасувати змерджений pull request, відкрий його: унизу вкладки Conversation, поруч із позначкою про мердж, станом на 2026 рік є кнопка Revert.

Revert нічого не видаляє. Це новий коміт, який робить рівно протилежне до змердженого. GitHub створює гілку revert-168-content/delivery-typo з одним комітом, що скасовує #168, і готує для неї pull request, #169. Він проходить ті самі правила, що й будь-який інший: перевірки й одне схвалення. Скасування зміни — теж зміна.

Слід лап іде стежкою вперед, а другий слід повертається до попереднього місця; усі відбитки обох слідів досі видно.
Revert нічого не видаляє: це новий коміт, що скасовує старий.

Коли #169 змерджено й викладено, рядка Emma про лояльність, доданого в #168 перед мерджем, немає, але й виправлення одруку теж: «arival» повернувся. #168 став одним squash-комітом з обома змінами, а revert скасовує коміт цілком, ніколи не наполовину.

Revert скасовує рівно цей коміт і нічого після нього. Пізніші зміни лишаються на сайті. Історія зберігає все: початковий коміт, revert, хто що зробив і коли, а #168 і далі показує Merged. У командному рядку та сама ідея — git revert <commit>, що додає новий коміт, а не переписує історію.

Зміна та її revert у mainНічого не зникає: revert це новий коміт, який скасовує f3c8d21. Обидва лишаються в історії, а #168 і далі показує Merged.
  1. c3f7a05Show points balance in the account (#166)v1.5.0
  2. 8d2b6e9Write loyalty programme page (#157)
  3. 5e9a1b4Fix typo in courier note
  4. 1a7c4f2Mention loyalty points on delivery pagecontent/delivery-typo
  5. f3c8d21Fix courier typo and mention loyalty points (#168)
  6. a6b0e53Revert "Fix courier typo and mention loyalty points"revert-168-content/delivery-typo
  7. d7e2f48Revert "Fix courier typo and mention loyalty points" (#169)main

Граф комітів, від найстарішого: Зміна та її revert у main 1. коміт c3f7a05 у main "Show points balance in the account (#166)", тег v1.5.0 2. коміт 8d2b6e9 у main "Write loyalty programme page (#157)" 3. гілка content/delivery-typo починається від коміту 8d2b6e9 4. коміт 5e9a1b4 у content/delivery-typo "Fix typo in courier note" 5. коміт 1a7c4f2 у content/delivery-typo "Mention loyalty points on delivery page" 6. коміт f3c8d21: content/delivery-typo змерджено в main через squash "Fix courier typo and mention loyalty points (#168)" 7. гілка revert-168-content/delivery-typo починається від коміту f3c8d21 8. коміт a6b0e53 у revert-168-content/delivery-typo "Revert "Fix courier typo and mention loyalty points"" 9. коміт d7e2f48: revert-168-content/delivery-typo змерджено в main через squash "Revert "Fix courier typo and mention loyalty points" (#169)" (виділено)

  • Так
    Натиснути Revert на #168, провести #169 через рев'ю й мердж, як будь-який інший pull request.

    Новий коміт скасовує старий; історія лишається повною.

  • Не так
    Чекати, що revert #168 збереже виправлення одруку й прибере лише рядок про лояльність.

    Squash-коміт скасовується цілком.

Revert чи виправлення вперед?

Рядок про лояльність можна було й просто видалити новим pull request. Це виправлення вперед (fix forward): нова зміна, яка усуває проблему, і виправлення одруку тоді лишилося б.

  • Revert, коли на сайті помилка й треба просто зараз повернути останню робочу версію, особливо коли правильне виправлення ще неочевидне: зламане оформлення замовлення з незрозумілою причиною, банер із датами, які ще уточнюють.
  • Виправлення вперед, коли воно крихітне й зрозуміле (одне неправильне число у відповіді FAQ) або коли revert забрав би з собою добрі зміни (п'ять добрих змін і одна помилка в тексті).
Revert одразу повертає останню робочу версію, коли виправлення неочевидне; виправляй уперед, коли воно крихітне й зрозуміле або revert забрав би добрі зміни.

Два обмеження. Кнопка Revert спрацьовує не завжди: якщо пізніші зміни зачепили ті самі рядки, GitHub не зможе сам зібрати revert, і його вручну робить інженер. І revert коду не скасовує того, що вже сталося. Якщо через баг клієнти отримали неправильні бали, revert зупинить нові, але виправлення їхніх балансів потребує плану, а не кнопки.

Тут рядок був обіцянкою, яку Котокорм ще не міг виконати, а одрук міг повисіти ще годину. Почати з revert було правильно.

Там, де дорога розходиться, один шлях повертає до знайомого безпечного будинку, а інший веде вперед до бригади, що латає вибоїну.
  • Так
    Після останнього мерджу зламалося оформлення, і ніхто ще не знає чому: revert зараз, розбиратися потім.

    Спершу остання робоча версія.

  • Не так
    Робити revert великого pull request з п'ятьма добрими змінами через одне неправильне слово.

    Краще виправити слово вперед.

  • Не так
    «Ми зробили revert бага з балами, тож баланси клієнтів знову в порядку.»

    Revert зупиняє нову шкоду, але не виправляє вже завдану.

Одна зміна — один pull request

#168 змішав дві зміни, в яких не було нічого спільного, крім файлу: виправлення одруку, яке могло з'явитися на сайті одразу, і рядок про лояльність, якому треба було чекати на запуск. Злиті в один коміт, вони скасовувалися лише разом.

Тож прибирання — це два pull requests:

  • #170, гілка content/courier-typo, один коміт «Fix typo in courier note» і така сама назва. Лише одрук. Daniel схвалює його за кілька хвилин.
  • Рядок Emma отримує власний pull request, готовий до мерджу 10 листопада, того ранку, коли флаг увімкнуть для всіх.

Правило за цим: одна зміна — один pull request. Тоді кожну можна окремо переглянути, змерджити, коли вона готова, і скасувати, нічого не зачепивши. Коли тебе просять додати «ще один рядок» у відкритий pull request, запитай себе, чи це та сама зміна.

І розкажи людям, що сталося. Emma попросила про свій рядок із добрих намірів і захоче повернути його за шість днів: два-три речення в командному чаті про те, чому його прибрали, що зараз на сайті й коли він повернеться, збережуть їй годину хвилювань.

  • Так
    #170 «Fix typo in courier note» зараз; рядок Emma — окремим pull request на 10 листопада.

    Кожна зміна мерджиться й скасовується окремо.

  • Не так
    «Поки ти там, додай заодно рядок про лояльність?» — і він потрапляє в той самий pull request.

    Не пов'язані зміни стають одним комітом, який потім не розділиш.

Готові потренуватися?

Виконайте вправи уроку й отримайте 250 балів, коли пройдете його вперше.

Розпочати вправи