Инструкция

git add и git commit: как правильно сохранять изменения

Обновлено: · Skillaria.Top

Сохранение изменений в Git идёт в два шага: git add добавляет нужные правки в индекс (staging area), а git commit -m "сообщение" записывает их в историю как один снимок. git status показывает, что изменено и что уже подготовлено. Исправить последний коммит можно через git commit --amend.

В Git нет кнопки «сохранить». Изменения фиксируются в два шага: сначала git add отбирает, какие правки войдут в следующий снимок, затем git commit записывает этот снимок в историю. Промежуточная зона между ними называется индексом, или staging area. Именно её многие не понимают годами — и именно она делает коммиты осмысленными.

Три состояния файла: рабочая папка, индекс, история

Любое изменение проходит путь через три области:

  1. Рабочая директория — вы редактируете файл в редакторе.
  2. Индекс (stage) — git add кладёт текущую версию файла в черновик следующего коммита.
  3. История — git commit превращает содержимое индекса в коммит с автором, датой и сообщением.

Удобная аналогия — посылка. Рабочая папка — это комната с вещами, индекс — открытая коробка, куда вы складываете то, что хотите отправить, а коммит — запечатанная и подписанная посылка. Вы сами решаете, что положить в коробку, и не обязаны отправлять всё сразу.

Зачем нужен индекс

Представьте: за час вы починили баг в авторизации, заодно поправили опечатку в README и начали новую функцию. Без индекса всё это попало бы в один коммит «разное». С индексом вы делаете три отдельных коммита, каждый из которых легко понять, проверить на ревью и при необходимости откатить, не задев остальное.

git status: что изменено и что подготовлено

Перед каждым add и commit полезно смотреть git status. Это самая безопасная команда Git — она ничего не меняет.

$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   src/auth.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   README.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        src/profile.js
  • Changes to be committed — уже в индексе, войдёт в коммит;
  • Changes not staged — изменено, но не добавлено;
  • Untracked files — новые файлы, о которых Git пока не знает.

Короткий формат удобнее, когда файлов много:

$ git status -s
M  src/auth.js
 M README.md
?? src/profile.js

Первая колонка — состояние в индексе, вторая — в рабочей папке. M слева значит «изменён и добавлен», справа — «изменён, не добавлен», ?? — неотслеживаемый.

git add: как добавить изменения в индекс

КомандаЧто добавляет
git add file.jsКонкретный файл
git add src/Всё изменённое в папке
git add .Все изменения в текущей папке и ниже, включая новые и удалённые файлы
git add -AВсе изменения во всём репозитории
git add -uТолько уже отслеживаемые файлы, новые не трогает
git add -pИнтерактивно, по фрагментам (hunks)
git add '*.css'Файлы по шаблону

Синоним git add — git stage: это одна и та же команда, отсюда и термин «stage», «застейджить».

git add -p: добавить часть файла

Самый недооценённый приём. Если в одном файле перемешаны две разные правки, git add -p покажет каждый фрагмент и спросит, добавлять ли его:

$ git add -p src/auth.js
@@ -12,7 +12,7 @@ function login(user) {
-  if (user.password = input) {
+  if (user.password === input) {
(1/2) Stage this hunk [y,n,q,a,d,s,e,?]?

y — добавить, n — пропустить, s — разбить фрагмент мельче, q — выйти. Так из одного файла получаются два аккуратных коммита.

Как проверить, что именно уйдёт в коммит

git diff            # изменения, ещё НЕ добавленные в индекс
git diff --staged   # то, что уже в индексе и войдёт в коммит

Частая путаница: после git add обычный git diff ничего не показывает. Это не значит, что изменения пропали, — они в индексе, смотрите git diff --staged (синоним --cached).

Как убрать файл из индекса

git restore --staged file.js

Правки в файле при этом остаются, он просто перестаёт быть подготовленным к коммиту. В старых версиях Git для этого использовали git reset HEAD file.js — работает и сейчас.

git commit: фиксируем изменения

git commit -m "Исправить проверку пароля при входе"
[main 3f2a9c1] Исправить проверку пароля при входе
 1 file changed, 1 insertion(+), 1 deletion(-)

В ответе — ветка, короткий хеш нового коммита и статистика. В коммит попадает только содержимое индекса. Если после git add вы ещё раз поправили файл, новые правки в коммит не войдут, пока не добавите их снова.

Полезные флаги git commit

КомандаЧто делает
git commitОткроет редактор для многострочного сообщения
git commit -m "..."Сообщение прямо в команде
git commit -am "..."Добавит все изменённые отслеживаемые файлы и закоммитит; новые файлы не попадут
git commit -vПокажет diff в редакторе, пока пишете сообщение
git commit --amendПерезапишет последний коммит
git commit --allow-empty -m "..."Пустой коммит, например чтобы перезапустить CI

Если редактор по умолчанию — Vim и вы в нём застряли: напишите сообщение, нажмите Esc, затем введите :wq и Enter. Сменить редактор: git config --global core.editor "code --wait" или nano.

Как писать хорошее сообщение коммита

Сообщение читают через полгода, когда ищут, откуда взялся баг. Оно должно отвечать на вопрос «что и зачем», а не «что я делал сегодня».

  • первая строка — до 50–72 символов, суть изменения;
  • в повелительном наклонении или нейтрально: «Добавить валидацию email», «Fix login redirect»;
  • при необходимости — пустая строка и подробности: почему так, какие есть ограничения;
  • один коммит — одно логическое изменение.

Плохо: fix, правки, wip, asdf. Хорошо: Исправить падение корзины при пустом списке товаров. Многие команды используют формат Conventional Commits: feat: ..., fix: ..., docs: ....

git commit --amend: как исправить последний коммит

Опечатка в сообщении или забыли добавить файл — не нужно делать новый коммит «забыл файл». Для этого есть amend.

Исправить сообщение

git commit --amend -m "Исправить проверку пароля при входе"

Добавить забытый файл

git add forgotten.js
git commit --amend --no-edit

Флаг --no-edit оставляет прежнее сообщение.

Важное про amend

--amend не «редактирует» коммит, а создаёт новый с другим хешем и заменяет им старый. Пока коммит только у вас — это безопасно. Если вы уже сделали git push, после amend обычный push будет отклонён, и придётся использовать git push --force-with-lease. В общих ветках, где работают другие, так делать не стоит: вы перепишете историю, на которой они уже строят свою работу.

Если amend сделан по ошибке, старый коммит можно найти в git reflog и вернуться к нему через git reset --soft HEAD@{1}.

Типичные ошибки

«nothing to commit, working tree clean»

Изменений нет — всё уже закоммичено, или вы правите файл в другой папке. Проверьте git status и путь к проекту.

«no changes added to commit»

Файлы изменены, но не добавлены в индекс. Выполните git add или используйте git commit -am для уже отслеживаемых файлов.

«Please tell me who you are»

Не заданы имя и e-mail. Один раз выполните git config --global user.name "Имя" и git config --global user.email "почта".

Закоммитили лишнее

Если коммит ещё не отправлен, отмените его, сохранив изменения в индексе: git reset --soft HEAD~1. Затем уберите лишнее через git restore --staged и закоммитьте заново. Если в коммит попал секрет, считайте его скомпрометированным и перевыпустите.

git add . добавил мусор

Настройте .gitignore заранее и перед коммитом смотрите git status. Уже отслеживаемый файл перестаёт отслеживаться только после git rm --cached файл.

Что такое коммит на самом деле

Коммит хранит не разницу с предыдущей версией, а снимок всего проекта: ссылку на дерево файлов, ссылку на родительский коммит, автора, дату и сообщение. Неизменённые файлы не копируются — Git ссылается на уже сохранённые объекты, поэтому история занимает мало места.

Хеш коммита (например, 3f2a9c1) вычисляется из всего этого содержимого. Поменяйте хоть букву в сообщении — получится другой хеш. Именно поэтому --amend и rebase создают новые коммиты, а не правят старые, и поэтому переписанная история конфликтует с копиями у коллег.

Посмотреть историю коротко можно так:

git log --oneline --graph -10

Каждая строка — коммит; если сообщения в вашей истории понятны без открытия диффа, вы всё делаете правильно.

Рабочий цикл на каждый день

git status                 # что изменилось
git diff                   # посмотреть правки
git add -p                 # отобрать нужное
git diff --staged          # проверить, что уйдёт в коммит
git commit -m "Понятное описание"
git log --oneline -5       # убедиться, что коммит на месте
git push                   # отправить на сервер

Коммит сохраняет изменения только локально. Чтобы они попали на GitHub или другой сервер, нужен git push.

Итог

git add собирает следующий снимок в индексе, git status и git diff --staged показывают, что в него войдёт, а git commit записывает снимок в историю. Делайте маленькие логичные коммиты с понятными сообщениями, а для мелких исправлений последнего коммита используйте git commit --amend — до push. Индекс и двухшаговая схема add → commit разобраны на практике в курсе по Git.

Частые вопросы

Как часто нужно делать коммиты?

Каждый раз, когда завершено одно логическое изменение и проект в рабочем состоянии. Лучше много маленьких коммитов, чем один огромный в конце дня.

Есть ли в Git команда git save?

Нет, такой команды нет. Сохранение — это git add и git commit, а временно отложить незаконченную работу можно через git stash.

Как посмотреть, что было в коммите?

Команда git show хеш покажет автора, сообщение и все изменения коммита. Без хеша она покажет последний коммит.

Чем git add . отличается от git add -A?

В современных версиях Git оба добавляют новые, изменённые и удалённые файлы. Разница в области: git add . работает с текущей папкой и вложенными, а git add -A — со всем репозиторием.

Можно ли изменить не последний, а более старый коммит?

Да, через интерактивный rebase: git rebase -i хеш-родителя, затем отметить нужный коммит как edit или reword. Делайте это только с коммитами, которые ещё не отправлены в общую ветку.

Разберите тему на видео

Эта тема подробно разобрана с практикой в курсе «Git с нуля до уверенного разработчика».

Перейти к курсу