Пошук уроків, статей та іншого контенту
Розберете, як git pull поєднує отримання змін і їх інтеграцію, а також як розв’язувати конфлікти синхронізації.
git pullgit pull синхронізує поточну локальну гілку з віддаленим репозиторієм. Команда складається з двох логічних кроків:
git fetch — отримує нові коміти з віддаленого репозиторію.
Інтеграція отриманих змін у поточну гілку — зазвичай через merge, а іноді через rebase.
Базовий виклик:
git pullЗа замовчуванням Git використовує віддалений репозиторій і гілку, налаштовані для поточної локальної гілки.
Наприклад, якщо поточна гілка main відстежує origin/main, команда фактично працює приблизно так:
git fetch origin
git merge origin/mainВажливо: git pull змінює поточну локальну гілку, а git fetch лише отримує інформацію про зміни та оновлює віддалені посилання на кшталт origin/main.
Локальна гілка може бути пов’язана з віддаленою гілкою. Таку віддалену гілку називають upstream-гілкою.
Переглянути поточну гілку та її зв’язок із віддаленим репозиторієм можна так:
git branch -vvПриклад результату:
* main a1b2c3d [origin/main] Оновлено документаціюЗапис [origin/main] означає, що локальна main відстежує origin/main.
Якщо upstream ще не налаштовано, Git може попросити явно вказати віддалений репозиторій і гілку:
git pull origin mainПід час першого надсилання нової локальної гілки upstream можна налаштувати командою:
git push -u origin feature/loginПісля цього для наступних синхронізацій у гілці feature/login достатньо виконувати:
git pull
git pushЯкщо локальна гілка не має власних нових комітів, а у віддаленій гілці з’явилися коміти, Git може просто перемістити вказівник локальної гілки вперед.
До синхронізації:
A---B main
\
C---D origin/mainПісля git pull:
A---B---C---D main, origin/mainНовий коміт злиття не створюється. Такий варіант називається fast-forward.
Якщо локальна й віддалена гілки мають незалежні коміти, Git не може просто перемістити вказівник. За стандартного режиму він створює merge-коміт.
До синхронізації:
C локальний main
/
A---B
\
D origin/mainПісля git pull із merge:
C
/ \
A---B---M main
\ /
DКоміт M поєднує локальну та віддалену історію.
Замість merge Git може перенести локальні коміти поверх нової версії віддаленої гілки:
git pull --rebaseДо синхронізації:
C локальний main
/
A---B
\
D origin/mainПісля rebase:
A---B---D---C' mainКоміт C замінюється на новий коміт C', оскільки його батьком стає D.
Rebase часто зберігає лінійну історію, але змінює ідентифікатори локальних комітів. Не слід без потреби робити rebase комітів, які вже опубліковані та використовуються іншими розробниками.
Режим можна вказати для одного виклику:
git pull --rebase origin mainАбо налаштувати для поточного репозиторію:
git config pull.rebase trueЯкщо потрібно дозволити лише fast-forward і не створювати автоматичні merge-коміти, використовуйте:
git pull --ff-onlyКоманда завершиться з помилкою, якщо локальна й віддалена історії розійшлися. Це дає змогу спочатку самостійно вирішити, як саме інтегрувати зміни.
Перед git pull корисно перевірити стан робочого дерева:
git statusЯкщо є незбережені зміни, Git може відмовитися виконувати pull, щоб не перезаписати їх. Залежно від ситуації зміни потрібно:
закомітити;
тимчасово відкласти через git stash;
видалити, якщо вони більше не потрібні.
Нехай ви працюєте в локальній гілці main, яка відстежує origin/main.
# Перевірити поточну гілку та стан робочого дерева
git status
# Отримати зміни та інтегрувати їх у поточну гілку
git pull
# Перевірити нову історію комітів
git log --oneline --decorate --graph -5Якщо локальна гілка має власні коміти, а віддалена — нові коміти колег, можна явно обрати стратегію:
# Інтегрувати зміни через merge
git pull --no-rebase
# Інтегрувати зміни через rebase
git pull --rebaseКонфлікт виникає, коли Git не може автоматично поєднати зміни. Наприклад, локальний і віддалений коміти змінили той самий фрагмент одного файлу.
Після невдалого злиття git pull покаже повідомлення про конфлікт. Перевірити конфліктні файли можна так:
git statusУ файлі з конфліктом з’являються спеціальні маркери:
function getGreeting() {
<<<<<<< HEAD
return "Привіт!";
=======
return "Вітаю!";
>>>>>>> origin/main
}Маркери означають:
<<<<<<< HEAD — зміни з поточної локальної гілки;
======= — роздільник між варіантами;
>>>>>>> origin/main — зміни, отримані з віддаленої гілки.
Потрібно вручну залишити правильний варіант або об’єднати обидва варіанти, а потім видалити всі маркери:
function getGreeting() {
return "Вітаю!";
}Після виправлення потрібно додати файл до індексу:
git add src/greeting.jsДля merge після цього потрібно завершити злиття:
git commitGit запропонує повідомлення для merge-коміту. Його можна залишити або відредагувати.
Повна послідовність розв’язання конфлікту під час merge:
git pull
# Після повідомлення про конфлікт
git status
# Виправити конфліктні файли в редакторі
git add src/greeting.js
# Завершити merge
git commitЯкщо під час розв’язання конфлікту стало зрозуміло, що злиття потрібно скасувати, виконайте:
git merge --abortКоманда поверне поточну гілку до стану, у якому вона була до початку merge.
Це працює, якщо процес merge ще не завершено. Після скасування можна перевірити стан репозиторію:
git statusgit pull --rebaseПід час rebase конфлікт розв’язується схожим способом, але завершення виконується іншими командами.
git pull --rebase
# Перевірити конфліктні файли
git status
# Виправити файли та додати їх
git add src/greeting.js
# Продовжити rebase
git rebase --continueЯкщо конфлікти виникають у кількох комітах, Git може зупинятися після кожного з них. Після виправлення чергового конфлікту потрібно знову виконати:
git add <виправлений-файл>
git rebase --continueСкасувати весь процес rebase можна так:
git rebase --abortПісля цього локальна гілка повернеться до стану перед початком rebase.
Після успішного pull перевірте:
git status
git log --oneline --decorate --graph -10Якщо локальна гілка синхронізована з віддаленою, git status зазвичай повідомить, що вона відповідає upstream-гілці.
Якщо після merge залишилися незакомічені зміни або конфліктні файли, синхронізація ще не завершена.
Перед початком роботи можна оновити гілку:
git switch main
git pull --ff-onlyСтворити робочу гілку від актуального стану main:
git switch -c feature/profileПісля роботи та створення локальних комітів перед публікацією гілки можна отримати нові зміни з її upstream-гілки:
git pull --rebaseЯкщо виник конфлікт:
git status
# Виправити файли
git add .
git rebase --continueПісля успішної інтеграції перевірити історію та опублікувати зміни:
git log --oneline --decorate --graph -10
git pushgit pull із незбереженими змінамиGit може зупинити операцію, якщо локальні зміни конфліктують із тими, що надходять із сервера.
Спочатку перевірте стан:
git statusЯкщо зміни потрібно зберегти, створіть коміт або тимчасово відкладіть їх. Не варто бездумно використовувати команди, які видаляють локальні зміни.
Після конфлікту не можна просто продовжувати роботу й очікувати, що Git завершить pull автоматично. Потрібно:
знайти конфліктні файли;
виправити маркери конфлікту;
виконати git add;
завершити merge або продовжити rebase.
git add . без перевіркиКоманда git add . може додати не лише виправлені конфліктні файли, а й інші небажані зміни. Надійніше спочатку переглянути стан:
git statusПотім додати конкретні файли:
git add src/greeting.jsgit pull --rebase може змінити локальні коміти. Не використовуйте rebase без розуміння того, чи були ці коміти вже опубліковані та чи працюють із ними інші розробники.
fetch і pullgit fetch не змінює поточну гілку. Він лише отримує нові об’єкти та оновлює посилання на віддалені гілки.
git pull після отримання змін одразу намагається інтегрувати їх у поточну гілку. Тому pull може створити merge-коміт або зупинитися через конфлікт.
git pull поєднує git fetch та інтеграцію змін.
Стандартна інтеграція зазвичай виконується через merge.
git pull --rebase переносить локальні коміти поверх оновленої віддаленої гілки.
git pull --ff-only дозволяє виконувати лише безпечне fast-forward-оновлення.
Під час конфлікту потрібно вручну відредагувати файли та видалити маркери конфлікту.
Після merge використовується git add і git commit.
Після rebase використовується git add і git rebase --continue.
Скасування merge виконується через git merge --abort, а скасування rebase — через git rebase --abort.
Перед pull варто перевіряти стан робочого дерева командою git status.