Перейти к содержанию

2. Работа с изменениями и индекс (staging)

Цель темы: уверенно управлять тем, что попадает в коммит, и отменять изменения на разных этапах — рабочая директория, индекс, последний коммит.


Определения терминов

Индекс (staging area, индекс)

Индекс — промежуточная область между рабочей директорией и историей коммитов. Физически это файл .git/index. В нём хранится «снимок» того, что должно войти в следующий коммит. Команда git add не сразу пишет в историю, а обновляет индекс; git commit сохраняет в репозиторий только содержимое индекса.

В контексте этой темы важно различать три зоны:

Зона Описание Команды просмотра / изменения
Рабочая директория Файлы, которые вы редактируете git status, git diff
Индекс (staged) То, что подготовлено к коммиту git diff --staged, git restore --staged
Последний коммит Уже сохранённая история git log, git show

Staged / unstaged

  • Staged (подготовлено) — файл или изменение уже добавлено в индекс командой git add и попадёт в следующий коммит.
  • Unstaged (не в индексе) — изменение есть только в рабочей копии и в коммит не попадёт, пока не выполнить git add.

Amend (исправление последнего коммита)

Amend — изменение последнего коммита: можно поменять сообщение или добавить в него новые файлы/правки без создания нового коммита. История переписывается (меняется хеш последнего коммита), поэтому на общих ветках после amend обычно нужен осторожный push (или не делать amend уже запушенных коммитов).


Цепочка: рабочая директория → индекс → коммит

  [Рабочая директория]  --git add-->  [Индекс]  --git commit-->  [Коммит]
       (файлы на диске)                  (.git/index)              (история)
  • git add <file> — копирует текущее состояние файла из рабочей директории в индекс.
  • git commit — создаёт новый коммит из текущего состояния индекса и сдвигает текущую ветку на этот коммит.
  • Изменения только в рабочей директории не попадут в коммит, пока вы не добавите их в индекс.

Добавление в индекс

Добавление целиком

git add readme.md           # один файл
git add src/                # каталог и всё внутри
git add .                   # все изменения в репозитории

Добавление по частям (интерактивно)

Чтобы разбить изменения в одном файле на несколько коммитов:

git add -p readme.md
# или
git add --patch readme.md

Git покажет каждый «кусок» (hunk) изменений и спросит: stage (y), skip (n), split (s) и т.д. Так можно включить в коммит только часть правок.

Практика

Перед коммитом выполните git diff --staged, чтобы убедиться, что в индекс попало только нужное.


Снятие с индекса

Убрать файл из индекса, не трогая изменения в рабочей директории:

git restore --staged readme.md   # Git 2.23+
git reset HEAD readme.md         # классический вариант

После этого файл снова в состоянии «modified», но не «staged».

git restore --staged .
# убрать из индекса все файлы

Отмена изменений в рабочей директории

Вернуть файл к состоянию последнего коммита (или к состоянию в индексе), удалив локальные правки:

git restore readme.md      # Git 2.23+
git checkout -- readme.md # старый синтаксис

Внимание

После git restore <file> несохранённые изменения в этом файле теряются. Убедитесь, что не отменяете то, что нужно.


Просмотр различий

Рабочая директория vs индекс

Показывает, что вы изменили в файлах, но ещё не добавили в индекс:

git diff
git diff -- readme.md     # только по файлу

Индекс vs последний коммит

Показывает, что уже в индексе и попадёт в следующий коммит:

git diff --staged
git diff --cached         # то же самое

Между двумя коммитами

git diff abc123 def456
git diff HEAD~2 HEAD -- src/   # последние два коммита по каталогу src/

Пример

Типичный порядок перед коммитом: git statusgit diff (что меняли) → git diff --staged (что попадёт в коммит) → git commit -m "...".


Изменение последнего коммита (amend)

Поменять сообщение последнего коммита

git commit --amend -m "Новое сообщение"

Добавить файл в последний коммит

Например, забыли добавить файл:

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

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

Production

На общих ветках (например, main) лучше не менять уже запушенные коммиты. Amend уместен для локальных коммитов до первого git push или в личных ветках.


.gitignore

Файл .gitignore в корне репозитория задаёт шаблоны файлов и каталогов, которые Git не отслеживает. Синтаксис:

  • Одна строка — один шаблон.
  • # — комментарий.
  • * — любое количество символов; ? — один символ.
  • / в начале — только от корня репозитория; в конце — только каталог.
  • ! — исключение (файл не игнорировать).
# Зависимости и артефакты
node_modules/
__pycache__/
*.pyc
build/
dist/

# Локальные настройки и секреты
.env
.env.local
*.pem

# IDE
.idea/
.vscode/
*.swp

Исключение: не игнорировать один конкретный файл внутри игнорируемого каталога:

logs/
!logs/.gitkeep

Файлы, уже отслеживаемые Git, из .gitignore не исчезнут автоматически — их нужно перестать отслеживать: git rm --cached <file>.


Паттерны использования

Паттерн Описание
Проверять diff перед коммитом Всегда смотреть git diff и git diff --staged, чтобы не закоммитить лишнее и не забыть нужное.
Дробить изменения Использовать git add -p для логического разбиения правок по разным коммитам.
Атомарные коммиты Один коммит — одна логическая правка; так проще ревью и откат.
Актуальный .gitignore Добавлять шаблоны для артефактов и секретов до первого коммита, чтобы они не попали в историю.

Антипаттерны

Антипаттерн Почему плохо Что делать
git add . без просмотра В коммит могут попасть билды, секреты, временные файлы. Проверять git status и git diff --staged; добавлять файлы выборочно или использовать git add -p.
Игнорировать индекс Путаница между «что изменено» и «что попадёт в коммит». Явно различать git diff и git diff --staged.
Amend уже запушенных коммитов Переписывание истории на общих ветках ломает коллег и CI. Amend только до первого push или в личной ветке; в общих ветках использовать git revert.
Коммитить секреты Утечка ключей и паролей в истории. Держать секреты в .env и в .gitignore; не добавлять конфиги с паролями.

Примеры из production

Pre-commit хуки

В CI или локально через pre-commit проверяют список файлов в коммите: нет ли билдов, секретов, больших бинарников. Понимание индекса и git diff --staged помогает писать такие проверки (например, «запретить коммитить файлы из списка»).

Проверка в CI

Пайплайн может проверять, что в коммите нет определённых паттернов (например, TODO в продакшен-коде или отладочных выводов). Всё это опирается на то, что коммит — снимок конкретного набора файлов из индекса.

Восстановление после случайного add

Если случайно сделали git add на секрет или лишний файл, достаточно снять его с индекса до коммита: git restore --staged <file>. После коммита отмена сложнее (revert или переписывание истории).


Дополнительные материалы