Типові ситуації при безперервній інтеграції

Ви вивчили команди Git, але хочете уявляти, як безперервна інтеграція (Continuous Integration, CI) відбувається в реальності? Чи, можливо, ви хочете оптимізувати свої щоденні дії? Цей курс дасть вам практичні навички безперервної інтеграції з використанням репозиторію на GitHub. Цей курс не задуманий як якийсь візард, який можна просто прокликати, навпаки, ви будете робити ті ж дії, що люди насправді роблять на роботі, тим самим способом, яким вони це роблять. Я поясню теорію в міру проходження вами кроків, що мають до неї відношення.

Що ми будемо робити?

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

Цей GIF схематично показує коміти у репозиторії у міру просування по курсу. Як бачите, тут немає нічого складного і лише найнеобхідніше.

Типові ситуації при безперервній інтеграції

Ви пройдете такі стандартні для CI сценарії:

  • Робота над фічею;
  • застосування автотестів для забезпечення якості;
  • Реалізація пріоритетного завдання;
  • Вирішення конфлікту при злитті гілок (merge conflict);
  • Виникнення помилки у продуктивному середовищі.

Що ви впізнаєте?

Ви зможете відповісти на такі запитання:

  • Що таке безперервна інтеграція (CI)?
  • Які типи автотестів використовуються при CI і у відповідь на які дії вони запускаються?
  • Що таке pull request та коли вони потрібні?
  • Що таке технологія через тестування (Test Driven Development, TDD) і як вона співвідноситься з CI?
  • Здійснювати злиття (merge) чи застосовувати зміни поверх (rebase)?
  • Відкочувати чи лагодити в наступній версії?

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

Що таке безперервна інтеграція?

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

Існують різночитання щодо цього терміну

Предметом суперечки є частота інтеграції. Деякі стверджують, що об'єднувати код лише щодня недостатньо насправді інтегруватися безупинно. В приклад наводиться команда, де всі беруть новий код вранці і інтегруються один раз увечері. Хоча це і розумне заперечення, все ж таки в цілому вважається, що варіант визначення "щодня" досить практичний, конкретний, і підходить для команд різних розмірів.

Інше заперечення полягає в тому, що C ++ давно не єдина мова, що використовується при розробці, і проста вимога складання без помилок, як спосіб валідації, слабенька. Набір тестів (наприклад, модульних (unit), що виконуються локально) також повинен завершитися успішно. В даний момент, спільнота тяжіє до того, щоб така вимога була обов'язковою, і, в майбутньому "складання + модульні тести", мабуть, стане загальноприйнятим, якщо це вже не сталося.

Безперервна інтеграція відрізняється від безперервного постачання (Continuous Delivery, CD) тим, що вимагає реліз-кандидата після кожного циклу інтеграції.

Список кроків, які ми будемо використовувати протягом курсу

  1. Pull in the latest code. Create a branch from master. Start working.
  2. Create commits on your new branch. Build and test locally. Pass? Go до the next step. Fail? Fix errors or tests and try again.
  3. Push to your remote repository or remote branch.
  4. Create a pull request. Discuss the changes, add more commits as discussion continues. Make tests pass на feature branch.
  5. Merge/rebase commits from master. Make tests pass на merge result.
  6. Deploy from the feature branch to production.
  7. Якщо все це добре в production для деякого періоду часу, merge changes to master.

Типові ситуації при безперервній інтеграції

️ Підготовка

Переконайтеся в наявності потрібного програмного забезпечення

Щоб пройти цей курс вам знадобиться Node.js и Git-клієнт.

Можете використовувати будь-який Git-клієнт, але я наводитиму команди тільки для командного рядка.

Переконайтеся, що у вас встановлений Git-клієнт, який підтримує командний рядок

Якщо у вас поки не встановлений Git-клієнт, який підтримує командний рядок, можете знайти інструкції з встановлення тут.

Підготуйте репозиторій

Вам потрібно створити особисту копію (fork) репозиторія-шаблону з кодом для курсу на GitHub. Давайте домовимося називати цю особисту копію репозиторієм курсу.

Зробили? Якщо ви не змінювали налаштування за замовчуванням, ваш репозиторій курсу швидше за все називається continuous-integration-team-scenarios-students, він знаходиться у вашому обліковому записі на GitHub, і URL виглядає так

https://github.com/<ваше имя ползователя на GitHub>/continuous-integration-team-scenarios-students

Я називатиму цю адресу просто <URL репозитория>.

Кутові дужки як <тут> означатиме, що ви повинні замінити такий вираз на відповідне значення.

Впевніться, що GitHub actions включені для цього репозиторію курсу. Якщо вони не будуть увімкнені, будь ласка, увімкніть їх, натиснувши на велику кнопку в середині сторінки, на яку ви можете потрапити, натиснувши Actions в інтерфейсі GitHub.

Вам не вдасться пройти курс, дотримуюсь моїх інструкцій, якщо GitHub Actions не будуть включені.

Типові ситуації при безперервній інтеграції

Ви завжди можете використовувати здатність GitHub відображати Markdown щоб побачити поточний стан списку, який ми вигадуємо, тут

https://github.com/<your GitHub user name>/continuous-integration-team-scenarios-students/blob/master/ci.md

Про відповіді

Хоча найкращий спосіб завершити цей курс це робити все своїми руками, у вас можуть і виникнути складності.

Якщо ви відчуваєте, що не розумієте, що робити і не можете продовжувати, можете піддивитися в гілку solutionяка є у вашому стартовому репозиторії.
Будь ласка, не здійснюйте злиття solution в master під час курсу. Ви можете використовувати цю гілку, щоб розібратися, що робити, або щоб порівнювати свій код з авторським, використовуючи всі можливості, які дає нам Git. Якщо ви зовсім загубилися, можете повністю замінити свою гілку master на гілку solution і потім скинути свою робочу директорію до кроку курсу, який вам потрібен.

Використовуйте це тільки якщо вам це дійсно потрібно

Закоментуйте свій код

git add .
git commit -m "Backing up my work"

Ці команди

  • перейменовують master в master-backup;
  • перейменовують solution в master;
  • перемикають (checkout) на нову гілку master та переписують вміст робочої директорії;
  • створюють гілку "solution" з "master" (яка раніше була "solution") на випадок, якщо вам у майбутньому знадобиться гілка "solution".

git branch -m master master-backup
git branch -m solution master
git checkout master -f
git branch solution

Після цих дій ви можете використати git log master щоб з'ясувати, який коміт вам потрібний.
Ви можете скинути свою робочу директорію на цей коміт так:

git reset --hard <the SHA you need>

Якщо ви задоволені результатом, в якийсь момент вам знадобиться опублікувати вашу версію репозиторію у віддалений репозиторій (remote). Не забудьте явно вказати віддалену гілку коли це робитимете.

git push --force origin master

Будь ласка, зверніть увагу, що ми використовуємо git push --force. Навряд чи ви часто захочете так чинити, але в нас тут вкрай специфічний сценарій з одним користувачем репозиторію, який до того ж розуміє, що він робить.

Starting working

Типові ситуації при безперервній інтеграції

Почнемо складати наш перелік кроків CI. Зазвичай ви починаєте цей крок із вилучення останньої версії коду з віддаленого репозиторію, але в нас ще немає локального репозиторію, тому натомість ми клонуємо його з віддаленого.

️ Завдання: оновіть локальний репозиторій, створіть гілку з master, почніть працювати

  1. Клонуйте репозиторій курсу з <URL репозитория>.
  2. запустіть npm install у каталозі репозиторія курсу; він потрібний нам для встановлення Jest, який ми використовуємо для запуску тестів.
  3. Створіть гілку та назвіть її feature. Перейдіть на цю гілку.
  4. Додайте тестовий код до ci.test.js між коментарями із проханням зробити це.

    it('1. pull latest code', () => {
      expect(/.*pull.*/ig.test(fileContents)).toBe(true);
    });
    
    it('2. add commits', () => {
      expect(/.*commit.*/ig.test(fileContents)).toBe(true);
    });
    
    it('3. push to the remote branch with the same name', () => {
      expect(/.*push.*/ig.test(fileContents)).toBe(true);
    });
    
    it('4. create a pull request and continue working', () => {
      expect(/.*pulls+request.*/ig.test(fileContents)).toBe(true);
    });

  5. Додайте текст із першими 4 кроками до файлу ci.md.
    1. Pull in the latest code. Create a branch from `master`. Start working.    
    2. Create commits on your new branch. Build and test locally.  
    Pass? Go to the next step. Fail? Fix errors or tests and try again.  
    3. Push to your remote repository or remote branch.  
    4. Create a pull request. Discuss the changes, add more commits  
    as discussion continues. Make tests pass on the feature branch.  

    Команди

# Клонируйте репозиторий курса
git clone <repository URL>
cd <repository name>

# Выполните npm install в каталоге репозитория курса; он установит Jest, который мы используем для запуска тестов.
npm install

# Создайте ветку и назовите ее feature. Переключитесь на эту в ветку.
git checkout -b feature

# Отредактируйте ci.test.js как описано выше.
# Отредактируйте ci.md как описано выше

Створюйте комміти у новій гілці, здійснюйте складання та тестування локально.

Ми збираємося налаштувати тести, щоб вони запускалися перед коммітом, а потім закоммітити код.

Типові сценарії, коли тести запускаються автоматично

  • Локально:
    • Постійно чи у відповідь на відповідні зміни коду;
    • При збереженні (для інтерпретованих або JIT-компілюваних мов);
    • При збиранні (коли потрібна компіляція);
    • При коміті;
    • При публікації до загального репозиторію.

  • На сервері збирання (build server) або в середовищі збирання:
    • Коли код публікується в персональну гілку/репозиторій.
    • Тестується код у цій гілці.
    • Тестується потенційний результат злиття (зазвичай з master).
    • Як етап безперервної інтеграції/конвеєра безперервного постачання

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

  • Швидкі модульні тести - при складанні, в конвеєрі CI
  • Повільні модульні тести, швидкі компонентні та інтеграційні тести - при коміті, в конвеєрі CI
  • Повільні компонентні та інтеграційні тести – у конвеєрі CI
  • Тестування безпеки, навантажувальне та інші тривалі або дорогі тести — у конвеєрах CI/CD, але тільки в певних режимах/етапах/конвеєрах складання, наприклад, під час підготовки реліз-кандидата або запуску вручну.

️ Завдання

Я пропоную спочатку запустити тести вручну, використовуючи команду npm test. Після цього давайте додамо git hook для запуску наших тестів у коміті. Є одна проблема: Git hooks не вважаються частиною репозиторію і тому не можуть бути клоновані з GitHub разом з іншими матеріалами курсу. Щоб встановити hook, вам потрібно запустити install_hook.sh або скопіювати файл repo/hooks/pre-commit у локальний каталог .git/hooks/.
Під час коміту ви побачите, що виконуються тести, і вони перевіряють, чи є у списку певні ключові слова.

  1. Запустіть тести вручну, виконавши команду npm test у папці репозиторію вашого курсу. Переконайтеся, що випробування були виконані.
  2. Встановіть hook на коміт (pre-commit hook), запустивши install_hook.sh.
  3. Закохніть зміни до локального репозиторію.
  4. Перевірте, чи тести виконуються перед комітом.

Ваш репозиторій має виглядати так після виконання цих дій.
Типові ситуації при безперервній інтеграції

Команди

# Установите pre-commit hook выполнив install_hook.sh.  

# Закоммитьте изменения в локальный репозиторий. Используйте "Add first CI steps" в качестве сообщения при коммите.
git add ci.md ci.test.js
git commit -m "Add first CI steps"

# Убедитесь, что тесты запускаются перед коммитом.  

Опублікуйте код у віддалений репозиторій або віддалену гілку

Завершивши працювати локально, розробники зазвичай роблять свій код загальнодоступним, щоб його можна було зрештою інтегрувати із загальним. За допомогою GitHub це зазвичай досягається публікацією роботи або в персональній копії репозиторію (personal fork, форк), або в особистій гілці.

  • При використанні форків розробник клонує спільний віддалений репозиторій, створюючи його особисту віддалену копію, також відому як форк. Після цього він клонує цей особистий репозиторій, щоб працювати з ним локально. Коли робота завершена і створені комміти, він поміщає їх у свій форк, де вони доступні іншим і можуть бути інтегровані в загальний репозиторій. Цей підхід зазвичай використовується в проектах з відкритим кодом на GitHub. Він також використовується в моєму розширеному курсі [Team Work and CI with Git] (http://devops.redpill.solutions/).
  • Інший підхід полягає в тому, щоб використовувати лише один віддалений репозиторій і вважати лише гілку master спільно використовується репозиторія "захищеної". У цьому сценарії окремі розробники публікують свій код у гілки віддаленого репозиторію, щоб інші могли цей код подивитися, якщо все гаразд, об'єднати з master загального репозиторію.

У цьому конкретному курсі ми використовуватимемо робочий процес, який використовує гілки.

Давайте опублікуємо наш код.

️ Завдання

  • Опублікуйте зміни у віддалену гілку з тим самим ім'ям, що й ваша робоча гілка

Команди

git push --set-upstream origin feature

Створіть pull request

Створіть pull request під назвою Steps review. встановіть feature як "head branch" та master як "base branch".

Переконайтеся, що ви встановили master в своєму форці репозиторію як "base branch", я не відповідатиму на запити на зміни в репозиторій з матеріалами курсу.

На сленгу GitHub "base branch" - це гілка, на якій ви ґрунтуєте свою роботу, а "head branch" - це гілка, що містить пропоновані зміни.

Обговоріть зміни, додайте нові коміти з продовженням обговорення

Pull request(PR)

Pull request(PR) - це спосіб обговорити та задокументувати код, а також провести перевірку (code review) коду. Pull request названо на честь загального способу інтеграції окремих змін до загального коду. Зазвичай людина клонує віддалений офіційний репозиторій проекту та працює над кодом локально. Після цього він поміщає код у свій власний віддалений репозиторій і вимагає відповідальних за офіційний репозиторій забрати(тягнути) його код у свої локальні репозиторії, де вони переглядають і, можливо, інтегрують(злиття) його. Це поняття відоме і під іншими назвами, наприклад, merge request.

Насправді, вам не обов'язково використовувати функцію pull request GitHub або аналогічних платформ. Команди розробників можуть використовувати інші способи зв'язку, включаючи особисте спілкування, голосові дзвінки або електронну пошту, але є все ж таки ряд причин використовувати такі pull requests у стилі обговорення на форумі. Ось деякі з них:

  • організовані обговорення, пов'язані з конкретними змінами коду;
  • як місце для перегляду відгуків про незавершену роботу як від автотестів, так і від колег;
  • формалізація перевірок коду;
  • щоб пізніше можна було з'ясувати причини та міркування, що стоять за тим чи іншим фрагментом коду.

Зазвичай ви створюєте pull request, коли вам потрібно щось обговорити або отримати зворотний зв'язок. Наприклад, якщо ви працюєте над функцією, яка може бути реалізована кількома способами, ви можете створити запит на внесення змін ще до написання першого рядка коду, щоб поділитися своїми ідеями та обговорити свої плани із співавторами. Якщо робота простіша, pull request відкривається, коли щось уже зроблено, зафіксовано та може бути обговорено. У деяких сценаріях ви можете відкрити PR тільки з міркувань контролю якості: щоб запустити автоматичні тести або ініціювати перевірку коду. Що б ви не вирішили, не забувайте @згадувати людей, схвалення яких потрібно у вашому pull request'і.

Зазвичай під час створення PR ви робите таке.

  • Вказуєте, що ви пропонуєте змінити і де.
  • Пишете опис, який пояснює мету змін. Ви можете захотіти:
    • додати щось важливе, що не є очевидним з коду, або щось корисне для розуміння контексту, наприклад, відповідні #баги та номери коммітів;
    • @згадати всіх, з ким хочете почати працювати разом, або ви можете @згадати їх у коментарях пізніше;
    • попросити колег допомогти з чимось або перевірити щось конкретне.

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

Зачекайте, поки завершаться тести. Ви можете побачити статус тестів у нижній частині обговорення PR в інтерфейсі GitHub. Продовжуйте, коли тести будуть завершені.

️ Додати зауваження про довільність списку кроків CI

Список, використаний у цьому курсі, є довільним та суб'єктивним, ми повинні додати примітку про це.

️ Завдання: створення pull request для цієї примітки

  1. Перейдіть на гілку master.
  2. Створіть гілку з ім'ям bugfix.
  3. Додайте текст примітки до кінця файлу ci.md.
    > **GitHub flow** is sometimes used as a nickname to refer to a flavor of trunk-based development  
    when code is deployed straight from feature branches. This list is just an interpretation  
    that I use in my [DevOps courses](http://redpill.solutions).  
    The official tutorial is [here](https://guides.github.com/introduction/flow/).
  4. Закохніть зміни.
  5. Опублікуйте гілку bugfix у віддалений репозиторій.
  6. Створіть pull request з ім'ям Adding a remark з головною гілкою bugfix та базовою гілкоюmaster.

Переконайтеся, що ви встановили master в своєму форці репозиторію як "base branch", я не відповідатиму на запити на зміни в репозиторій з матеріалами курсу.

Ось як має виглядати ваш репозиторій.
Типові ситуації при безперервній інтеграції

Команди

# Переключитесь на ветку master. Создайте ветку bugfix.
git checkout master

# Создайте ветку bugfix-remark.
git checkout -b bugfix

# Добавьте текст примечания внизу ci.md.

# Закоммитьте изменения
git add ci.md
git commit -m "Add a remark about the list being opinionated"

# Опубликуйте ветку bugfix в удалённый репозиторий.
git push --set-upstream origin bugfix

# Создайте pull request при помощи интерфейса GitHub как описано выше

Затвердіть "Пуль решта "Adding a remark"

️ Завдання

  1. Створіть повний запит.
  2. Натисніть кнопку "Merge pull request".
  3. Натисніть кнопку "Confirm merge".
  4. Натисніть "Delete branch", вона нам більше не потрібна.

Це діаграма коммітів після злиття.
Типові ситуації при безперервній інтеграції

️ Продовжуйте працювати та додавати тести

p align="justify"> Спільна робота над pull request часто призводить до необхідності додаткової роботи. Зазвичай це результат перевірки коду або обговорення, але в нашому курсі ми збираємося змоделювати це, додавши нові елементи до нашого списку кроків CI.

При безперервній інтеграції зазвичай використовується деяке тестове покриття. Вимоги до покриття тестами різняться і зазвичай перебувають у документі під назвою на кшталт " посібник для авторів " (contribution guidelines). Ми зробимо просто і додамо тест для кожного рядка в нашому контрольному списку.

Під час виконання завдань спочатку спробуйте закомтіти тести. Якщо ви правильно встановили pre-commit hook раніше, щойно доданий тест буде запущено, не буде пройдено, і нічого не буде закоммічено. Зверніть увагу: так ми дізнаємось, що наші тести справді щось перевіряють. Цікаво, що якби ми почали з коду до тестів, проходження тестів могло означати те, що код працює так, як очікувалося, або що тести насправді нічого не перевіряють. Крім того, якби ми не написали тести в першу чергу, ми могли б їх зовсім забути, оскільки ніщо не нагадувало б нам про це.

Розробка через тестування (TDD)

TDD рекомендує писати тести перед кодом. Звичайний процес роботи з використанням TDD має такий вигляд.

  1. Додати тест.
  2. Запустіть усі тести та переконайтеся, що новий тест не проходить успішно.
  3. Напишіть код.
  4. Запустіть тести, переконайтеся, що всі тести успішно проходять.
  5. Проведіть рефакторинг коду.
  6. Повторіть.

Оскільки результати роботи тестів, які не були пройдені успішно, зазвичай відображається червоним, а виконані успішно зеленим, цикл також відомий як "червоний-зелений-рефакторинг" (red-green-refactor).

️ Завдання

Спочатку спробуйте закомітіті тести і дати їм завершитися неуспішно, потім додайте і закомтіть сам текст списку кроків CI. Ви побачите, що тести проходять ("зелені").
Потім опублікуйте новий код у віддалений репозиторій та подивіться, як виконуються тести в інтерфейсі GitHub у нижній частині обговорення запиту на внесення змін, та оновлюється статус PR.

  1. Перейдіть на гілку feature.
  2. Додайте ці тести до ci.test.js після останнього виклику it (...);.

    it('5. Merge/rebase commits from master. Make tests pass on the merge result.', () => {
      expect(/.*merge.*commits.*testss+pass.*/ig.test(fileContents)).toBe(true);
    });
    
    it('6. Deploy from the feature branch to production.', () => {
      expect(/.*Deploy.*tos+production.*/ig.test(fileContents)).toBe(true);
    });
    
    it('7. If everything is good in production for some period of time, merge changes to master.', () => {
      expect(/.*merge.*tos+master.*/ig.test(fileContents)).toBe(true);
    });

  3. Спробуйте закомитити тести. Якщо pre-commit hook встановлено, спроба комміта завершиться помилкою.
  4. Після додайте цей текст до ci.md.
    5. Merge/rebase commits from master. Make tests pass on the merge result.  
    6. Deploy from the feature branch with a sneaky bug to production.
    7. If everything is good in production for some period of time, merge changes to master. 
  5. Внесіть та закомтіть зміни локально.
  6. Опублікуйте зміни у гілку feature.

Тепер у вас має вийти щось на зразок цього
Типові ситуації при безперервній інтеграції

Команди


# Переключительна ветку feature
git checkout feature

# Добавить тесты в ci.test.js как описано выше

# Добавьте в индекс ci.test.js чтобы позже закоммитить
git add ci.test.js

# Попытайтесь закоммитить тесты. Если pre-commit hook установлены, коммит не произойдёт.
git commit

# Теперь добавьте текст в ci.md как описано выше

# Внесите изменения и закоммитьте их
git add ci.md
git commit -m "Add the remaining CI steps"

# Опубликуйте изменения в ветку feature
git push

Конфлікт злиття

Перейдіть до запиту на внесення змін Steps review.

Незважаючи на те, що ми не зробили нічого поганого, і тести для нашого коду пройшли успішно, ми все ще не можемо здійснити злиття гілки. feature и master. Це тому, що інша гілка bugfix була об'єднана з master доки ми працювали над цим PR.
Це створює ситуацію, коли віддалена гілка master має новішу версію, ніж та, на якій ми засновували гілку feature. Через це ми не можемо просто перемотати HEAD master до кінця гілки feature. У цій ситуації нам потрібно або здійснити злиття, або застосувати коміти. feature поверх(rebase) master. GitHub насправді може виконувати автоматичне злиття, якщо немає конфліктів. На жаль, у нашій ситуації обидві гілки мають конкуруючі зміни у файлі ci.md. Ця ситуація відома як конфлікт при злитті (merge conflict), і нам потрібно вирішити її вручну.

Merge або rebase

Злиття

  • Створює додатковий коміт злиття (merge commit) та зберігає історію роботи.
    • Зберігає вихідні комміти гілок із вихідними відмітками часу та авторами.
    • Зберігає SHA коммітів та посилання на них в обговореннях запитів на зміни.
  • Потребує одноразового вирішення конфліктів.
  • Робить історію нелінійною.
    • Історію може бути важко читати через велику кількість гілок (нагадує кабель IDE).
    • Ускладнює автоматичне налагодження, наприклад, робить git bisect менш корисним – він тільки знайде комміт злиття.

База даних

  • Відтворює комміти з поточної гілки поверх базової один за одним.
    • Формуються нові комміти з новими SHA, в результаті чого коміти GitHub співвідносяться з вихідними pull requests, але не з відповідними коментарями.
    • Коміти можуть бути рекомбіновані та змінені у процесі або навіть об'єднані в один.
  • Може знадобитися вирішити кілька конфліктів.
  • Дозволяє підтримувати лінійну історію.
    • Історію може бути простіше читати, якщо вона не є занадто довгою без розумних на те причин.
    • Автоматичне налагодження та усунення несправностей дещо простіше: уможливлює git bisect, може зробити автоматичні відкати більш чіткими та передбачуваними.
  • Потрібна публікація гілки з перенесеними комітами з прапором --force у разі використання із запитами на внесення змін.

Зазвичай команди погоджуються завжди використовувати ту саму стратегію, коли їм потрібно об'єднувати зміни. Це може бути "чисте" злиття або "чисте" застосування коммітів поверх або щось проміжне, наприклад, виконання застосування коммітів поверх інтерактивному режимі(git rebase -i) локально для гілок, не опублікованих у загальному репозиторії, але злиття (merge) для "загальнодоступних" гілок.

Тут ми використовуватимемо злиття.

️ Завдання

  1. Переконайтеся, що код у локальній гілці master оновлено з віддаленого репозиторію.
  2. Перейдіть на гілку feature.
  3. Ініціюйте злиття з гілкою master. Буде повідомлено про конфлікт злиття, пов'язаний з конкуруючими змінами ci.md.
  4. Вирішити конфлікт так, щоб у тексті залишився і наш список кроків CI, і зауваження про нього.
  5. Опублікуйте коміт злиття у віддалену гілку feature.
  6. Перевірте статус pull request'а в інтерфейсі користувача GitHub, дочекайтеся поки злиття не буде дозволено.

Команди

# Убедитесь, что код в локальное ветке `master` обновлён из удалённого репозитория.
git checkout master
git pull

# Переключитесь на ветку feature
git checkout feature

# Инициируйте слияние с веткой master 
git merge master

# A merge conflict related to concurrent changes to ci.md will be reported
# => Auto-merging ci.md
#    CONFLICT (content): Merge conflict in ci.md
#    Automatic merge failed; fix conflicts and then commit the result.

# Разрешите конфликт так, чтобы и наш список шагов CI, и замечание о нем остались в тексте.
# отредактируйте ci.md чтоб он не содержал маркеров конфликта слияния
git add ci.md
git merge --continue
# при коммите можете оставить сообщение по умолчанию

# Опубликуйте коммит слияния в удаленную ветку feature.
git push

# Проверьте статус запроса на изменения в пользовательском интерфейсе GitHub, дождитесь пока слияние не будет разрешено.

Відмінна робота!

Ви закінчили роботу зі списком і тепер вам потрібно затвердити pull request в master.

️ Завдання: Затвердіть pull request "Steps review"

  1. Відкрийте pull request.
  2. Натисніть кнопку "Merge pull request".
  3. Натисніть кнопку "Confirm merge".
  4. Натисніть "Delete branch", тому що вона нам більше не потрібна.

Це ваш репозиторій зараз
Типові ситуації при безперервній інтеграції

Помилка на продуктивності

Кажуть, що «тестування можна використовувати, щоб показати наявність помилок, але ніколи, щоб показати їх відсутність». Незважаючи на те, що у нас були тести, і вони не показали нам жодних помилок, підступна помилка проникла у продакшн.

У подібному сценарії нам потрібно подбати про:

  • те, що розгорнуто на продуктиве;
  • коді у гілці master з помилкою, з якої розробники можуть розпочинати нову роботу.

Відкочувати чи виправляти у наступній версії?

"Відкочування" (rolling back) - це розгортання свідомо справної більш ранньої версії в продуктивне середовище і скасування (revert) коммітів, що містять помилку. "Виправлення в наступній версії"(fixing forward) - це додавання виправлення в master і розгортання нової версії якнайшвидше. Оскільки API та схеми баз даних змінюються у міру розгортання коду у виробничому середовищі, при безперервному постачанні та наявності хорошого покриття тестами, відкочування, як правило, набагато складніше та ризикованіше, ніж виправлення в наступній версії.

Оскільки відкочування не несе в нашому випадку жодного ризику, ми підемо цим шляхом, адже це дозволяє нам

  • виправити помилку на продуктивності якнайшвидше;
  • зробити код у master Одночасно придатним для початку нової роботи.

️ Завдання

  1. Перейдіть на гілку master локально.
  2. Оновіть локальний репозиторій із віддаленого репозиторію.
  3. Скасуйте коміт злиття PR Steps review в master.
  4. Опублікувати зміни до віддаленого репозиторію.

Це історія репозиторію зі скасованим коммітом злиття
Типові ситуації при безперервній інтеграції

Команди

# Переключитесь на ветку master.
git checkout master

# Обновите локальный репозиторий из удалённого репозитория.
git pull

# Отмените коммит слияния PR Steps review в master.
# Мы отменяем коммит слияния, поэтому нам нужно выбрать ветку истории, которую мы захотим оставить
git show HEAD

# предположим, что коммит, который был последним в ветке master до слияния, был отображён предыдущей командой первым
git revert HEAD -m 1
# можете не менять сообщения коммитов

# Опубликуйте изменения в удалённый репозиторий
git push

️ Самоперевірка

Переконайтесь, що ci.md більше не містить тексту "sneaky bug" після скасування комміту злиття.

Виправити список кроків CI і повернути його до master

Ми повністю скасували коміт злиття гілки feature. Хороша новина в тому, що тепер у нас немає помилки у master. Погана новина про те, що зник і наш дорогоцінний список кроків безперервної інтеграції. Отже, в ідеалі, нам потрібно застосувати виправлення до комітів з feature і повернути їх у master разом із виправленням.

Ми можемо підійти до завдання по-різному:

  • скасувати комміт, яка скасовує злиття feature с master;
  • перенести коміти з колишньої feature.

Різні команди розробників в даному випадку використовують різні підходи, ми ж перенесемо корисні комміти в окрему гілку і створимо окремий pull request для цієї нової гілки.

️ Завдання

  1. Створіть гілку під назвою feature-fix і перейдіть на неї.
  2. Перенесіть усі комміти з колишньої гілки feature у нову гілку. Вирішіть конфлікти злиття, які виникли під час перенесення.

    Типові ситуації при безперервній інтеграції

  3. Додайте регресійний тест у ci.test.js:

    it('does not contain the sneaky bug', () => {
    expect( /.*sneakys+bug.*/gi.test(fileContents)).toBe(false);
    });

  4. Запустіть тести локально, щоб переконатися, що вони успішно не завершуються.
  5. Видаліть текст " with a sneaky bug" в ci.md.
  6. Додайте до індексу зміни тестів та зміни у списку кроків і закомтіть їх.
  7. Опублікуйте гілку у віддалений репозиторій.

У вас в результаті має вийти щось схоже
Типові ситуації при безперервній інтеграції

Команди

# Создайте ветку под названием feature-fix и переключитесь на нее.
git checkout -b feature-fix

# Перенесите все коммиты из бывшей ветки feature в новую ветку. Разрешите конфликты слияния, которые возникли при переносе.
# используйте историю чтобы узнать хэши коммитов:
# - предшествующего коммиту с первой частью списка: C0
# - добавляющего последние элементы списка: C2
git log --oneline --graph
git cherry-pick C0..C2
# разрешите конфликты слияния
# - отредактируйте ci.md и/или ci.test.js
# - добавьте файлы в индекс
# - выполните "git cherry-pick --continue", можете не менять сообщение коммита

# Добавьте регрессионный тест в ci.test.js
# Запустите тесты локально, чтобы убедиться, что они не завершаются успешно.

# Удалите текст " with a sneaky bug" в ci.md.

# Добавьте в индекс изменения тестов и в списке шагов и закоммитьте их.
git add ci.md ci.test.js
git commit -m "Fix the bug in steps list"

# Опубликуйте ветку в удалённый репозиторий.
git push --set-upstream origin feature-fix

Створіть повний запит.

Створіть pull request під назвою Fixing the feature. встановіть feature-fix як "head branch", а master як "base branch".
Зачекайте, поки завершаться тести. Ви можете побачити статус тестів у нижній частині обговорення PR.

Переконайтеся, що ви встановили master в своєму форці репозиторію як "base branch", я не відповідатиму на запити на зміни в репозиторій з матеріалами курсу.

Затвердіть "Pull request "Fixing the feature"

Дякую за виправлення! Будь ласка, затвердіть зміни в master із pull request.

️ Завдання

  1. Натисніть кнопку "Merge pull request".
  2. Натисніть кнопку "Confirm merge".
  3. Натисніть "Delete branch", тому що вона нам більше не потрібна.

Це те, що у вас має бути на даний момент
Типові ситуації при безперервній інтеграції

Вітаю!

Ви виконали всі дії, які зазвичай зазвичай здійснюють у процесі безперервної інтеграції.

Якщо ви помітили будь-які проблеми з курсом або знаєте як його покращити, створіть issue в репозиторії з матеріалами курсу. Цей курс також має інтерактивна версія використовує GitHub Learning Lab як платформу.

Джерело: habr.com

Додати коментар або відгук