Перед тем, как перейти к более специализированными утилитам, давайте поговорим о reset и checkout. Эти команды кажутся самыми непонятными из всех, которые есть в Git, когда вы в первый раз сталкиваетесь с ними. Они делают так много, что попытки по-настоящему их понять и правильно использовать кажутся безнадежными. Для того, чтобы всё же достичь этого, мы советуем воспользоваться простой аналогией.
Разобраться с командами reset и checkout будет проще, если считать, что Git управляет содержимым трех различных деревьев. Здесь под “деревом” мы понимаем “набор файлов”, а не специальную структуру данных. (В некоторых случаях индекс ведет себя не совсем так, как дерево, но для наших текущих целей его проще представлять именно таким.)
В своих обычных операциях Git управляет тремя деревьями:
Дерево |
Назначение |
HEAD |
Снимок последнего коммита, родитель следующего |
Индекс |
Снимок следующего намеченного коммита |
Рабочий Каталог |
Песочница |
HEAD – это указатель на текущую ветку, которая, в свою очередь, является указателем на последний коммит, сделанный в этой ветке. Это значит, что HEAD будет родителем следующего созданного коммита. Как правило, самое простое считать HEAD снимком вашего последнего коммита.
На самом деле, довольно легко увидеть, что представляет из себя этот снимок. Ниже приведен пример получения содержимого каталога и контрольных сумм для каждого файла в HEAD:
$git cat-file -p HEAD
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
author Scott Chacon 1301511835 -0700
committer Scott Chacon 1301511835 -0700
initial commit
$git ls-tree -r HEAD
100644 blob a906cb2a4a904a152... README
100644 blob 8f94139338f9404f2... Rakefile
040000 tree 99f1a6d12cb4b6f19... lib
Команды cat-file и ls-tree являются “служебными” ( plumbing ) командами, которые используются внутри системы и не требуются при ежедневной работе, но они помогают нам разобраться, что же происходит на самом деле.
Индекс – это ваш следующий намеченный коммит. Мы также упоминали это понятие как “область подготовленных изменений” Git – то, что Git просматривает, когда вы выполняете git commit.
Git заполняет индекс списком изначального содержимого всех файлов, выгруженных в последний раз в ваш рабочий каталог. Затем вы заменяете некоторые из таких файлов их новыми версиями и команда ‘git commit’ преобразует изменения в дерево для нового коммита.
$git ls-files -s
100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README
100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb
Повторим, здесь мы используем служебную команду ls-files, которая показывает вам, как выглядит сейчас ваш индекс.
Технически, индекс не является древовидной структурой, на самом деле, он реализован как сжатый список ( flattened manifest ) – но для наших целей такого представления будет достаточно.
Наконец, у вас есть рабочий каталог. Два других дерева сохраняют свое содержимое эффективным, но неудобным способом внутри каталога .git. Рабочий Каталог распаковывает их в настоящие файлы, что упрощает для вас их редактирование. Считайте Рабочий Каталог песочницей, где вы можете опробовать изменения перед их коммитом в индекс (область подготовленных изменений) и затем в историю.
$tree
.
├── README
├── Rakefile
└── lib
└── simplegit.rb
1 directory, 3 files
Основное предназначение Git – это сохранение снимков последовательно улучшающихся состояний вашего проекта, путем управления этими тремя деревьями.

Давайте рассмотрим этот процесс: пусть вы перешли в новый каталог, содержащий один файл. Данную версию этого файла будем называть v1и изображать голубым цветом. Выполним команду git init, которая создаст Git-репозиторий, у которого ссылка HEAD будет указывать на еще несуществующую ветку (master пока не существует).

На данном этапе только дерево Рабочего Каталога содержит данные.
Теперь мы хотим закоммитить этот файл, поэтому мы используем git add для копирования содержимого Рабочего Каталога в Индекс.
Читать дальше