Сравнение

git fetch и git pull: в чём разница и что выбрать

Обновлено: · Skillaria.Top

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 fetchgit 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). Вручную надёжный цикл выглядит так:

  1. git status — убедиться, что всё закоммичено или спрятано через git stash;
  2. git pull --rebase — забрать изменения и переставить свои коммиты наверх;
  3. разрешить конфликты, если они есть: поправить файлы, git add, git rebase --continue;
  4. прогнать тесты;
  5. 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 с нуля до уверенного разработчика».

Перейти к курсу