Git: Команда "git pull --rebase" простыми словами

Представьте, что вы и ваш коллега работаете над одной и той же веткой в Git. Коллега решил немного «прибраться» в истории коммитов, сделал это у себя локально и потом отправил изменения на сервер с помощью git push --force.
Вы же в это время продолжали работать со старой версией этой ветки.
Теперь вы хотите забрать обновления с сервера через git pull, но Git ругается и говорит: «Что-то тут не так, история у нас разная, я не знаю, как их объединить».
В этом посте я простыми словами объясню, что именно произошло, что значит эта ошибка и зачем в таких случаях использовать git pull --rebase
.
Что вообще случилось?
Когда ваш коллега переписал историю коммитов и сделал git push --force
это как будто он выкинул старую цепочку событий (которая была на сервере) и заменил её на новую (ту, тоторая сейчас у него локально). Git это заметил. А у вас на компьютере осталась старая история, и теперь Git видит две разные линии событий: одна у вас, другая - на сервере.к слову у нас в компании техлид запретил использовать
push --force
без согласования лично с ним, и это на мой взгляд правильное решение, чтобы избежать бардака. Но такие правила не везде...
Вы пытаетесь сделать
git pull
, чтобы обновить свою ветку. Но Git не знает, как правильно склеить вашу старую историю с новой. Поэтому он и выдаёт такое сообщение, например:
User + 538d044...84e43d3 feature_0981 -> origin/feature_0981 (forced update) hint: You have divergent branches and need to specify how to reconcile them. hint: You can do so by running one of the following commands sometime before hint: your next pull: hint: hint: git config pull.rebase false # merge (the default strategy) hint: git config pull.rebase true # rebase hint: git config pull.ff only # fast-forward only hint: hint: You can replace "git config" with "git config --global" to set a default hint: preference for all repositories. You can also pass --rebase, --no-rebase, hint: or --ff-only on the command line to override the configured default per hint: invocation.Говоря простым языком: «У вас с сервером разная история. Скажите мне, что делать: сливать, пересобирать или вообще не трогать?»
Какие есть варианты?
Git предлагает вам три пути:
1. Слияние (
merge
)Это поведение по умолчанию. Git просто добавит коммит слияния поверх всего, чтобы объединить две разные истории.
Как включить:
git config pull.rebase false
2. Переписать историю (
rebase
)Git возьмёт ваши локальные коммиты и как бы «переустановит» их поверх новых коммитов с сервера, как будто вы сделали их позже.
Как включить:
git config pull.rebase true
3. Только fast-forward
Работает только если ваша история полностью устарела, и можно просто «перемотать» её вперёд без конфликтов.
Как включить:
git config pull.ff only
Так что же делать в нашей ситуации?
Если коллега переписал историю и сделал
git push --force
, вы не сможете просто сделать git pull
без указания стратегии. Самый безопасный способ в этом случае - использовать --rebase
.Выглядит это так:
git pull --rebase origin feature_0981
где
feature_0981
- имя веткиЧто делает эта команда?
1. Git сначала подтянет свежую историю с сервера.
2. Потом временно «открепит» ваши локальные коммиты.
3. Потом применит их заново, как будто вы их сделали позже, чем коллега.
4. Вуаля - теперь у вас красивая линейная история, без лишних коммитов слияния и конфликтов (если всё прошло гладко, если нет - то придётся исправить конфликты).
Почему не стоит навсегда включать pull.rebase?
Можно было бы просто прописать (тем самым создать постоянную запись в настройках вашего Git):
git config --global pull.rebase true
...и забыть об этом. Но я не советую этого делать.
Почему?
Потому что бывают ситуации, когда
merge
- это именно то, что нужно. Например, если вы намеренно хотите видеть коммиты слияния, или работаете с ветками, где rebase
может запутать остальных участников.Поэтому лучше каждый раз осознанно выбирать нужную стратегию, добавляя флаг вручную:
--rebase
, --no-rebase
или --ff-only
.Вывод
Если вы получили странное сообщение при
git pull
после того, как кто-то сделал git push --force
, не паникуйте. Это обычная ситуация при Запомните простое правило:
git pull --rebase
- когда хотите «подстроить» свою историю под чужую (например ту, которая образовалась на сервере после того как кто-то сделал git push --force
), не создавая лишних слияний.Надеюсь, теперь команда
git pull --rebase
стала для вас понятной и больше не вызывает страха 
Если что - смело спрашивайте в комментариях!