---
title: 'Гігієна Git та монорепозиторії: атомарні комміти, ребейз та CI/CD мікросервісів'
description: 'Детальний посібник для розробників з гігієни Git, атомарних коммітів, угоди Conventional Commits, порівняння merge та rebase, інтерактивного ребейзу, монорепозиторіїв проти полірепозиторіїв та оптимізації CI/CD.'
faq:
    - { question: 'У чому головна перевага атомарних коммітів?', answer: "Атомарні комміти гарантують, що кожен комміт містить рівно одну логічну зміну та відповідні тести. Це спрощує код-рев'ю, зберігає історію зрозумілою, дозволяє легко відкочувати конкретні зміни та робить налагодження за допомогою таких інструментів, как 'git bisect', надзвичайно ефективним." }
    - { question: 'Коли слід використовувати merge, а коли rebase?', answer: "Використовуйте rebase на локальних приватних гілках для очищення історії, об'єднання проміжних WIP-коммітів та збереження лінійної структури перед інтеграцією. Використовуйте merge для злиття готових фіча-гілок у публічні спільні гілки (наприклад, main або develop), щоб зберегти фактичний хронологічний порядок та уникнути перезапису спільної історії." }
    - { question: 'Як уникнути запуску тестів для всіх сервісів у монорепозиторії при зміні лише одного сервісу?', answer: "Ви можете оптимізувати конвеєр CI, використовуючи фільтрацію за шляхами (наприклад, фільтр 'paths' у GitHub Actions або 'rules:changes' у GitLab CI), щоб воркфлоу запускався лише при зміні файлів у піддиректорії конкретного сервісу." }
published: '2026-06-15'
---
# Гігієна Git та монорепозиторії: атомарні комміти, ребейз та CI/CD мікросервісів

Уявіть картину: вечір п'ятниці, у продакшені критичний баг. Ви відкриваєте історію коммітів, щоб знайти регресію, але бачите лише нескінченну стіну повідомлень: «wip», «fix typo», «test», «hope this works» та заплутаний клубок із merge-коммітів. Пошук зміни, яка зламала код, перетворюється на пошук голки в стозі сіна. В іншому проекті розробник змінює один рядок у readme-файлі мікросервісу, і це запускає 40-хвилинний конвеєр CI/CD, який перезбирає та деплоїть заново всі двадцять мікросервісів системи. Ці проблеми — не дефекти технологій, а наслідок неефективної стратегії контролю версій та архітектури репозиторіїв.

Чисті стандарти коммітів та оптимізована конфігурація монорепозиторіїв критично важливі для побудови надійних, масштабованих та зручних процесів розробки в мікросервісній архітектурі.

## Зміст
* [Гігієна коммітів та сила атомарності](#git-hygiene)
* [Стратегії інтеграції: Merge проти Rebase](#merge-vs-rebase)
* [Просунута робота з Git: інтерактивний ребейз та Reflog](#advanced-git)
* [Структура мікросервісів: монорепозиторії проти полірепозиторіїв](#monorepo-vs-polyrepo)
* [Інструменти монорепозиторіїв для PHP та Laravel](#php-monorepos)
* [Оптимізація CI/CD конвеєрів у монорепозиторіях](#monorepo-ci)
* [Обмеження та компроміси](#limitations)
* [Практичні висновки](#takeaways)

---

<a id="git-hygiene"></a>
## Гігієна коммітів та сила атомарності

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

### Атомарні комміти
* **Теза**: Комміт має бути мінімально можливою логічною одиницею коду, яка завершена, працездатна та містить саму зміну разом із тестами.
* **Чому це важливо**: Атомарний комміт можна легко відкотити (revert) без ризику зламати інші фічі. Також це робить команду `git bisect` (пошук багів бінарним перебором історії) максимально ефективною.
* **Приклад**: Замість об'єднання рефакторингу, виправлення багу та оновлення залежностей в один гігантський комміт, розділіть їх на три окремі комміти.
* **Наслідки**: Код-рев'ю проходить швидше, історія змін залишається чистою, а відкати версій стають безболісними.

### Conventional Commits (Угода про комміти)
Для стандартизації повідомлень використовується специфікація **Conventional Commits**. Повідомлення будуються за шаблоном: `<type>(<scope>): <description>`.
* `feat`: Нова функціональність.
* `fix`: Виправлення багів.
* `chore`: Рутинні завдання, оновлення залежностей, конфігурація збірки.
* `docs`: Зміни в документації.
* `refactor`: Правки коду, що не виправляють баги та не додають фічі.
* `test`: Додавання або виправлення тестів.

---

<a id="merge-vs-rebase"></a>
## Стратегії інтеграції: Merge проти Rebase

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

```
Merge (Нелінійна історія):
A --- B --- C (main)
 \         /
  D --- E (feature)

Rebase (Лінійна історія):
A --- B --- C --- D' --- E' (main/feature)
```

### Git Merge
* **Теза**: Об'єднує гілки шляхом створення спеціального «merge-комміту», який має кількох батьків.
* **Чому это важливо**: Зберігає точну хронологію подій та відображає реальну історію того, коли гілки розходилися та зливалися.
* **Наслідки**: Історія стає нелінійною та перевантажується коммітами виду \"Merge branch 'main' into feature\", що ускладнює її читання.

### Git Rebase
* **Теза**: Переносить базовий комміт вашої фіча-гілки на найсвіжіший комміт цільової гілки, перебудовуючи ваші комміти поверх нього.
* **Чому це важливо**: Створює абсолютно лінійну історію, де всі зміни виглядають так, ніби вони розроблялися послідовно.
* **Наслідки**: Команда переписує хеші коммітів. Якщо зробити ребейз публічної спільної гілки, це викличе конфлікти у всіх інших розробників у команді. **Правило: Ніколи не робити rebase для спільних гілок.**

---

<a id="advanced-git"></a>
## Просунута робота з Git: інтерактивний ребейз та Reflog

Просунуті команди Git допомагають навести лад у коді локально перед тим, як ділитися ним з командою.

### Інтерактивний ребейз (`git rebase -i`)
* **Теза**: Дозволяє переписати, об'єднати, перевпорядкувати або видалити комміти в історії локальної гілки перед відправкою.
* **Чому це важливо**: Допомагає позбутися проміжних коммітів типу «wip» та «fix typo», представити чисту історію в пул-реквесті та зберегти атомарність.
* **Приклад**: Команда `git rebase -i HEAD~4` відкриє список з останніх 4 коммітів:
  ```text
  pick a1b2c3d feat(auth): add google oauth provider
  squash d4e5f6g wip oauth login
  squash h7i8j9k fix typo in redirect url
  reword l0m1n2o feat(auth): add docs for oauth integration
  ```
  Це об'єднає (squash) проміжні дрібні правки в основний комміт фічі та перепише фінальне повідомлення.

### Cherry-Picking (`git cherry-pick`)
* **Теза**: Переносить конкретний комміт з однієї гілки в поточну гілку.
* **Чому це важливо**: Корисно для швидкого перенесення хотфіксу багу в прод-гілку без злиття всієї фіча-гілки, що містить цей фікс.

### Git Reflog (`git reflog`)
* **Теза**: Локальний журнал, який записує абсолютно всі переміщення вказівників гілок, навіть якщо комміти були видалені або втрачені при ребейзі.
* **Чому це важливо**: Якщо ви припустилися помилки під час ребейзу і втратили код, `git reflog` покаже вихідний хеш комміту, який можна відновити командою `git reset --hard <hash>`.

---

<a id="monorepo-vs-polyrepo"></a>
## Структура мікросервісів: монорепозиторії проти полірепозиторіїв

При проектуванні мікросервісів постає питання організації репозиторіїв коду.

### Полірепозиторій (Polyrepo — репозиторій під кожен сервіс)
* **Теза**: Кожен мікросервіс живе у своєму ізольованому репозиторії.
* **Чому це важливо**: Чіткі межі відповідальності, невеликий розмір клонування коду та повністю ізольовані конвеєри CI/CD.
* **Наслідки**: Ускладнено спільний доступ до спільного коду (потрібна публікація пакетів), складно вносити наскрізні зміни, версії спільних залежностей швидко розсинхронізовуються.

### Монорепозиторій (Monorepo — один репозиторій для всього)
* **Теза**: Усі мікросервіси, бібліотеки та шлюзи живуть в одному спільному репозиторії.
* **Чому це важливо**: Простіть наскрізних правок, єдині версії бібліотек та миттєвий спільний доступ до коду без публікації зовнішніх пакетів.
* **Наслідки**: Величезний розмір репозиторію, складна настройка CI/CD та ризик розмиття меж, коли сервіси починають неявно зв'язуватися через спільні папки.

---

<a id="php-monorepos"></a>
## Інструменти монорепозиторіїв для PHP та Laravel

На відміну від JavaScript, де популярні Turborepo або Lerna, PHP-розробники можуть ефективно будувати монорепозиторії за допомогою вбудованих можливостей Composer.

### 1. Репозиторії шляхів Composer (Path Repositories)
Замість публікації спільних бібліотек у Packagist, ви можете посилатися на локальні папки через `path` репозиторії в `composer.json` мікросервісу:
```json
{
    "repositories": [
        {
            "type": "path",
            "url": "../packages/shared-dto",
            "options": {
                "symlink": true
            }
        }
    ],
    "require": {
        "devsense/shared-dto": "*"
    }
}
```
Composer створить символічне посилання на локальну бібліотеку. Це дозволяє змінювати спільний код та миттєво бачити зміни в мікросервісі без запуску `composer update`.

### 2. Monorepo Builder
Інструменти на кшталт **Monorepo Builder** допомагають об'єднувати конфігурації `composer.json`, автоматизувати семантичне версіонування підпакетів та синхронізувати версії зовнішніх залежностей у всіх сервісах.

---

<a id="monorepo-ci"></a>
## Оптимізація CI/CD конвеєрів у монорепозиторіях

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

* **Теза**: Запускаємо етапи CI/CD вибірково за допомогою фільтрації шляхів.
* **Чому це важливо**: Економить ресурси серверів та прискорює доставку коду.
* **Пример**: У GitHub Actions можна налаштувати запуск воркфлоу тільки при зміні файлів у конкретних папках:
  ```yaml
  # .github/workflows/user-service.yml
  on:
    push:
      branches: [ main ]
      paths:
        - 'services/user-service/**'
        - 'packages/shared-dto/**' # Запуск, якщо змінилися спільні залежності
  ```
* **Наслідки**: Тестується та збирається тільки змінений сервіс та його прямі залежності, що скорочує час CI з 30 до 2 хвилин.

---

<a id="code-demo"></a>
## Практичний приклад коду

Ось реальні конфігураційні шаблони для налаштування воркфлоу.

### 1. Процес інтерактивного ребейза в Git
Для очищення локальної історії перед відправкою гілки:
```bash
# 1. Запуск інтерактивного ребейза для останніх 3 коммітів
git rebase -i HEAD~3

# 2. У відкритому редакторі замініть 'pick' на 'squash' (або 's') для проміжних коммітів:
# pick 82a17f2 feat: add database indexing
# squash d928f01 fix syntax error in migration
# squash a19f291 add missing index fields

# 3. Збережіть зміни. Git запропонує відредагувати об'єднане повідомлення:
# feat: add database indexing and migrations
```

### 2. Налаштування вибіркового CI для монорепозиторію (GitHub Actions)
```yaml
# .github/workflows/checkout-service.yml
name: Checkout Service CI

on:
  push:
    branches: [ main, development ]
    paths:
      - 'services/checkout-service/**'
      - 'packages/shared-kernel/**'
  pull_request:
    branches: [ main, development ]
    paths:
      - 'services/checkout-service/**'
      - 'packages/shared-kernel/**'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.5'
          extensions: mbstring, xml, bcmath, pdo_pgsql

      - name: Install Dependencies
        run: |
          cd services/checkout-service
          composer install --no-interaction --prefer-dist --optimize-autoloader

      - name: Run Tests
        run: |
          cd services/checkout-service
          ./vendor/bin/phpunit
```

---

<a id="limitations"></a>
## Обмеження та компроміси

* **Небезпека ребейза**: Ребейз переписує історію коммітів. Форсована відправка (`git push --force`) відребейженої спільної гілки зітре комміти колег. Для безпеки завжди використовуйте `git push --force-with-lease`.
* **Масштаб монорепозиторію**: У міру зростання монорепозиторію команди `git status` та `git fetch` можуть сповільнюватися. Великі медіафайли необхідно зберігати через Git LFS (Large File Storage) або повністю виносити за межі Git.
* **Складність CI/CD**: Ручне управління залежностями шляхів у CI може призвести до багів, якщо зміна в бібліотеці не запустить тести в залежному мікросервісі. Для контролю графу збірки у великих проектах варто використовувати Turborepo або Nx.

---

<a id="takeaways"></a>
## Практичні висновки

1. **Пишіть атомарні комміти**: Одна логічна зміна — один комміт. Пишіть повідомлення в наказовому способі (наприклад, `feat(auth): add token verification`, а не `added verification`).
2. **Локально — Rebase, публічно — Merge**: Тримайте фіча-гілки лінійними через `git rebase`, але зливайте їх у спільні гілки через явні merge-комміти (`git merge --no-ff`) для збереження точок інтеграції.
3. **Використовуйте Path Repositories для PHP**: Зв'язуйте спільні пакети через символічні посилання для миттєвого тестування змін на локальній машині.
4. **Впроваджуйте фільтрацію шляхів у CI**: Запобігайте надлишковому запуску тестів, націлюючи пайплайни тільки на змінені папки.
5. **Використовуйте `git push --force-with-lease`**: Ніколи не робіть push наосліп, захищайте віддалену роботу колег від випадкового перезапису.