### Снимки состояний, а не изменений
Каждый раз, когда вы создаете новую версию или сохраняете состояние проекта в Git, по сути, делается снимок всех файлов в конкретный момент времени и сохраняется ссылка на этот снимок. Для повышения продуктивности вместо файлов, которые не претерпели изменений, сохраняется всего лишь ссылка на их ранее сохраненные версии. Git воспринимает данные скорее как поток снимков состояния (stream of snapshots).
### Три состояния
Файлы в Git могут находиться в трех основных состояниях: зафиксированном, модифицированном и индексированном. Зафиксированное (committed) состояние означает, что данные надежно сохранены в локальной базе. Модифицированное (modified) состояние означает, что изменения уже внесены в файл, но пока не зафиксированы в базе данных. Индексированное (staged) состояние означает, что вы пометили текущую версию модифицированного файла как предназначенную для следующей фиксации.
###Первая настройка Git
Система Git поставляется с инструментом git config, позволяющим получать и устанавливать переменные конфигурации, которые задают все аспекты внешнего вида и работы Git. Эти переменные хранятся в разных местах.
* Файл /etc/gitconfig содержит значения, действующие для всех пользователей системы и всех их репозиториев. Указав параметр --system при запуске git config, вы добьетесь чтения и записи для этого конкретного файла.
* Файл ~/.gitconfig или ~/.config/git/config связан с конкретным пользователем. Чтение и запись для этого файла инициируются передачей параметра --global.
* Параметры конфигурационного файла в папке Git (то есть .git/config) репозитория, с которым вы работаете в данный момент, действуют только на конкретный репозиторий.
### Ваш идентификатор
При установке Git первым делом следует указать имя пользователя и адрес электронной почты. Это важно, так как данную информацию Git будет включать в каждую фиксируемую вами версию, и она обязательно включается во все создаваемые вами коммиты (зафиксированные данные):
```
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
```
Передача параметра --global позволяет сделать эти настройки всего один раз, так как в этом случае Git будет использовать данную информацию для всех ваших действий в системе. Если для конкретного проекта требуется указать другое имя или адрес электронной почты, войдите в папку с проектом и выполните эту команду без параметра --global.
### Выбор редактора
```
git config --global core.editor vim
```
### Проверка настроек
```
$ git config --list
```
### Просмотр индексированных и неиндексированных изменений
Команда git diff без дополнительных параметров позволяет посмотреть, что было изменено, но пока не проиндексировано. Эта команда сравнивает содержимое в рабочей папке и в области индексирования. Она выводит список изменений, которые вы внесли, но пока не проиндексировали.
Чтобы посмотреть, что из проиндексированного войдет в следующий коммит, воспользуйтесь командой git diff --staged. Эта команда сравнивает индексированные изменения с содержимым последней зафиксированной версии.
А команда git diff --cached покажет проиндексированные изменения.
### Пропуск области индексирования
Хотя область индексирования помогает получить именно ту версию состояния, котораявам требуется, иногда она чрезмерно усложняет рабочий процесс. Впрочем, в Git есть простой способ обойтись без этой области. Достаточно передать команде git commit параметр -a, и система Git начнет автоматически индексировать все отслеживаемые файлы перед их фиксацией, позволяя обойтись без команды git add.
```
$ git commit -a -m 'added new benchmarks'
```
### Удаление файлов
Чтобы система Git перестала работать с файлом, его нужно удалить из числа отслеживаемых (точнее, убрать из области индексирования) и зафиксировать данное изменение. Это делает команда git rm, которая заодно удаляет указанный файл из рабочей папки, благодаря чему он исчезает из списка неотслеживаемых.
Иногда требуется оставить файл в рабочей папке, удалив его из области индексирования. Другими словами, нужно, чтобы файл остался на своем месте, но система Git перестала за ним следить. В этом случае на помощь приходит параметр --cached:
```
$ git rm --cached README
```
### Отмена индексирования
С параметром --hard команда git reset может привести к опасным последствиям, так как в этом случае затрагиваются файлы в рабочей папке. Без этого параметра команда git reset совершенно безопасна, так как затрагивает только область индексирования.
Важно понимать степень опасности команды git checkout -- [файл]. Все внесенные в файл изменения пропадают — вы просто копируете в этот файл содержимое другого файла. Никогда не пользуйтесь этой командой, если не уверены, что данный файл вам больше не понадобится.
### Извлечение данных из удаленных репозиториев
```
$ git fetch [имя удаленного репозитория]
```
Эта команда связывается с удаленным проектом и извлекает оттуда все пока отсутствующие у вас данные.
Команда git fetch origin извлекает все, что появилось на этом сервере после его клонирования (или после момента последнего извлечения информации). Важно понимать, что команда git fetch помещает все данные в ваш локальный репозиторий, — она не выполняет автоматическое слияние с ветками, с которыми вы работаете в данный момент, и вообще никак не затрагивает эти ветки. Слияние вы выполните вручную, как только в этом возникнет необходимость.
Если же у вас есть ветка, настроенная на слежение за какой-то удаленной веткой, команда git pull будет автоматическиизвлекать информацию из удаленной ветки и выполнять слияние с текущей веткой.В общем случае команда git pull извлекает данные с сервера, который вы клонировали, и автоматически пытается слить их с вашим текущим рабочим кодом.
### Просмотр удаленных репозиториев
Для получения дополнительной информации о конкретном удаленном репозитории применяется команда git remote show [имя удаленного сервера].
### Удаление и переименование удаленных репозиториев
Переименование ссылок осуществляется командой git remote rename, меняющей сокращенные имена удаленных репозиториев. К примеру, вот как выглядит присвоение репозиторию pb имени paul:
```
$ git remote rename pb paul
$ git remote
origin
paul
```
## Теги
Для просмотра списка доступных тегов применяется команда git tag:
```
$ git tag
v0.1
v1.3
```
### Создание тегов
В Git используются два основных типа тегов: легковесные и снабженные комментарием.Легковесный
тег (lightweight tag) во многом напоминает не меняющуюся ветку — это просто указатель на конкретный коммит. А вот теги с комментариями (annotated tags) хранятся в базе данных Git как полноценные объекты. Они обладают контрольной суммой; содержат имя человека, поставившего тег, адрес его электронной почты и дату создания; снабжены комментарием; могут быть подписаны и проверены в программе GNU Privacy Guard (GPG). Обычно рекомендуется создавать именно теги с комментариями, чтобы у вас была вся эта информация, но если нужно сделать временный тег или по какой-то причине вы не хотите хранить все эти сведения, можно обойтись и легковесными тегами.
```
git tag -a v1.4 -m 'my version 1.4'
```
Параметр -m задает сообщение, которое будет храниться вместе с тегом. Если вы не укажете это сообщение, Git запустит редактор, чтобы вы смогли его ввести.
Для просмотра данных тега вместе с помеченным им коммитом служит команда git show:
```
$ git show v1.4
```
**Легковесные теги**
Другим средством пометки коммитов являются легковесные теги. По сути, это сохраненная в файле контрольная сумма коммита — больше никакой информации они не содержат. Для создания легковесного тега достаточно опустить параметры -a, -s и -m:
### Расстановка тегов постфактум
Это можно сделать указав в конце команды контрольную сумму коммита (или ее часть):
```
$ git tag -a v1.2 9fceb02
```
### Обмен тегами
По умолчанию команда git push не отправляет теги на удаленные серверы. Созданные вами теги нужно отправлять на сервер общего доступа отдельно. Этот процесс напоминает совместное использование удаленных веток — вы делаете это командой git push origin [имя тега].
```
$ git push origin v1.5
```
Когда требуется переслать сразу много тегов, добавляйте к команде git push параметр --tags.
### Псевдонимы в Git
При неполном вводе команды Git не пытается догадаться, что за команду вы имели в виду. Но если мысль о вводе длинных команд вас не привлекает, команда git config позволяет легко создать псевдоним для любой из них. Вот пара примеров ее применения:
```
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
```
Теперь вместо команды git commit достаточно будет ввести git ci.
Кроме того, эта техника позволяет создавать команды, которых, с вашей точки зрения, не хватает.
```
$ git config --global alias.unstage 'reset HEAD --'
```
### Удаленные ветки
Удаленные ветки (remote branches) представляют собой ссылки на состояния веток в удаленных репозиториях. Перемещать их локально вы не можете; они смещаются автоматически при каждом подключении по сети. Удаленные ветки работают как закладки, напоминающие, где в удаленных репозиториях находились соответствующие ветки во время вашего последнего подключения к ним.
Имя ветки «origin», как и имя «master», в Git не несет особого значения. Имя master широко распространено потому, что оно по умолчанию присваивается ветке, порождаемой командой git init, а имя origin по умолчанию присваивается удаленной ветке, порождаемой командой git clone. Если написать git clone -o booyah, по умолчанию вы будете работать с удаленной веткой booyah/master.
### Получение данных с последующим слиянием
Команда git fetch забирает с сервера всю пока отсутствующую у вас новую информацию, на состояние рабочей папки она никак не влияет. Она всего лишь предоставляет данные, которые можно подвергнуть слиянию. Но существует и команда git pull, по сути, представляющая собой команду git fetch, за которой немедленно следует команда git merge.
### Ликвидация веток с удаленного сервера
```
$ git push origin --delete serverfix
```
эта команда просто удаляет с сервера указатель. Как правило, Git-сервер хранит данные, пока в дело не вступит сборщик мусора, поэтому, в случае ошибочного удаления, информацию зачастую легко восстановить.
### Основы cлияния данных
Простейшим средством объединения двух веток является команда merge. Она в три шага выполняет слияние последних снимков состояния из разных веток (C3 и C4) и последнего общего предка этих состояний (C2), генерируя при этом новый снимок состояния (и коммит).

Но существует и другой способ: можно взять фрагмент изменений, появившийся в коммите C4, и применить его поверх коммита C3. В Git эта операция называется перемещением (rebasing). Команда rebase позволяет взять изменения, зафиксированные в одной ветке, и повторить их в другой.
```
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
```
Это работает следующим образом: берётся общий родительский снимок двух веток (текущей, и той, поверх которой вы выполняете перебазирование), определяется дельта каждого коммита текущей ветки и сохраняется во временный файл, текущая ветка устанавливается на последний коммит ветки, поверх которой вы выполняете перебазирование, а затем по очереди применяются дельты из временных файлов.

После этого вы можете переключиться обратно на ветку master и выполнить слияние перемоткой.
```
$ git checkout master
$ git merge experiment
```
Теперь снимок, на который указывает C4' абсолютно такой же, как тот, на который указывал C5 в примере с трёхсторонним слиянием. Нет абсолютно никакой разницы в конечном результате между двумя показанными примерами, но перебазирование делает историю коммитов чище. Если вы взглянете на историю перебазированной ветки, то увидите, что она выглядит абсолютно линейной: будто все операции были выполнены последовательно, даже если изначально они совершались параллельно.
### Более интересные варианты перемещений
Можно сделать так, чтобы воспроизведение результатов перемещения начиналось не с ветки, куда они были перемещены. Вы создаёте тематическую ветку server, чтобы добавить в проект некоторую функциональность для серверной части, и делаете коммит. Затем вы выполнили ответвление, чтобы сделать изменения для клиентской части, и создали несколько коммитов. Наконец, вы вернулись на ветку server и сделали ещё несколько коммитов.

Предположим, вы хотите внести изменения клиентской части в окончательную версию кода, оставив изменения серверной части для дальнейшего тестирования. Взять изменения клиентской части (коммиты C8 и C9), не связанные с изменениями на серверной стороне, и воспроизвести их в ветке master позволяет команда git rebase с параметром --onto:
```
$ git rebase --onto master server client
```
### Зафиксировать работу, сделанную наполовину
В такой ситуации используйте
```
git stash
```
Команда git stash сохраняет неподтвержденные изменения (индексированные и неиндексированные) в отдельном хранилище, чтобы вы могли вернуться к ним позже. Затем происходит откат до исходной рабочей копии
как вернуть спрятанные в буфер изменения в рабочее состояние
```
$ git stash apply
```