Пошук уроків, статей та іншого контенту
Пройдете повний сценарій оновлення feature-гілки, очищення її історії та підготовки до інтеграції.
Feature-гілка часто розвивається кілька днів або тижнів. За цей час у цільовій гілці з’являються нові зміни, а сама feature-гілка може накопичити:
багато дрібних технічних комітів;
коміти з неінформативними повідомленнями;
виправлення попередніх комітів;
конфлікти з актуальним станом main;
зміни, які вже не потрібні.
Перед інтеграцією таку гілку варто оновити, очистити її історію та перевірити, що вона готова до merge або створення pull request.
У цьому сценарії використовується:
main — цільова гілка;
feature/payment-validation — робоча гілка;
origin — віддалений репозиторій.
Перед будь-якою перебудовою історії переконайтеся, що робоче дерево чисте:
git statusОчікуваний результат:
On branch feature/payment-validation
nothing to commit, working tree cleanЯкщо є незбережені зміни, їх потрібно або закомітити, або тимчасово сховати:
git stash push -u -m "Тимчасові зміни перед оновленням гілки"Працювати з незбереженими змінами під час rebase не варто: це ускладнює розв’язання конфліктів і підвищує ризик випадково втратити частину роботи.
Спочатку оновіть локальні remote-tracking гілки:
git fetch originЦя команда не змінює поточну локальну гілку. Вона лише оновлює посилання на стан віддалених гілок, зокрема origin/main.
Перевірте, наскільки feature-гілка відстає або випереджає main:
git log --oneline --graph --decorate --all --max-count=30Для точнішої перевірки:
git rev-list --left-right --count origin/main...HEADНаприклад:
5 7У цьому результаті:
5 — кількість комітів, яких немає у feature-гілці, але вони є в origin/main;
7 — кількість комітів feature-гілки, яких немає в origin/main.
Отже, гілка одночасно відстає від main на 5 комітів і містить 7 власних комітів.
Очищення історії за допомогою rebase змінює ідентифікатори комітів. Перед цим корисно створити локальну резервну гілку:
git branch backup/payment-validation-before-rebaseТепер попередній стан можна буде переглянути або відновити:
git show backup/payment-validation-before-rebaseРезервна гілка не змінюється під час подальшого rebase, тому вона зберігає стару історію.
Переконайтеся, що перебуваєте у правильній гілці:
git switch feature/payment-validationПісля цього перенесіть її коміти поверх актуального origin/main:
git rebase origin/mainGit знайде коміти, які належать feature-гілці, тимчасово зніме їх, перемістить базу на вершину origin/main, а потім застосує ці коміти послідовно.
Успішний результат виглядає приблизно так:
Successfully rebased and updated refs/heads/feature/payment-validation.Після успішного rebase історія стає лінійною:
origin/main ── A ── B ── C
\
feature/payment-validation D' ── E' ── F'Символи D', E', F' позначають нові коміти. Навіть якщо зміст коміту не змінився, його SHA-ідентифікатор змінюється, оскільки змінилася батьківська база.
Якщо Git не може автоматично застосувати один із комітів, rebase зупиняється:
CONFLICT (content): Merge conflict in src/validation.js
error: could not apply 4f2a91c Add payment validationПеревірте список конфліктних файлів:
git statusВідкрийте кожен файл і вручну залиште правильний варіант. Конфлікт позначається спеціальними маркерами:
<<<<<<< HEAD
const limit = 1000;
=======
const limit = 5000;
>>>>>>> 4f2a91c (Add payment validation)Після редагування у файлі не повинно залишитися маркерів <<<<<<<, ======= або >>>>>>>.
Позначте файл як розв’язаний:
git add src/validation.jsПродовжте перебудову:
git rebase --continueЯкщо конфлікт виникне в наступному коміті, повторіть ті самі кроки.
Якщо стало зрозуміло, що поточний коміт більше не потрібен або його зміст уже присутній у main, можна пропустити його:
git rebase --skipЦю команду використовуйте лише після перевірки змісту коміту. Пропущений коміт буде вилучено з поточної послідовності rebase.
Щоб повністю скасувати поточну операцію:
git rebase --abortПісля цього гілка повернеться до стану, який був до початку rebase.
Після оновлення бази перегляньте список комітів feature-гілки:
git log --oneline origin/main..HEADНаприклад:
91ab320 Fix typo in validation message
5c31a8e Add validation tests
a17b4f2 Add payment validation
0c86f11 Start payment validationЧотири коміти можуть бути корисними під час розробки, але для інтеграції логічніше залишити один або два змістовні коміти.
Запустіть інтерактивний rebase відносно актуальної бази:
git rebase -i origin/mainGit відкриє список на кшталт:
pick 0c86f11 Start payment validation
pick a17b4f2 Add payment validation
pick 5c31a8e Add validation tests
pick 91ab320 Fix typo in validation messageКоміти виконуються зверху вниз. Для очищення історії можна змінити список так:
pick 0c86f11 Start payment validation
squash a17b4f2 Add payment validation
squash 5c31a8e Add validation tests
fixup 91ab320 Fix typo in validation messageКоманди мають таке призначення:
pick — залишити коміт без змін;
reword — залишити зміни, але змінити повідомлення;
edit — зупинитися на коміті для додаткового редагування;
squash — об’єднати коміт із попереднім і відредагувати спільне повідомлення;
fixup — об’єднати коміт із попереднім і відкинути його повідомлення;
drop — вилучити коміт разом із його змінами.
Після збереження списку Git може відкрити редактор для нового повідомлення об’єднаного коміту. Залиште, наприклад:
Add payment validation
Add validation rules and tests for payment limits.Не варто залишати в інтеграційній історії повідомлення на кшталт:
fix;
oops;
try again;
changes;
debug.
Повідомлення має пояснювати завершений результат, а не проміжний стан роботи.
Якщо перед очищенням було створено резервну гілку, можна порівняти стару й нову послідовність комітів:
git range-diff \
origin/main...backup/payment-validation-before-rebase \
origin/main...feature/payment-validationrange-diff порівнює не лише кінцевий стан файлів, а й послідовності комітів. Це дає змогу перевірити, що під час очищення:
не зникла важлива зміна;
коміти були об’єднані очікуваним чином;
порядок логічних змін залишився правильним;
випадковий коміт не потрапив до feature-гілки.
Також перегляньте підсумкову історію:
git log --oneline --decorate --graph origin/main..HEADІ перевірте фактичний diff відносно цільової гілки:
git diff --stat origin/main...HEAD
git diff --check origin/main...HEADКоманда git diff --check виявляє типові проблеми форматування, наприклад зайві пробіли в кінці рядків.
Перед публікацією оновленої гілки потрібно перевірити не тільки Git-історію, а й сам результат роботи.
Мінімальний сценарій перевірки:
git status
git diff --check origin/main...HEAD
git diff --stat origin/main...HEAD
git log --oneline origin/main..HEADПісля цього запустіть проєктні перевірки. Наприклад, для Node.js-проєкту:
npm test
npm run buildКонкретні команди залежать від проєкту. Важливо, щоб перевірки виконувалися вже після rebase, адже оновлення бази могло змінити результат роботи коду.
Переконайтеся, що:
у робочому дереві немає випадкових змін;
у diff немає файлів, не пов’язаних із задачею;
конфлікти повністю розв’язані;
тести та збірка проходять;
коміти мають зрозумілі повідомлення;
feature-гілка базується на актуальному origin/main.
Якщо feature-гілка вже була опублікована, звичайний git push після rebase буде відхилений:
! [rejected] feature/payment-validation -> feature/payment-validation (non-fast-forward)Причина полягає в тому, що локальна гілка тепер містить інші SHA-ідентифікатори комітів.
Для безпечного оновлення віддаленої гілки використовуйте:
git push --force-with-lease origin feature/payment-validation--force-with-lease перевіряє, що віддалена гілка все ще має очікуваний стан. Якщо хтось інший встиг опублікувати нові коміти, команда відмовиться перезаписувати їх.
Не використовуйте без крайньої потреби:
git push --forceЗвичайний --force може без перевірки видалити чужі коміти з віддаленої гілки.
Після push ще раз перевірте стан:
git status
git log --oneline --decorate --graph -n 15Якщо гілку використовують кілька розробників, переписування її історії потрібно узгодити заздалегідь. Після rebase інші локальні клони можуть містити стару історію, і їм доведеться окремо синхронізуватися.
Нижче наведено компактну послідовність команд для вже існуючої feature-гілки:
# Перевіряємо, що робоче дерево чисте
git status
# Отримуємо актуальні посилання на віддалені гілки
git fetch origin
# Перемикаємося на feature-гілку
git switch feature/payment-validation
# Створюємо резервну копію старої історії
git branch backup/payment-validation-before-rebase
# Переносимо коміти поверх актуального main
git rebase origin/main
# Очищуємо історію інтерактивно
git rebase -i origin/main
# Перевіряємо різницю між старою та новою послідовністю комітів
git range-diff \
origin/main...backup/payment-validation-before-rebase \
origin/main...feature/payment-validation
# Перевіряємо стан, форматування та diff
git status
git diff --check origin/main...HEAD
git diff --stat origin/main...HEAD
# Переглядаємо підсумкову історію
git log --oneline --decorate --graph origin/main..HEAD
# Запускаємо перевірки проєкту
npm test
npm run build
# Публікуємо переписану історію безпечним способом
git push --force-with-lease origin feature/payment-validationЯкщо під час rebase виник конфлікт, послідовність змінюється:
# Переглядаємо конфліктні файли
git status
# Після ручного виправлення додаємо розв’язаний файл
git add path/to/conflicted-file
# Продовжуємо rebase
git rebase --continuegit pull без розуміння стратегіїКоманда git pull може виконати merge або rebase залежно від конфігурації Git. У сценарії підготовки feature-гілки краще явно розділяти операції:
git fetch origin
git rebase origin/mainТак зрозуміло, яку саме віддалену гілку використано як базу.
rebase переписує історію. Якщо кілька людей активно пушать у ту саму feature-гілку, після цього вони отримають розбіжність історій.
Перед переписуванням спільної гілки потрібно:
узгодити операцію з командою;
переконатися, що всі останні коміти отримано через git fetch;
після rebase використовувати --force-with-lease;
повідомити інших учасників про нову базу гілки.
--force замість --force-with-lease--force не перевіряє, чи з’явилися нові коміти на сервері. Це може знищити роботу іншого розробника.
Для особистої feature-гілки після локального rebase майже завжди потрібен саме:
git push --force-with-leaseУспішний rebase не гарантує, що результат правильний. Під час конфлікту можна випадково залишити не той варіант коду або втратити частину змін.
Після очищення обов’язково перевірте:
git diff origin/main...HEAD
git diff --check origin/main...HEADІ запустіть тести.
dropКоманда drop вилучає коміт із поточної історії. Якщо коміт містить важливу зміну, вона може зникнути з feature-гілки.
Перед drop перевірте зміст коміту:
git show COMMIT_SHAБез резервної гілки відновлення старої послідовності комітів складніше. Перед великим інтерактивним rebase створюйте тимчасове посилання:
git branch backup/feature-before-rebaseПісля успішної інтеграції його можна видалити:
git branch -d backup/feature-before-rebaseПідготовка feature-гілки до інтеграції складається з послідовних кроків:
перевірити чистоту робочого дерева;
отримати актуальний стан через git fetch;
створити резервну копію історії;
виконати git rebase origin/main;
розв’язати конфлікти та продовжити rebase;
очистити історію через git rebase -i;
перевірити зміни за допомогою git diff, git log і git range-diff;
запустити тести та збірку;
опублікувати переписану гілку через git push --force-with-lease.
У результаті feature-гілка містить актуальні зміни цільової гілки, має зрозумілу історію та готова до безпечної інтеграції.