Перед этим и последующими уроками обязательно нужно потренироваться с базовыми командами.

Если посмотреть на вывод команды git status репозитория, в котором были сделаны все возможные изменения, такие как добавление нового файла, изменение и удаление, то он будет выглядеть примерно так:

lasso$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed: # Изменения попадающие в следующий коммит

    new file:   .editorconfig
    modified:   Dockerfile

Changes not staged for commit: # Изменения которые не попадут в коммит

    modified:   docker-compose.yml
    deleted:    rebar.lock

Untracked files: # Неотслеживаемые файлы

    Procfile

Не вдаваясь в детали можно сказать, что у любых файлов, с которыми мы работаем внутри рабочей копии, есть разные состояния. И именно им посвящен данный урок.

Untracked

В первую очередь все файлы делятся на tracked и untracked. Untracked – это новый файл, который не был добавлен для отслеживания командой git add. Все остальные файлы являются tracked.

lasso$ touch .editorconfig
lasso$ git status

On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files: # Тут не отслеживается

    .editorconfig

lasso$ git add .editorconfig
lasso$ git status

On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed: # Тут отслеживается

    new file:   .editorconfig

С непривычки такое поведение может показаться странным. Почему бы сразу не давать возможность коммитить, без необходимости добавлять файл в отслеживаемые?

На самом деле такое поведение очень важно. Как вы убедитесь в своей практике, множество инструментов генерирует свои файлы (например, редакторы, операционная система, пакетные менеджеры), а запуск программ порождает файлы с логами и другие артефакты. И если бы git commit автоматически включал все новые файлы, в репозиторий после коммитов постоянно попадали бы ненужные данные.

Если вы заметили такие файлы, то их нужно добавить в специальный файл .gitignore, который поможет гиту определить то, что точно не придется коммитить. Больше вы эти файлы и папки не увидите даже после команды git status. Все, что перечислено в этом файле, закоммитить не удастся. Правда, если вы хотите добавить в .gitignore то что уже было закоммичено, предварительно придется удалить соответствующие данные из репозитория с помощью команды git rm.

Формат файла простой, его можно подсмотреть в одном из наших репозиториев.

Tracked

С отслеживаемыми файлами все сложнее. Начнем с того, что они тоже могут находиться в 3-х разных состояниях:

  • unmodified
  • modified
  • staged

С unmodified все просто. Если файл в рабочей копии точно такой же как и в репозитории, то считается что его не модифицировали. Любой файл после коммита переходит в состояние unmodified. Соответственно, команда git status никак не отражает это состояние.

Modified тоже интуитивно понятен. Как только мы изменили любой unmodified (но не untracked!) файл, он автоматически становится modified. И вот тут нас поджидает сюрприз: если попробовать вызвать git commit, то modified файлы в него не попадут. Предварительно их нужно перевести в состояние staged сделав git add. В этом и заключается смысл команды git add, она переводит файлы с любым состоянием, кроме unmodifed, в состояние staged. Это касается и untracked файлов. И только после этого они попадут в коммит.

Я понимаю, что абзац выше может снести крышу, это нормально. Понимание состояний гита – это не то, что можно понять и простить исключительно по чтению мануалов. Единственное, что поможет – постоянная практика. Если сейчас вы поняли, что стало очень сложно – не отчаивайтесь, дочитайте до конца (как мы рекомендуем) и поэкспериментируйте.

Git Files Lifecycle

По большому счету наличие состояния staged не является критически необходимым, другими словами, можно было реализовать git и без этого промежуточного звена. Но сделан он не просто так, и его польза станет понятна только со временем. Главная идея в том, что во время работы над репозиторием, как правило, делаются несвязанные изменения в разных местах, например, вы делали какую-то фичу, а попутно отрефакторили код, который вам не понравился. Если этот код не имеет отношения к задаче, то, с точки зрения, понятия "хороший коммит" он должен быть закоммичен отдельно. Так вот, такое можно сделать именно благодаря наличию состояния staged. Делается это посредством интерактивного добавления git add -i, во время которого git показывает фрагменты измененного кода и спрашивает, нужно ли добавить это изменение в staged (или, как говорят, "в индекс").

Reset

Мы научились добавлять файлы в индекс, но что делать если мы наоборот хотим их удалить из него? Для этого нам помогут две команды: reset и checkout.

  • git reset path/to/file переводит файл из состояния staged в modified
  • git checkout path/to/file переводит файл из состояния modified в unmodified, то есть по сути эта команда сбрасывает изменения.