Перейти к содержанию

GIT

Git - распределенная система контроля версий, потому что в ней не требуется центральный сервер, у каждого разработчика локальная версия репозитория. В реальных проектах используют сервер для удобства обмена данными, сервер не выполняет никакой умной работы, это только центральный пункт обмена данными.

git-bash-prompt oh-my-zsh

Команды

Что куда перемещает — карта четырёх областей:

graph LR
  W["Рабочая<br/>директория"] -->|git add| I["Индекс<br/>staging"]
  I -->|git commit| L["Локальный<br/>репозиторий"]
  L -->|git push| R["Remote"]
  R -->|git fetch| L
  L -->|"git switch"| W
  I -->|"git restore"| W

Дальше команды по группам: заголовок — сама команда, таблица под ним — её флаги и формы.


Настройка

git config

Читает и пишет настройки. Уровень задаётся флагом, ближний перебивает дальний.

Флаг Область действия
--system все пользователи машины
--global текущий пользователь
--local текущий репозиторий, по умолчанию
--list показать, что в итоге собралось
git config --global user.name "Name"
git config --global user.email "email@example.com"

Репозиторий

git init

Создаёт пустой репозиторий в текущей директории.

git clone

git clone <url> — забирает удалённый репозиторий вместе со всей историей.


Состояние и различия

git status

Состояние рабочей директории и индекса: отслеживаемые и неотслеживаемые файлы, готовое к коммиту, состояние ветки, конфликты слияния.

Флаг Что делает
-s, --short краткий формат
-b, --branch ветка и её связь с удалённой
-v, --verbose подробности, повторный флаг увеличивает детализацию
--long полный формат, он же по умолчанию

git diff

Показывает различия. Что с чем сравнивать, задаётся аргументом.

Форма Сравнивает
git diff рабочую директорию с индексом
git diff --staged индекс с последним коммитом, --cached — синоним
git diff HEAD рабочую директорию с последним коммитом
git diff <commit> рабочую директорию с указанным коммитом
git diff <commit1> <commit2> два коммита
git diff <branch1> <branch2> две ветки

Индекс и коммиты

git add

git add <file> — переносит изменения из рабочей директории в индекс.

Форма Что добавляет
git add . всё в текущей директории
git add -A все изменения: добавления, удаления, перемещения
git add -u только уже отслеживаемые файлы

git commit

Фиксирует подготовленные изменения в истории.

Флаг Что делает
-m "текст" сообщение без открытия редактора
-am "текст" -a добавляет отслеживаемые файлы, заменяя git add .
--amend переписать последний коммит: сообщение или забытые файлы
--no-edit не открывать редактор для сообщения
--date=now перезаписать дату
--author="Name <email>" сменить автора
--reset-author сбросить автора на текущего

Ветки

git branch

Без аргументов показывает локальные ветки. С именем создаёт новую от текущего коммита, но не переключает на неё.

Форма Что делает
git branch список локальных веток
git branch <branch> создать ветку от текущего коммита
git branch -d <branch> удалить, только если изменения куда-то слиты
git branch -D <branch> удалить принудительно

git switch и git checkout

Две равнозначные команды для переключения. switch появился позже и умеет только это, checkout перегружен и делает ещё десяток вещей.

git switch <branch>       # переключиться
git switch -c <branch>    # создать и переключиться
git checkout <branch>     # переключиться
git checkout -b <branch>  # создать и переключиться

Слияние и перенос

git merge

git merge <branch> — вливает изменения указанной ветки в текущую.

git rebase

git rebase <branch> — переносит коммиты текущей ветки поверх указанной. git rebase -i HEAD~3 — интерактивно по последним трём коммитам.

rebase переписывает историю

На ветке, которую уже забрал кто-то ещё, rebase и amend ломают чужие клоны: коммиты меняют хэши. На общих ветках отменяй через git revert, историю переписывай только у себя.

git cherry-pick

git cherry-pick <commit> — переносит отдельный коммит из другой ветки в текущую.

Форма Что берёт
git cherry-pick <branch>~2 предпоследний коммит ветки
git cherry-pick abc1234..def5678 все коммиты диапазона, исключая первый

История

git log

История коммитов.

Флаг Что делает
--oneline по строке на коммит
--graph ASCII-граф ветвлений
--decorate показывает ветки и теги
--pretty=format:"%h - %an, %ar : %s" свой формат вывода

Читаемый граф целиком:

git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all

git show

git show <commit> — содержимое коммита.

Форма Что показывает
git show abc123 по хэшу, хватает первых 6–7 символов
git show HEAD~2 предпредпоследний коммит
git show <branch> последний коммит ветки
git show abc123..def456 сравнение двух коммитов
git show 123abc:src/app.js файл в состоянии этого коммита

git blame

git blame <file> — кто и когда последним менял каждую строку файла.


Отмена изменений

git revert

git revert <commit> — создаёт новый коммит, отменяющий указанный. Историю не переписывает, поэтому безопасен на общих ветках.

git reset

git reset <commit> — перемещает текущую ветку на указанный коммит. В отличие от revert переписывает историю: коммиты после указанного могут исчезнуть из ветки.

Режим HEAD Индекс Рабочие файлы
--soft сброшен сохранён сохранены
--mixed сброшен сброшен сохранены
--hard сброшен сброшен сброшены

git reset @~2 — снять последние два коммита.

Промахнулся — коммиты обычно ещё живы:

git reflog              # найти старый хэш
git reset <старый-хэш>  # вернуться к нему

git restore

git restore <file> — отменяет незакоммиченные изменения в рабочих файлах, убирает файлы из индекса, восстанавливает файлы из определённого коммита.

git clean

git clean -dxf — удаляет неотслеживаемые файлы из рабочей директории.

Флаг Что делает
-n пробный запуск: показать, что будет удалено
-f реально удалить, без флага команда не работает
-d захватывать и неотслеживаемые директории
-x удалять и игнорируемые файлы из .gitignore
-X удалять только игнорируемые
-i интерактивный режим

reset --hard и clean -f ничего не спрашивают

--hard затирает незакоммиченные изменения, clean -f удаляет файлы мимо корзины. Перед clean прогоняй -n: покажет список, ничего не тронув.


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

git remote

Управляет списком удалённых репозиториев.

Форма Что делает
git remote список подключённых
git remote -v то же самое с URL
git remote add <name> <url> подключить новый

git fetch

git fetch <remote> — забирает изменения с сервера, не трогая рабочую ветку.

git pull

git pull <remote> <branch> — fetch плюс слияние в текущую ветку.

git push

git push <remote> <branch> — отправляет коммиты на сервер. git push -u <remote> <branch> — отправляет и связывает ветку с удалённой, дальше хватает голого git push.


Сохранение временных изменений

git stash

Временно прячет незакоммиченные изменения, чтобы переключиться на другую ветку или выполнить другие операции, и возвращает их потом.

Команда Что делает
git stash push -m "..." сохранить с описанием
git stash list список сохранённого
git stash pop вернуть последнее и удалить из stash
git stash apply <stash> вернуть конкретное, оставив в stash
git stash drop stash@{1} удалить конкретное
git stash clear удалить всё

Дополнительные

git submodule

Команда Что делает
git submodule add <url> подключить внешний репозиторий подмодулем
git submodule update --init --recursive подтянуть подмодули после клонирования

git reflog

История всех перемещений HEAD, включая «удалённые» коммиты. Главный способ откатить неудачный reset.

git bisect

Бинарный поиск коммита, который сломал.

git gc

Очистка репозитория: упаковать объекты, убрать старые.

git fsck

Проверка целостности репозитория.

git help

git help <команда> — справка по команде.

Области GIT

  1. Working directory

Файлы, которые лежат в файловой системе

  1. Index (в .git/index)

Содержит изменения, которые будут включены в следующий коммит.

Контролирует, какие изменения попадут в следующий коммит

  1. Repository (в .git) - база данных всех версий проекта

Содержит полную историю коммитов, веток, тегов

.git

.github

.gitattribute

Сброс кэша

Если .gitignore не применяется - значит есть файлы которые git уже отслеживает. Нужно удалить файлы из индекса

git rm -r --cached .
git add .
git commit -m "Restore cached + .gitignore"
git push

Как писать хорошие коммиты

Источники

В качестве основы используется Angular Git commit Message Convention - это наиболее авторитетный источник. Все остальные вариации конвенций по коммитам ссылаются на эту.

Также достаточно авторитетным источником является conventionalcommits.org

Шаблон коммита

Для оформления сообщения коммита следует использовать следующий шаблон:

<type>(<scope>): <description>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

Type, scope и description вместе составляют заголовок коммита (header).

  • Type - тип коммита (рефакторинг, исправление багов, новая фича и т.п.)
  • Scope - область действия (где были изменения). Это может быть отдельный файл, директория или затронутая часть проекта (rendering, routing и т.д.). Не обязательно для заполнения (но желательно).
  • Description - описание сути коммита. Обычно отвечает на вопрос "что было изменено/добавлено/удалено?" Например: add comment section
  • Blank line - пустая строка, ей отделяется тело коммита от заголовка, и тело от футера.
  • Body - не обязательно для заполнения. Здесь обычно отвечают на вопрос "Зачем были изменения?" и "Почему сделаны именно такие изменения?" (почему не стоит делать по-другому).
  • Footer - не обязательно для заполнения. Может содержать информацию о критических изменениях (breaking changes), а также является местом для указания задач из бэклога, GitHub issues, тикетов, и других проблем, которые этот коммит закрывает или с которыми он связан.

Пример коммита

chore: drop Node 6 from testing matrix

see the issue for details on the typos fixed

BREAKING CHANGE: dropping Node 6 which hits end of life in April
closes issue #12

Примеры заголовков коммитов

Плохо:

Changed render method in Block

Лучше:

refactor: Changed render method in Block

Хорошо:

refactor(Block.ts): update render method

Несколько коротких правил

  1. Коммиты пишутся на английском языке.
  2. Заголовок коммита пишется с маленькой буквы.
  3. Точка в конце не ставится.
  4. Длина заголовка не должна превышать 100 символов, а лучше 50. Подробности коммита выносятся в тело и футер.
  5. Description начинается с глагола. Глагол указывается в настоящем времени, например: add, update, improve, remove (не added, updates) и тд.

Как писать коммит при Pull Request

  1. Сообщение коммита при merge PR формируется по такому же принципу как описано выше.
  2. В конец заголовка коммита включается номер PR в скобочках после основного сообщения. Например: refactor(Block.ts): update render method (#67)
  3. Все сообщения коммитов из сливаемой ветки вносятся в тело коммита.

docs(readme.md): add documentation about project (#3)

* docs(workFlow.md): fix name of developing branch
* chore(package.json): add commitlint to devDependencies
  Some extra notes.

Тип коммита

  • feat - используется при добавлении новой функциональности.
  • fix - исправление багов.
  • refactor - изменения кода, которые не исправляет баги и не добавляют функционал.
  • chore - изменение конфигов, системы сборки, обновление зависимостей и т.д.
  • test - всё, что связано с тестированием.
  • style - исправление опечаток, изменение форматирования кода (переносы, отступы, точки с запятой и т.п.) без изменения смысла кода.
  • docs - изменения только в документации.

Эти типы расширяют вышеописанные, но их использовать не обязательно:

  • perf - изменения кода, повышающие производительность.
  • build - изменения, влияющие на систему сборки или внешние зависимости (webpack, npm).
  • ci - изменения в файлах конфигурации.

BREAKING CHANGE (критические изменения)

BREAKING CHANGE: указывается в футере и автоматически добавляется в конец заголовка. Критические изменения - это изменения, нарушающие обратную совместимость. Может быть частью коммита любого типа.

Должен начинаться с фразы BREAKING CHANGE:, за которой следует краткое изложение критического изменения, пустая строка и подробное описание критического изменения.

Как правильно создавать ветки и вести репозиторий

  • Git Flow
  • GitLab Flow
  • GitРги Flow
  • Trunk-Based Development
  • Forking Workflow
  • Centralized Workflow