git fetch и git pull: в чём разница и что выбрать
git fetch только скачивает новые коммиты с сервера и обновляет удалённые ветки вида origin/main, не трогая ваши файлы и ветки. git pull делает то же самое и сразу вливает изменения в текущую ветку через merge или rebase. Fetch безопасен всегда, pull удобен, когда вы готовы сразу принять чужие изменения.
Короткий ответ
git fetch скачивает с сервера новые коммиты и обновляет ссылки удалённых веток (origin/main, origin/feature-x), но не меняет ни вашу текущую ветку, ни файлы в рабочей папке. git pull — это git fetch плюс немедленное объединение скачанного с текущей веткой: через merge (по умолчанию) или через rebase.
Отсюда практическое правило: fetch можно запускать когда угодно, он ничего не ломает. Pull меняет вашу ветку и может закончиться конфликтом, поэтому его стоит запускать с чистой рабочей папкой и пониманием, что сейчас придёт.
Где живут удалённые ветки
Чтобы разница стала очевидной, нужно понять, что в локальном репозитории есть два вида веток. Локальные — main, feature-x — двигаете вы своими коммитами. Удалённые отслеживающие ветки — origin/main — это закладки «так выглядел сервер в момент последней синхронизации». Двигать их вручную нельзя, их обновляет только общение с сервером: fetch, pull и push.
git branch -a
* main
remotes/origin/HEAD -> origin/main
remotes/origin/main
remotes/origin/feature-x
git status сравнивает вашу ветку именно с закладкой origin/main, а не с живым сервером. Поэтому сообщение «Your branch is up to date with 'origin/main'» может врать: если вы давно не делали fetch, Git просто не знает о новых коммитах коллег.
Что делает git fetch
$ git fetch
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
Unpacking objects: 100% (4/4), done.
From github.com:team/project
3f2a1c9..8b7d4e2 main -> origin/main
Последняя строка говорит главное: ссылка origin/main передвинулась с 3f2a1c9 на 8b7d4e2. Ваша main осталась на месте. Теперь можно спокойно посмотреть, что пришло:
git status # Your branch is behind 'origin/main' by 2 commits
git log main..origin/main --oneline # коммиты, которых у вас нет
git diff main origin/main # что изменится в файлах
Полезные варианты fetch:
git fetch --all— забрать изменения из всех remote (актуально, если естьoriginиupstreamу форка);git fetch --prune(-p) — удалить локальные закладки веток, которых больше нет на сервере;git fetch origin main— забрать только одну ветку;git fetch --tags— дополнительно забрать все теги.
Чтобы прунинг работал всегда, включите его один раз: git config --global fetch.prune true.
Что делает git pull
git pull выполняет два шага подряд. Сначала fetch для upstream-ветки текущей ветки, затем объединение origin/<ветка> с вашей веткой. Буквально это равносильно:
git fetch origin
git merge origin/main # или git rebase origin/main при pull --rebase
Результат объединения зависит от того, как разошлись истории:
- у вас нет новых коммитов — происходит fast-forward, ветка просто перематывается вперёд;
- новые коммиты есть и у вас, и на сервере — при merge создаётся коммит слияния, при rebase ваши коммиты переставляются поверх серверных;
- одни и те же строки менялись с двух сторон — конфликт, который нужно разрешить вручную.
Сравнение git fetch и git pull
| git fetch | git pull | |
|---|---|---|
| Скачивает коммиты | Да | Да |
| Обновляет origin/* | Да | Да |
| Меняет текущую ветку | Нет | Да |
| Меняет файлы в рабочей папке | Нет | Да |
| Может вызвать конфликт | Нет | Да |
| Требует чистой рабочей папки | Нет | Желательно |
| Затрагивает другие ветки | Обновляет все отслеживаемые закладки | Вливает только в текущую |
| Когда использовать | Посмотреть, что изменилось; перед rebase; в скриптах | Быстро догнать сервер в своей ветке |
git pull: merge или rebase
С Git 2.27 при расхождении истории без явной настройки pull выводит предупреждение, а в новых версиях вместо молчаливого merge останавливается с ошибкой «Need to specify how to reconcile divergent branches». Git просит один раз выбрать стратегию:
git config --global pull.rebase false # merge (поведение по умолчанию раньше)
git config --global pull.rebase true # rebase
git config --global pull.ff only # только fast-forward, иначе отказ
Merge сохраняет историю как была и добавляет коммит «Merge branch 'main' of github.com:...». Если каждый день делать pull в ветку с локальными коммитами, история зарастает такими техническими слияниями.
Rebase переставляет ваши неотправленные коммиты поверх свежих серверных. История остаётся линейной, а конфликты разрешаются по одному коммиту за раз. Для неопубликованных локальных коммитов это обычно лучший выбор. Опасен rebase только для уже отправленных коммитов, на которых строят работу другие.
ff only — самый строгий режим: pull срабатывает лишь тогда, когда у вас нет своих коммитов. Если история разошлась, вы явно решаете, что делать. Многие опытные разработчики ставят именно его для основных веток.
Если в рабочей папке есть незакоммиченные правки, а pull нужен прямо сейчас, пригодится git pull --rebase --autostash: Git спрячет изменения, выполнит rebase и вернёт их обратно.
Типичный сценарий: fetch, посмотреть, влить
Подход «сначала fetch» даёт контроль над тем, что попадает в вашу ветку. Особенно он полезен перед отправкой pull request и после долгого перерыва.
git fetch
git log --oneline --graph HEAD origin/main # как разошлись ветки
git rebase origin/main # или git merge origin/main
git push
Ещё один частый случай — обновить свою feature-ветку свежим main, не переключаясь на него:
git switch feature-x
git fetch
git rebase origin/main
Здесь pull не подходит: git pull в feature-ветке подтянет изменения её собственного upstream (origin/feature-x), а не основной ветки. Можно, конечно, написать git pull --rebase origin main, но вариант с fetch нагляднее.
Синхронизация с сервером: как держать ветку в актуальном состоянии
Под запросом «git sync» обычно имеют в виду цикл «забрать чужое — отправить своё». В чистом Git отдельной команды sync нет (кнопка Sync есть в IDE и GUI-клиентах, и внутри она делает pull, затем push). Вручную надёжный цикл выглядит так:
git status— убедиться, что всё закоммичено или спрятано черезgit stash;git pull --rebase— забрать изменения и переставить свои коммиты наверх;- разрешить конфликты, если они есть: поправить файлы,
git add,git rebase --continue; - прогнать тесты;
git push.
Синхронизировать форк с исходным репозиторием можно так:
git remote add upstream https://github.com/original/project.git
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main
Частые проблемы с git pull
Your local changes would be overwritten by merge
Pull хочет изменить файлы, которые вы правите и не закоммитили. Варианты: закоммитить, спрятать (git stash, затем pull и git stash pop) или использовать --autostash. Удалять изменения ради pull не нужно.
Конфликт после pull
Git остановится и покажет файлы с конфликтом в git status. Откройте их, выберите нужный вариант между маркерами <<<<<<< и >>>>>>>, затем git add и git commit (при merge) или git rebase --continue (при rebase). Передумали — git merge --abort или git rebase --abort вернут всё как было до pull.
There is no tracking information for the current branch
У ветки не настроен upstream, и Git не знает, откуда тянуть. Укажите явно: git pull origin main, или настройте связь один раз: git branch --set-upstream-to=origin/main.
refusing to merge unrelated histories
Локальный и удалённый репозитории созданы независимо, например, на сервере при создании добавили README. Если вы уверены, что их нужно объединить: git pull origin main --allow-unrelated-histories.
Неудачный pull: как откатить
Если merge после pull уже завершён, а результат не устраивает, верните ветку в состояние до него: git reset --hard ORIG_HEAD. Команда удаляет незакоммиченные изменения, поэтому сначала проверьте git status. В крайнем случае прежнее положение ветки найдётся в git reflog.
Что выбрать
- Хотите узнать, что нового, ничего не меняя, —
git fetch. - Работаете в своей ветке и просто догоняете сервер —
git pull --rebase(или pull с настроеннымpull.rebase true). - Обновляете основную ветку без своих коммитов —
git pull --ff-only. - Нужно влить
mainв feature-ветку —git fetchи затемgit rebase origin/mainилиgit merge origin/main. - Пишете скрипт или CI — fetch и явные команды, без pull.
Как это выглядит на графе коммитов
Представьте, что вы и коллега начали с коммита C. Вы локально сделали коммит D, а коллега отправил на сервер E. После git fetch ваш репозиторий знает обе линии: main указывает на D, origin/main — на E, и у них общий предок C.
D <- main (HEAD)
/
A---B---C
\
E <- origin/main
Дальше всё решает способ объединения. git merge origin/main создаст коммит M с двумя родителями D и E. git rebase origin/main скопирует D поверх E как новый коммит D' с другим хешем, и история станет прямой линией. git pull просто выполняет эти же шаги автоматически, без паузы между ними. Именно эта пауза — возможность посмотреть на граф до объединения — и есть главная ценность отдельного fetch.
Fetch и pull в IDE
В VS Code, IntelliJ IDEA и других редакторах кнопки называются по-разному, но под ними те же команды. «Fetch» — это git fetch, «Pull» или «Update Project» — pull с выбранной в настройках стратегией (merge или rebase), «Sync Changes» — pull, а затем push. Перед тем как нажимать Sync в общей ветке, полезно знать, какая стратегия выбрана, иначе в истории неожиданно появятся коммиты слияния. Многие IDE также периодически делают fetch в фоне, поэтому счётчик входящих коммитов в строке состояния обычно актуален.
Итог
git fetch обновляет ваше знание о сервере, git pull ещё и применяет это знание к текущей ветке. Fetch безопасен в любой момент, pull удобен, но меняет ветку и может принести конфликт, поэтому один раз настройте его стратегию и держите рабочую папку чистой. Разница между push, pull и fetch, работа с remote и GitHub разобраны на практике в курсе по Git.
Частые вопросы
Нужно ли делать git fetch перед git pull?
Нет, pull сам выполняет fetch первым шагом. Отдельный fetch нужен, когда вы хотите сначала посмотреть изменения, а потом решить, как их вливать.
Может ли git fetch удалить мои изменения?
Нет. Fetch меняет только удалённые ссылки вида origin/main и не трогает локальные ветки, индекс и рабочую папку.
Обновляет ли git pull все ветки?
Нет, pull вливает изменения только в текущую ветку. Закладки origin/* для остальных веток обновятся благодаря fetch, но сами локальные ветки останутся на месте.
Как часто делать git fetch?
Перед началом работы, перед созданием pull request и перед push. Многие IDE делают fetch в фоне автоматически, это безопасно.
Что такое FETCH_HEAD?
Служебная ссылка, в которую fetch записывает последнее скачанное. Например, после git fetch origin main можно выполнить git merge FETCH_HEAD.
Эта тема подробно разобрана с практикой в курсе «Git с нуля до уверенного разработчика».
Перейти к курсу