Rebase — това е операция в Git, която премества commits от един клон на върха на друг, създавайки линейна история без излишни merge-commits. За разлика от сливането, rebase презаписва историята: всеки преместен commit получава нов hash, тъй като родителят му се променя. Според документацията на Git (2026), rebase се използва за синхронизиране на feature-клонове с актуалното състояние на main преди създаване на pull request. Командата git rebase е един от основните инструменти за поддържане на чиста история в проекти, използващи Git Flow.
Основни точки
Rebase — това е команда на Git, която пребазира текущия клон върху посочения клон: взема всички commits от текущия клон, временно ги запазва, премества указателя на клона върху целевия commit и последователно прилага запазените commits отгоре му. Резултатът — историята изглежда така, сякаш разработчикът е работил директно от последния commit на целевия клон.
Основен синтаксис: git rebase main — намирайки се във feature-клон, тази команда премества всички feature commits на върха на main. Git използва стратегия three-way merge за всеки commit поотделно. Ако commit A вече присъства в целевия клон (определя се по hash), Git автоматично го пропуска, което избягва дублиране на промени.
Rebase поддържа и onto режим за преместване на част от commits: git rebase --onto target start end — тази форма позволява извличане на диапазон от commits от един клон и прилагането им върху друг. Например git rebase --onto main feature~3 feature ще премести последните три commits на feature-клона върху main.
# Превключи на feature клон
git checkout feature
# Пребазирай feature върху main
git rebase main
# След успешен rebase — историята е линейна
git log --oneline --graph
# Премести последните 3 commits в main
git rebase --onto main HEAD~3 HEAD
Rebase и merge решават една и съща задача — комбиниране на промени от различни клонове — но го правят по коренно различни начини. Merge запазва пълната история на сливанията, създавайки merge-commit с двама родители. Rebase презаписва историята, правейки я линейна. Изборът между тях зависи от работния поток на екипа и правилата за работа с хранилището.
Основната разлика — как се записва фактът на сливане. Merge запазва: „в този момент обединихме feature в main” — това е информативно за историята на проекта, но замърсява лога при чести сливания. Rebase показва: „feature commits бяха направени последователно от последното състояние на main” — това е чисто, но скрива факта, че работата е вървяла паралелно.
Втората разлика — обработка на конфликти. При merge конфликтите се разрешават веднъж и решението се записва в merge-commit. При rebase конфликти могат да възникнат за всеки преместен commit и всеки изисква отделно разрешаване. Това е по-трудоемко, но позволява по-прецизен контрол върху това кои промени попадат във финалната версия.
| Критерий | Rebase | Merge |
|---|---|---|
| История | Линейна, без merge-commits | Нелинейна, с merge-commits |
| Hash-ове на commits | Презаписват се (нови) | Оригиналните се запазват |
| Конфликти | За всеки commit поотделно | Веднъж в merge-commit |
| Публични клонове | Забранен | Позволен |
| Команда за отмяна | git rebase --abort | git merge --abort |
Интерактивен rebase (git rebase -i) — това е режим, при който Git отваря редактор със списък на commits и налични действия за всеки от тях. Разработчикът може да презапише историята преди изпращане в отдалеченото хранилище. Това е основният инструмент за поддържане на чистота на commits във feature-клон.
Налични команди в интерактивен режим: pick (остави commit както е), reword (промени съобщението на commit), edit (спри за промени), squash (обедини с предишния commit, запази и двете съобщения), fixup (обедини, като изхвърлиш съобщението), drop (изтрий commit). Всяка команда се посочва пред hash-а на commit в отворения редактор.
Squash и fixup — най-често използваните команди за обединяване на commits. Ако разработчикът е направил 5 малки commits с корекции по време на работа, squash ще ги обедини в един логически commit със смислено съобщение. Fixup е полезен за коригиране на правописни грешки: промените отиват в предишния commit, без да запазват свое собствено съобщение.
# Отвори редактор за последните 4 commits
git rebase -i HEAD~4
# Редакторът ще покаже:
pick a1b2c3d Add authentication
pick e4f5g6h Fix typo in login
squash i6j7k8l Additional login fixes
pick m9n0o1p Add auth tests
# След запазване — Git изпълнява rebase
# и отваря редактор за обединеното commit съобщение
# Auto-squash без отваряне на редактор
git rebase -i HEAD~4 --autosquash
Флагът --autosquash автоматично задава fixup/squash за commits, чиито съобщения започват с fixup! или squash!. Ускорява работата, ако разработчикът предварително маркира commits за последващо обединяване. Флагът --committer-date-is-author-date запазва оригиналната дата на commit при пребазиране — полезно за запазване на хронология в историята.
Конфликти при rebase възникват, когато Git не може автоматично да приложи преместения commit поради противоречия с промени в целевия клон. За разлика от merge, където конфликтът се разрешава веднъж, при rebase всеки commit може да предизвика конфликт и трябва да се разрешава последователно за всеки commit от най-стария до най-новия.
Когато възникне конфликт, Git спира rebase и съобщава кой commit е причинил проблема. Разработчикът отваря конфликтния файл (Git маркира конфликтните области с маркери <<<<<<<, =======, >>>>>>>), редактира го, добавя го в индекса (git add) и продължава rebase с командата git rebase --continue. Ако не се намери решение — git rebase --abort напълно отменя пребазирането.
Съвет: при множество конфликти е по-ефективно да използвате git mergetool, който отваря визуален редактор за разрешаване на противоречия. Може също да пропуснете проблемния commit (git rebase --skip), но това ще премахне неговите промени от крайната история, което рядко е правилното решение.
# Започни rebase с конфликт
git rebase main
# Auto-merging file.txt
# КОНФЛИКТ (съдържание): Конфликт при сливане в file.txt
# Провери статуса
git status
# и двата модифицирани: file.txt
# Редактирай конфликтните секции → git add → продължи
git add file.txt
git rebase --continue
# При съмнение — отмени
git rebase --abort
Златно правило на rebase: никога не пребазирайте commits, които вече са изпратени в отдалеченото хранилище и са достъпни за други разработчици. Тъй като rebase презаписва hash-овете на commits, колегите ще срещнат конфликти при опит за синхронизация — тяхната локална история ще се разминава с презаписаната отдалечена.
Ситуация, в която rebase е категорично забранен: ако някой вече е създал клон на базата на вашите commits (например вашият колега е направил feature от вашия feature), промяната на историята ще развали работата му. В такива случаи трябва да се използва merge. Също не се препоръчва да правите rebase точно преди крайния срок — грешка при разрешаване на конфликти може да отнеме повече време от очакваното и да блокира изданието.
Изключение: ако клонът се използва само от един разработчик (личен feature-клон, непубликуван или публикуван в draft режим), rebase преди push е стандартна практика. След публикуване и започване на колективна работа — само merge. GitHub и GitLab по подразбиране предлагат squash merge като компромис: обединява commits в един, но не презаписва историята на целевия клон.
В съвременните екипи най-често се използва работен поток, ориентиран към rebase в комбинация с GitHub Flow. Процесът изглежда така: разработчикът създава feature-клон от main, работи в него, периодично се синхронизира чрез git rebase main и преди създаване на pull request извършва интерактивен rebase за почистване на историята.
След създаване на PR (ако е необходимо да се изтеглят нови промени от main) се използва git pull --rebase main вместо обикновения git pull. Това позволява изтегляне на промени без създаване на излишен merge-commit. Git pull с флаг --rebase е еквивалентен на git fetch + git rebase — Git първо зарежда нови commits, след което пребазира локалните промени върху тях.
Git позволява настройване на rebase като поведение по подразбиране за pull: git config --global pull.rebase true. След тази конфигурация git pull винаги извършва rebase вместо merge. Ако е необходим обикновен pull — се използва git pull --no-rebase. Много екипи също включват autostash: git config --global rebase.autoStash true — това автоматично скрива непотвърдени промени преди rebase и ги възстановява след това.
Често задавани въпроси
Да пребазирате — означава да изпълните git rebase: да преместите commits от текущия клон на върха на друг. В резултат историята става линейна, всеки commit получава нов hash и merge-commits не се създават. Командата се използва за синхронизиране на клонове без излишни точки на сливане в лога.
Merge създава merge-commit с двама родители, запазвайки паралелна история и оригинални hash-ове. Rebase презаписва историята — commits получават нови hash-ове и историята става линейна. Merge е по-безопасен за публични клонове, rebase дава по-чист лог.
Командата git rebase -i HEAD~N отваря редактор с последните N commits. За всеки commit може да изберете действие: pick (остави), reword (преименувай), edit (промени), squash (обедини с предишния), fixup (обедини без съобщение), drop (изтрий). След запазване Git прилага избраните промени.
Rebase презаписва hash-овете на commits, което прави историята несъвместима с копия на същите commits при други разработчици. Ако колега вече е получил вашите commits чрез git pull и вие по-късно сте ги пребазирали, неговият git push ще бъде отхвърлен, а git pull ще създаде дублиращи се commits и конфликти.
Преди завършване — git rebase --abort напълно отменя. След завършване може да възстановите предишното състояние чрез git reflog — намерете hash-а на commit преди rebase и изпълнете git reset --hard към него. Reflog съхранява история на движенията на HEAD по подразбиране за 30 дни.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също