lesson ── git-labs ── ~20 мин ── 7 шагов
Цель - научиться резать большой набор изменений на маленькие
тематические коммиты через git add -p. И поправить только что
сделанный коммит без новой записи в истории - через git commit --amend.
интерактивный 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 atomic-lab && cd atomic-lab
git init -b main
cat > server.js <<'EOF'
function add(a, b) {return a + b;
}
console.log(add(2, 3));
EOF
git add . && git commit -m "init: add function"
git log --oneline
Стартовая точка - один файл с одной функцией.
✓ Стартовый коммит на месте.
Имитируй типичный рабочий день: подправил типизацию, добавил новую фичу, починил баг - всё в одном файле.
cd /home/student/work/atomic-lab
cat > server.js <<'EOF'
// refactor: jsdoc types
/**
* @param {number} a * @param {number} b*/
function add(a, b) {if (a == null || b == null) return 0;
return a + b;
}
// feat: subtract
function sub(a, b) {return a - b;
}
console.log(add(2, 3));
console.log(sub(5, 2));
EOF
git diff
Три темы перемешаны: refactor (jsdoc), fix (null-check), feat (sub). В нормальной работе так бы и закоммитил «misc changes». Сейчас - разделим.
✓ Три темы в одном diff. Дальше будем их резать.
Раз уж файл уже изменён, отдельно потренируем amend на сообщении. Сначала верни working tree чистым:
cd /home/student/work/atomic-lab
git stash push -m "wip-mess" # отложить uncommitted работу в stash с меткой
git log --oneline
# --amend заменяет последний коммит новым (с другим SHA), -m задаёт новое сообщение
git commit --amend -m "init: add function with two-arg signature"
git log --oneline # SHA коммита изменился
git stash pop # вернуть отложенную работу обратно
Видишь: сообщение поменялось, но SHA коммита стал другим (проверь
через git log -1 --format=%H). amend - не «edit in place»; это
создание нового коммита с заменой указателя ветки.
✓ Сообщение исправлено через amend. Дальше add -p.
git add -p server.js запустит интерактивный диалог. По каждому
hunk'у Git спросит: Stage this hunk [y,n,q,a,d,s,e,?]?.
Самое полезное:
y - да, в indexn - нет, оставить в working trees - split (разрезать hunk на меньшие)q - выйтиcd /home/student/work/atomic-lab
git add -p server.js # -p (--patch) = интерактивный staging по hunk'ам
Ответь y на hunk с jsdoc types и null-check рефактором (можно
s если они слиплись), n на всё что касается sub. После -
проверь:
git diff --cached # что попало в index (готово к commit'у)
git diff # что осталось unstaged в working tree
В index должен попасть только refactor. Subtract в working остался.
Если в интерактиве запутался - `q` выходит. Прогон не разрушающий, можно повторять.
✓ Refactor в index, feature ещё в working.
cd /home/student/work/atomic-lab
git commit -m "refactor: add jsdoc types and null-check"
git log --oneline
git status
Status покажет, что server.js ещё modified - subtract в working.
✓ Первый атомарный коммит готов.
Теперь добавь остаток - там только feat:
cd /home/student/work/atomic-lab
git add server.js
git diff --cached
git commit -m "feat: add sub function"
git log --oneline
Три коммита: init, refactor, feat. Каждый - отдельная тема.
✓ Атомарная декомпозиция готова.
Заметил, что забыл добавить console.log(sub(...)) отдельным
коммитом? Это часть той же фичи - можно добавить в amend.
Но console.log уже в файле. Сымитируем «забыл и добавил»:
cd /home/student/work/atomic-lab
echo "// usage example below" > note.txt
git add note.txt
# --amend = заменить HEAD новым коммитом, --no-edit = оставить старое сообщение
git commit --amend --no-edit
git log --oneline # количество коммитов то же, но HEAD теперь содержит note.txt
git show HEAD --stat # --stat = краткая сводка изменённых файлов
--amend --no-edit дополнил последний коммит файлом, сообщение
сохранил. История осталась 3 коммита, но последний теперь содержит
note.txt.
Правило: amend - только до push'а в shared ветку. На запушенной
ветке это force-push, что у других сорвёт git pull.
✓ Amend дополнил коммит. История осталась короткой.
git add -p - интерактивный staging по hunk'ам. Можно собрать
коммит из части изменений в файле. git commit --amend правит
последний коммит: либо сообщение, либо содержимое.
команды
git add -p fileинтерактивно выбрать hunk'и для staginggit diff --cachedпроверить что попало в index до commit'аgit commit --amendпоправить последний коммит (сообщение или содержимое)git commit --amend --no-editоставить сообщение, добавить новый stageконцепции