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

Если посмотреть на вывод команды 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

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

Неотслеживаемые файлы

В первую очередь все файлы делятся на отслеживаемые (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 определить то, что точно не придётся коммитить. Больше вы эти файлы и директории не увидите даже после команды git status. Всё, что перечислено в этом файле, закоммитить не удастся. Правда, если вы хотите добавить в .gitignore то что уже было закоммичено, предварительно придётся удалить соответствующие данные из репозитория с помощью команды git rm.

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

Отслеживаемые файлы

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

  • неизменённое (unmodified)
  • изменённое (modified)
  • отслеживаемое (staged)

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

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

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

Git Files Lifecycle

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

Сброс изменений файла

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

  • git reset path/to/file переводит файл из состояния staged в modified
  • git checkout -- path/to/file переводит файл из состояния modified в unmodified, то есть по сути эта команда сбрасывает изменения.
Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Node, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →