Что делает rebase
Git rebase (по-русски — перебазирование) — это команда, которая переносит коммиты вашей ветки на новый конец другой ветки, обычно main, как будто вы начали работу позже. Вы начнёте тёмную тему сайта в ветке feature/dark-theme, перенесёте её на обновлённый main, решите конфликт по ходу и узнаете золотое правило rebase.
Когда вы работали вдвоём, отставшую ветку обновляли слиянием main, и каждое обновление добавляло merge-коммит. Rebase даёт второй способ догнать main: история остаётся прямой линией.
Простыми словами
Вы пишете главу общей книги по черновику недельной давности, а соавтор за неделю дописал перед ней ещё одну. Можно приложить свою главу с пометкой «объединено» — это merge. А можно переписать её поверх свежего черновика, будто начали сегодня, — это rebase.
D---E---F feature/dark-theme
/
A---B---G main
Что на схеме: ветка отошла от B, в ней три коммита D, E, F, а в main тем временем появился коммит коллеги G.
D'--E'--F' feature/dark-theme
/
A---B---G main
Что на схеме: ветка начинается от G. D', E', F' — копии ваших коммитов: изменения те же, хеши новые (сменился родитель).
Официальный термин
База ветки (base) — коммит, от которого она отходит; re-base — «сменить базу». git rebase main откладывает коммиты вашей ветки, ставит её на последний коммит main и применяет изменения заново по одному. Сам main не меняется.
Частая путаница: rebase не «склеивает» ветки
После rebase ваши коммиты ещё не в main: ветка лишь стала его продолжением. В main они попадут, как и раньше, через pull request.
Коммиты только своей ветки показывает запись с двумя точками: git log --oneline main..feature/dark-theme — «что есть в feature/dark-theme, но нет в main».
Rebase на практике
В ветке feature/dark-theme три коммита с тёмной темой в style.css. Тем временем коллега влил в main pull request «Оформить ссылки»: он переписал правило a { color: #3b82f6; } в конце style.css, после которого вы дописали тему. Обновляем main и переносим ветку:
$ git switch main
$ git pull
$ git switch feature/dark-theme
$ git rebase main
Auto-merging style.css
CONFLICT (content): Merge conflict in style.css
error: could not apply 778017a... wip тёмная тема
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Could not apply 778017a... wip тёмная тема
Разбор по строкам
CONFLICT (content): Merge conflict in style.css— обе стороны поменяли конец файла: коллега — правило ссылок, вы — дописали тему сразу после него.error: could not apply 778017a... wip тёмная тема— «не могу применить коммит 778017a»: rebase остановился на первом из трёх коммитов.hint: ... git rebase --continue— решите конфликт, отметьте файл черезgit addи продолжите.hint: ... git rebase --skip— пропустить коммит (его изменения пропадут).hint: ... git rebase --abort— отменить всё и вернуться к состоянию до rebase.
Решается такой конфликт так же, как конфликт слияния. В конце style.css маркеры:
<<<<<<< HEAD
a {
color: #2563eb;
=======
a { color: #3b82f6; }
@media (prefers-color-scheme: dark) {
body {
color: #e5e5e5;
backround: #18181b;
}
>>>>>>> 778017a (wip тёмная тема)
}
Частая путаница: при rebase HEAD — это не ваша ветка
При слиянии сверху была ваша ветка. При rebase наоборот: сверху (HEAD) — main с новым правилом коллеги, снизу — ваш переносимый коммит.
Сверху берём новое правило ссылок, снизу — только блок @media: старую строку a { color: #3b82f6; } коллега уже заменил. Уберите её и маркеры (опечатку backround исправит ваш третий коммит):
a {
color: #2563eb;
}
@media (prefers-color-scheme: dark) {
body {
color: #e5e5e5;
backround: #18181b;
}
}
Отметьте конфликт решённым и продолжите. Git откроет редактор с сообщением коммита — сохраните его без изменений и закройте:
$ git add style.css
$ git rebase --continue
[detached HEAD 1114e95] wip тёмная тема
1 file changed, 6 insertions(+)
Successfully rebased and updated refs/heads/feature/dark-theme.
Разбор по строкам
[detached HEAD 1114e95] wip тёмная тема— копия первого коммита с новым хешем;detached HEADна время rebase — нормально.Successfully rebased and updated refs/heads/feature/dark-theme.— остальные два коммита применились сами.
$ git log --oneline -5
02bf7d8 поправил
1353688 wip ещё цвета
1114e95 wip тёмная тема
816852b Merge pull request #7 from alex-ivanov/feature/colleague-links
60a9824 Оформить ссылки
Ваши коммиты стоят над слиянием коллеги, без развилки и merge-коммита. Если конфликтуют несколько коммитов, цикл «решить — git add — git rebase --continue» повторяется.
Merge или rebase
Оба способа соединяют вашу работу со свежим main, по-разному обращаясь с историей.
| merge | rebase | |
|---|---|---|
| История | Развилки и merge-коммиты, видно, как шла работа | Прямая линия, будто работали по очереди |
| Ваши коммиты | Остаются как были, хеши те же | Заменяются копиями с новыми хешами |
| Конфликты | Решаются один раз, в merge-коммите | Могут встретиться на каждом переносимом коммите |
| Для веток, которые взяли другие | Безопасно | Опасно: у других останутся старые коммиты |
| Когда брать | Влить готовую ветку в main, обновить общую ветку | Догнать main в своей ветке перед pull request |
Золотое правило rebase
Не перебазируйте коммиты, которые уже забрали другие. Rebase заменяет коммиты копиями: если коллега скачал вашу ветку и закоммитил поверх, у него останутся старые оригиналы, и при следующем git pull появятся дубли и конфликты на ровном месте.
Проще говоря: перебазируйте только свою ветку, в которую никто, кроме вас, не коммитит. feature/dark-theme можно: другие её только читают в pull request. main — никогда; её бережёт и ruleset (пункт Block force pushes включён по умолчанию), а на ваши ветки он не действует.
Push после rebase
Ветка feature/dark-theme уже была на GitHub — вы отправляли её до rebase:
$ git status
On branch feature/dark-theme
Your branch and 'origin/feature/dark-theme' have diverged,
and have 5 and 3 different commits each, respectively.
(use "git pull" if you want to integrate the remote branch with yours)
Разбор по строкам
have diverged— ваша ветка и её копия на GitHub разошлись.have 5 and 3 different commits each— у вас 5 коммитов, которых нет на GitHub (три копии и два коммита коллеги изmain), там — 3 старых оригинала.(use "git pull" ...)— после rebase этому совету не следуйте: pull вольёт старые оригиналы обратно.
Обычный push не пройдёт:
$ git push
To https://github.com/alex-ivanov/portfolio.git
! [rejected] feature/dark-theme -> feature/dark-theme (non-fast-forward)
error: failed to push some refs to 'https://github.com/alex-ivanov/portfolio.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
...
GitHub отказывает: отправка выкинула бы три его коммита. А мы как раз хотим заменить их копиями — для этого есть принудительная отправка с проверкой:
$ git push --force-with-lease
To https://github.com/alex-ivanov/portfolio.git
+ 011e648...02bf7d8 feature/dark-theme -> feature/dark-theme (forced update)
Разбор по строкам
+ 011e648...02bf7d8 ... (forced update)— ветка на GitHub принудительно переставлена со старого коммита на новый.
--force-with-lease — «силой, но с проверкой»: Git заменит ветку на GitHub, только если она там такая же, какой вы видели её в последний раз. Если туда успел прийти чужой коммит, Git откажет:
! [rejected] feature/dark-theme -> feature/dark-theme (stale info)
stale info — «устаревшие сведения». Выполните git fetch, заберите чужой коммит к себе и только потом отправляйте.
git push --force без lease стирает чужую работу
В старых ответах советуют git push --force (-f). Он ничего не проверяет, и чужой коммит молча пропадёт. Пользуйтесь --force-with-lease и только для своей ветки pull request, никогда для main.
Подробно — в документации: git rebase, git push.
Cherry-pick — перенести один коммит
Проверяя тему в браузере, вы щёлкаете «Все мои проекты» и видите «страница не найдена»: в адресе project.html вместо projects.html. Вы чините это в своей ветке, но тема будет готова через пару дней, а в main исправление нужно сейчас.
Простыми словами: из черновиков переписать в чистовик одну готовую страницу. Официально — cherry-pick («собирать вишенки»): git cherry-pick <хеш> создаёт копию одного коммита поверх текущей ветки. Rebase, по сути, делает то же самое с каждым вашим коммитом по очереди.
$ git log --oneline -1
852019c Исправить ссылку на проекты
$ git switch main
$ git switch -c fix/projects-link
$ git cherry-pick 852019c
[fix/projects-link 1bf90b5] Исправить ссылку на проекты
Date: Mon Nov 16 15:00:00 2026 +0300
1 file changed, 1 insertion(+), 1 deletion(-)
Разбор по строкам
[fix/projects-link 1bf90b5] ...— копия в веткеfix/projects-link: хеш новый, сообщение прежнее.Date: Mon Nov 16 15:00:00 2026 +0300— дата автора взята из оригинала.
Дальше push, pull request, слияние — и исправление на сайте раньше темы. Кто сломал ссылку, выясним, когда научимся искать по истории.
git pull --rebase
git pull --rebase скачивает новые коммиты и ставит ваши неотправленные поверх них вместо merge-коммита. У вас в настройках pull.rebase false — для начала хороший выбор, а --rebase указывайте явно, когда нужно.
Практика у себя
Работаем в ~/projects/portfolio. Сообщения первых коммитов плохие нарочно — причешем их в следующем уроке.
Шаг 1. Обновите main и создайте ветку:
$ git switch main
$ git pull
$ git switch -c feature/dark-theme
Switched to a new branch 'feature/dark-theme'
Шаг 2. Допишите в конец style.css блок, который включается при тёмной теме в системе. Опечатку backround оставьте:
@media (prefers-color-scheme: dark) {
body {
color: #e5e5e5;
backround: #18181b;
}
}
$ git add style.css
$ git commit -m "wip тёмная тема"
Шаг 3. Внутри @media после правила body добавьте цвет подзаголовка и закоммитьте как wip ещё цвета:
.lead {
color: #a1a1aa;
}
Шаг 4. Исправьте backround на background, закоммитьте как поправил и отправьте ветку: git push -u origin feature/dark-theme. Проверка:
$ git log --oneline main..feature/dark-theme
011e648 поправил
fed9cf6 wip ещё цвета
778017a wip тёмная тема
Шаг 5. За коллегу. Во втором клоне сделайте изменение, которое уйдёт в main раньше вашего. Опечатку в адресе повторите нарочно — это учебная поломка:
$ cd ~/projects/portfolio-colleague
$ git switch main
$ git pull
$ git switch -c feature/colleague-links
В конце style.css замените строку a { color: #3b82f6; } правилом ниже (синий темнее, запись в несколько строк, как у остальных правил), а в index.html замените строку со ссылкой <p><a href="projects.html">Все проекты</a></p> на <p><a href="project.html">Все мои проекты</a></p>.
a {
color: #2563eb;
}
Закоммитьте оба файла как Оформить ссылки, выполните git push -u origin feature/colleague-links, создайте pull request и слейте его.
Шаг 6. В своей папке обновите main и перебазируйте ветку:
$ cd ~/projects/portfolio
$ git switch main
$ git pull
$ git switch feature/dark-theme
$ git rebase main
...
CONFLICT (content): Merge conflict in style.css
error: could not apply 778017a... wip тёмная тема
Решите конфликт, как в разборе выше, затем git add style.css и git rebase --continue до строки Successfully rebased.
Шаг 7. Выполните git push --force-with-lease — в выводе (forced update).
Шаг 8. Откройте index.html в браузере и щёлкните «Все мои проекты» — страница не найдена. Исправьте project.html на projects.html и закоммитьте:
$ git add index.html
$ git commit -m "Исправить ссылку на проекты"
[feature/dark-theme 852019c] Исправить ссылку на проекты
1 file changed, 1 insertion(+), 1 deletion(-)
Шаг 9. Перенесите исправление в отдельную ветку (хеш — свой из шага 8):
$ git switch main
$ git switch -c fix/projects-link
$ git cherry-pick 852019c
$ git push -u origin fix/projects-link
Создайте pull request из fix/projects-link (у нас это #8), слейте его, затем у себя:
$ git switch main
$ git pull
$ git branch -d fix/projects-link
Deleted branch fix/projects-link (was 1bf90b5).
$ git switch feature/dark-theme
$ git push
Последний push обычный: история не переписывалась.
Проверьте себя
git log --oneline main..feature/dark-themeпоказывает четыре коммита:Исправить ссылку на проекты,поправил,wip ещё цвета,wip тёмная тема.- В
git log --oneline -3 mainсверху —Merge pull request #8 from alex-ivanov/fix/projects-link. - В
style.cssветки нет маркеров конфликта: правилоa, затем блок@media. git statusв ветке пишетYour branch is up to date with 'origin/feature/dark-theme'.- На сайте GitHub Pages ссылка «Все мои проекты» снова работает.
Частые ошибки
Перебазировали общую ветку (main или ветку, где коммитит коллега). Не отправили — верните её через reflog (ниже); отправили — договаривайтесь с командой.
Rebase «потерял» коммиты: удалили при конфликте не ту часть или нажали --skip. git reflog помнит, где ветка была до rebase:
$ git reflog -6
02bf7d8 HEAD@{0}: rebase (finish): returning to refs/heads/feature/dark-theme
02bf7d8 HEAD@{1}: rebase (pick): поправил
1353688 HEAD@{2}: rebase (pick): wip ещё цвета
1114e95 HEAD@{3}: rebase (continue): wip тёмная тема
816852b HEAD@{4}: rebase (start): checkout main
011e648 HEAD@{5}: checkout: moving from main to feature/dark-theme
Строка под rebase (start) — состояние до rebase (011e648); git reset --hard 011e648 вернёт ветку туда.
reset --hard стирает незакоммиченное
Перед git reset --hard убедитесь, что git status чист: незакоммиченные правки пропадут безвозвратно.
git rebase --continue отвечает You must edit all merge conflicts and then mark them as resolved using git add. Файл поправлен, но не добавлен: git add style.css.
Что важно запомнить
git rebase mainпереносит коммиты вашей ветки на конецmain: изменения те же, хеши новые, история прямая.- Конфликт при rebase: решить,
git add,git rebase --continue; передумали —git rebase --abort. - Золотое правило: перебазируйте только свою ветку, которую не взяли другие.
- После rebase отправленной ветки —
git push --force-with-lease, неgit pullи не--force. git cherry-pick <хеш>копирует один коммит в текущую ветку.
Ветка догнала main, но её коммиты — «wip» и «поправил» — ревьюеру ничего не скажут. В следующем уроке интерактивный rebase склеит и переименует их перед pull request.