= Git: основные команды
:title-separator: {sp}|
:category: Программирование
:tags: программирование, git
:toc:

== Ссылки

* https://githowto.com/ru/changes_not_files[GitHowTo]
* https://git-scm.com/book/ru/v2[ProGit]
* https://github.com/maxliscia/git-pocket[Git Pocket Guide]

== Установка

В Debian/Ubuntu:

[source,sh]
----
sudo apt-get install git
----

== Термины

[width="100%",cols="18%,20%,62%",options="header",]
|===
| Термин            | Англ                            | Определение
| Рабочий каталог   | working tree, working directory | Набор файлов в текущем каталоге
| Репозиторий       | repository, repo                | Контейнер, хранящий историю изменений файлов проекта
| Индекс            | index, staging area             | Область между рабочим каталогом и репозиторием, в котором осуществляется подготовка к фиксации
| SHA-1             | SHA-1                           | Уникальный идентификатор, отражающий информацию об истории
| Ветка             | branch                          | Именованная последовательность в истории изменений
| Фиксация (коммит) | commit                          | Набор файлов, записанных в историю одновременно
| `HEAD`            | `HEAD`                          | Имя ссылки на последнюю фиксацию в текущей ветке
| Метка             | tag                             | Именованная ссылка на некоторую фиксацию в истории
|===

== Состояния

Файлы в рабочем каталоге могут отслеживаться системой контроля версий
(tracked) или нет (untracked). Отслеживаемые файлы, которые на
<<states,диаграмме>>
обозначены зелёным фоном, могут быть неизменёнными (unmodified),
изменёнными (modified) или подготовленными к фиксации (indexed).


[[states]]
[.text-center]
.Состояния
[plantuml]
----
@startuml
skinparam padding 16

participant untracked  as "Неотслеживамые\n(untracked)"
box "Отслеживаемые"
participant staged     as "Подготовленные к фиксации\n(indexed)" #55FF55
participant unmodified as "Неизменённые\n(unmodified)" #99FF99
participant modified   as "Изменённые\n(modified)" #77FF77
end box

untracked  -> staged:     git add
staged     -> unmodified: git commit
unmodified -> modified:   редактирование
modified   -> staged:     git add
modified   -> untracked:  git rm --cached
unmodified -> untracked:  git rm --cached
staged     -> untracked:  git rm --cached
@enduml
----

Основные команды, осуществляющие взаимодействие между рабочим каталогом,
индексом, локальным и удалённым репозиторием, приведены на <<commands,диаграмме>>.

[[commands]]
[.text-center]
.Команды
[plantuml]
----
@startuml
skinparam padding 16

participant workspace as "Рабочий каталог\n(working dir)"
participant index     as "Индекс\n(index)" #77FF77
participant local     as "Локальный репозиторий\n(local repository)" #FF7777
participant remote    as "Удалённый репозиторий\n(remote repository)" #7777FF

workspace -> local : git commit -a
workspace -> index : git add (-u)
index     -> local : git commit
local     -> remote : git push

== Обновление с сервера ==

remote -> workspace : git pull (rebase)
remote -> local : fetch

== Откат изменений ==
local -[#red]> workspace : git checkout HEAD
index -[#red]> workspace : git checkout

== Сравнение ==
local -[#blue]> workspace : git diff HEAD
index -[#blue]> workspace : git diff

@enduml
----

Пример последовательности действий, выполняемых пользователем в совместном
проекте, приведён на <<workflow,диаграмме>>.

[[workflow]]
[.text-center]
.Последовательность действий
[plantuml]
----
@startuml
skinparam defaultFontSize 24
skinparam padding 16

participant workspace as "Рабочий каталог\n(working dir)"
participant index     as "Индекс\n(index)" #77FF77
participant local     as "Локальный репозиторий\n(local repository)" #FF7777
participant remote    as "Удалённый репозиторий\n(remote repository)" #7777FF

[-> workspace : <font color=red>Начало работы</font>
activate workspace
remote    -> local :      <font color=red>Получение изменений с сервера</font>\n<b>git fetch</b>
remote    -> local :      <font color=red>Обновление подмодулей</font>\n<b>git submodule update --recursive --init</b>
workspace <-> local :     <font color=red>Просмотр информации</font>\n<b>git status</b>
workspace <-> local :     <font color=red>Переход на ветку master</font>\n<b>git checkout master</b>
local     -> workspace :  <font color=red>Слияние с удалённой веткой</font>\n<b>git merge origin/master</b>
local     <-> workspace : <font color=red>Создание новой ветки</font>\n<b>git branch temp</b>
local     <-> workspace : <font color=red>Переход на новую ветку</font>\n<b>git checkout temp</b>
workspace ->o workspace : <font color=red>Редактирование</font>
workspace <-> local :     <font color=red>Просмотр изменений</font>\n<b>git diff</b>
workspace -> index :      <font color=red>Занесение файлов в индекс</font>\n<b>git add</b>
index     -> local :      <font color=red>Фиксация изменений</font>\n<b>git commit</b>
local     ->o local :     <font color=red>Присвоение ветки осмысленного названия</font>\n<b>git branch -m temp branch_name</b>
local     ->o local :     <font color=red>Переход на ветку</font>\n<b>git checkout branch_name</b>
remote    -> local :      <font color=red>Получение изменений с сервера</font>\n<b>git fetch</b>
local     ->o local :     <font color=red>Слияние изменений с сервера в текущую ветку (branch_name)</font>\n<b>git merge origin/master</b>
local     -> remote :     <font color=red>Отправка ветки на сервер</font>\n<b>git push origin branch_name</b>
remote    ->] :           <font color=red>Создание запроса на слияние</font>
deactivate workspace
@enduml
----

== Настройка

[width="100%",cols="15%,35%,50%",options="header",]
|===
| Команда      | Ключи                                    | Описание
| `git config` | `--global user.name "John Doe"`          | Имя текущего пользователя
| `git config` | `--global user.email "mail@example.com"` | Почта текущего пользователя
| `git config` | `--list`                                 | Вывод текущей конфигурации
| `git config` | `--global --list`                        | Вывод глобальной конфигурации
|===

== Инициализация

[width="100%",cols="15%,35%,50%",options="header",]
|===
| Команда     | Ключи                          | Описание
| `git init`  | `<dir>`                        | Создать пустой репозиторий в каталоге `<dir>`
| `git clone` | `<giturl>` `<dir>`             | Создать в каталоге `<dir>` копию репозитория, находящегося по адресу `<giturl>`
| `git clone` | `--recursive <giturl>` `<dir>` | Создать в каталоге `<dir>` копию репозитория, находящегося по адресу `<giturl>`, с учётом подмодулей
|===

== Подмодули

[width="100%",cols="15%,25%,60%",options="header",]
|===
| Команда         | Ключи                         | Описание
| `git submodule` | `add <giturl> <dir>`          | Добавить в каталог `<dir>` текущего репозитория подмодуль, находящийся по адресу `<giturl>`
| `git submodule` | `update --recursive --remote` | Обновить подмодули
| `git submodule` | `sync --recursive`            | Заменить адреса подмодулей на указанные в файле `.gitmodules`
|===

Удаление подмодуля:

[source,sh]
----
git submodule deinit <path/to/submodule>
git rm <path/to/submodule>
----

== Фиксация

[width="100%",cols="15%,20%,65%",options="header",]
|===
| Команда      | Ключи        | Описание
| `git add`    | `<filename>` | Подготовить файл `<filename>` к фиксации
| `git commit` |              | Зафиксировать подготовленные файлы
| `git commit` | `-a`         | Зафиксировать все отслеживаемые файлы, которые были изменены
|===

== Удаление

[width="100%",cols="15%,20%,65%",options="header",]
|===
| Команда  | Ключи                 | Описание
| `git rm` | `<filename>`          | Удалить файл из индекса и рабочего каталога
| `git rm` | `-f <filename>`       | Принудительное удаление файла
| `git rm` | `--cached <filename>` | Удаление файла из проекта, но не из рабочего каталога
|===

== Информация

[width="100%",cols="15%,20%,65%",options="header",]
|===
| Команда        | Ключи       | Описание
| `git status`   | `-s`        | Вывод информации о рабочем каталоге в краткой форме
| `git log`      | `--oneline` | Вывод журнала изменений в краткой форме
| `git ls-files` |             | Вывод списка отслеживаемых и подготовленных файлов
|===

== Удалённый репозиторий

[width="100%",cols="15%,20%,65%",options="header",]
|===
| Команда      | Ключи                | Описание
| `git remote` | `-v`                 | Список адресов удалённых репозиториев
| `git branch` | `-r`                 | Список веток в удалённых репозиториях
| `git remote` | `add <name> <url>`   | Создать ссылку `<name>` на удалённый репозиторий, находящийся по адресу `<url>`
| `git remote` | `rename <old> <new>` | Переименовать ссылку `<old>` на `<new>`
| `git remote` | `rm <name>`          | Удалить ссылку `<name>`
|===

* Обращение к удалённому репозиторию осуществляется по ссылке,
создаваемой командой `git remote`
* Команда `git clone` автоматически создаёт ссылку `origin`

== Отправка изменений

[width="100%",cols="15%,20%,65%",options="header",]
|===
| Команда    | Ключи                   | Описание
| `git push` | `<remote> <branch>`     | Отправить ветку `<branch>` в удалённый репозиторий `<remote>`
| `git push` | `<remote> --all`        | Отправить все ветки в удалённый репозиторий `<remote>`
| `git push` | `--d <remote> <branch>` | Удалить ветку `<branch>` из удалённого репозитория `<remote>`
|===

== Получение изменений

[width="100%",cols="15%,20%,65%",options="header",]
|===
| Команда     | Ключи               | Описание
| `git fetch` | `<remote>`          | Получить изменения из всех веток репозитория `<remote>`, но не выполнять слияние
| `git fetch` | `<remote> <branch>` | Получить изменения из ветки `<branch>` репозитория `<remote>`, но не выполнять слияние
| `git merge` | `<remote>/<branch>` | Выполнить слияние с веткой `<branch>` репозитория `<remote>`
| `git pull`  | `<remote>`          | Получение и слияние
|===

== Ветки

[width="100%",cols="15%,20%,65%",options="header",]
|===
|Команда |Ключи |Описание
| `git branch`   | `-a`             | Список локальных и удалённых веток
| `git branch`   |                  | Список локальных веток
| `git branch`   | `<branch>`       | Создать ветку `<branch>`
| `git checkout` | `<sha-1>`        | Перейти к фиксации с идентификатором `<sha-1>`
| `git branch`   | `-m <old> <new>` | Переименовать ветку `<old>` в `<new>`
| `git merge`    | `<branch>`       | Слить изменения из ветки `<branch>` в текущую ветку
| `git branch`   | `-d <branch>`    | Удалить ветку `<branch>`
|===

== Сравнение

[width="100%",cols="15%,20%,65%",options="header",]
|===
| Команда        | Ключи             | Описание
| `git diff`     |                   | Сравнить рабочий каталог и индекс
| `git diff`     | `–-cached`        | Сравнить индекс и последнюю фиксацию
| `git diff`     | `HEAD`            | Сравнить последнюю фиксацию и рабочий каталог
| `git diff`     | `--stat`          | Краткий вывод результатов
| `git diff`     | `<sha-1> <sha-1>` | Сравнить две точки с указанными идентификаторами
| `git diff`     | `<dir>` `<file>`  | Сравнивать только указанный каталог `<dir>` или файл `<file>`
| `git difftool` |                   | Отобразить результаты сравнения в программе, определяемой переменной `diff.tool`
|===