lesson ── git-labs ── ~22 мин ── 8 шагов
Цель - провести feature-ветку через полный цикл. Создашь её от main, сделаешь пару коммитов, увидишь fast-forward merge и three-way merge, попробуешь удалить недоtested ветку и получишь честный отказ Git'а.
интерактивный sandbox
Поднимется контейнер gitlab/git-base с git, bash, pre-commit. В браузере откроется терминал, можно сразу git init. Каждый шаг проверяется автоматически. Сеть air-gapped, github.com недоступен.
stack ── git · bash · 256 MB RAM · air-gapped · самоуничтожается через 30 мин простоя
cd /home/student/work
mkdir -p branches-lab && cd branches-lab
git init -b main
echo "base" > readme.txt
git add . && git commit -m "init"
git branch
Сейчас ветка одна - main. Дальше создашь свою.
✓ Репо с одним коммитом на main. Готов к ветвлению.
cd /home/student/work/branches-lab
git switch -c feat/quick # -c = create, аналог `checkout -b`
git branch # звёздочка у активной ветки
git log --oneline --graph --all # --graph = ASCII-граф, --all = все refs
switch -c (== checkout -b) создаёт ветку от HEAD и переключается.
git branch теперь показывает обе - звёздочка у активной.
Если ошибка `unknown switch 'switch'` - старый git. Используй `checkout -b feat/quick`.
✓ Ветка создана, ты на ней.
cd /home/student/work/branches-lab
echo "quick feature" > quick.txt
git add . && git commit -m "feat: add quick"
git log --oneline --graph --all
На feat/quick теперь 2 коммита, на main - 1. Граф показывает расхождение визуально не покажет (ещё нет ветвления в main).
✓ Ветка ушла вперёд на один коммит.
cd /home/student/work/branches-lab
git switch main
git merge feat/quick # ff = просто двигаем ref вперёд, без merge-коммита
git log --oneline --graph --all
Сообщение Fast-forward. main и feat/quick теперь указывают на
один коммит. Никакого merge-коммита - main просто переставился
вперёд, потому что между main и feat/quick не было расхождения.
✓ Fast-forward прошёл. Граф остался линейным.
Чтобы получить three-way, обе ветки должны разойтись от общего предка.
cd /home/student/work/branches-lab
git switch -c feat/slow
echo "slow line" > slow.txt
git add . && git commit -m "feat: add slow"
git switch main
echo "main update" >> readme.txt # >> = append, не перезатирает
git commit -am "main: update readme" # -a = staged уже отслеживаемых, -m = сообщение
git log --oneline --graph --all
Теперь main и feat/slow разошлись. Граф покажет V-форму.
✓ Ветки разошлись. Готов к three-way.
cd /home/student/work/branches-lab
# --no-edit = взять дефолтное сообщение merge-коммита, не открывать редактор
git merge --no-edit feat/slow
git log --oneline --graph --all
Сообщение Merge made by the 'ort' strategy. В логе появился
merge-коммит с двумя parent'ами. Граф больше не линейный.
Файлы из обеих веток оказались в working tree - они трогали разные файлы, конфликта нет.
✓ Merge-коммит создан. Это и есть three-way.
cd /home/student/work/branches-lab
git branch -d feat/quick # -d = "delete if merged", безопасно
git branch -d feat/slow
git branch
Обе удалились без вопросов - они слиты в main. branch -d
проверяет это сам, и отказывает, если нет.
✓ Слитые ветки удалены. Осталась только main.
cd /home/student/work/branches-lab
git switch -c feat/draft
echo "draft idea" > draft.txt
git add . && git commit -m "draft"
git switch main
git branch -d feat/draft # упадёт: ветка не слита в main
Должна выйти ошибка: error: The branch 'feat/draft' is not fully merged.. Это защита Git: ты можешь потерять коммиты, удалив
ветку, которой нет в main.
Принудительное удаление - заглавный -D:
git branch -D feat/draft # -D (заглавная) = принудительное удаление
git branch
Теперь действительно удалена. Если коммит больше нигде не
используется - его подметёт git gc, когда сработает (вручную
или как gc --auto); reflog держит запись о ветке ~30 дней по
умолчанию, после этого коммит становится кандидатом на сборку.
✓ Защита Git увидена, принудительное удаление сработало.
Ветка - это указатель на коммит. Создаётся через git branch или
switch -c, переключение через switch. Merge может быть
fast-forward или three-way - зависит от того, ушёл ли target.
Удаление через branch -d (безопасно) или -D (принудительно).
команды
git switch -c feat/xсоздать и переключитьсяgit merge feat/xслить feat/x в текущую (ff или 3-way)git merge --no-ff feat/xфорсировать merge-коммит даже при ffgit branch -d feat/xудалить, если ветка слитаgit branch -D feat/xудалить принудительноконцепции