Введение

Что такое Git

Git — это VCS (version control system) — система, записывающая изменения файлов и позволяющая вернуться позже к определённой версии.

VCS можно разделить на централизованные и распределенные. Git относится ко второй категории.

В распределенных VCS у каждого разработчика локально хранится репозиторий (проект с файлами) с полной историей всех изменений в проекте. В такой схеме разработчики полностью независимы от удаленного сервера.

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

Как получить помощь

Эти команды работают даже без подключения к сети.

git help <команда> (или git <команда> --help) Открыть страницу руководства по любой команде Git.

git <команда> -h Вывести список опций для команды с коротким описанием.

Общие команды для работы с файлами

cat <file> Просмотр содержимого файла.

mkdir <name> Создание каталога (папки).

touch <file> Создание файла.

cd <name> Переход в каталог.

cd .. Выход из каталога.

rm <file> Удаление файла.

rm -r <file> Позволяет удалить директорию (папку).

Навигация в Git Bash

"Листалка по умолчанию", представленная двоеточием в нижнем левом углу Git Bash — программа LESS, которая позволяет выводить постранично информацию на экран. Основные команды:

  1. / Поиск по строке или регулярному выражению
    • n Поиск вперед (прокрутка вниз)
    • shift + n Поиск назад (прокрутка вверх)
  2. q Выход из программы

Состояние файлов в Git

Файлы в рабочем каталоге могут быть tracked (под версионным контролем) и untracked (не под версионным контролем).

Отслеживаемые файлы могут находиться в одном из трех состояний: modified (изменён), staged (индексирован) и committed (зафиксирован).

Жизненный цикл состояния файлов

Каждый Git проект имеет три секции:

Working Directory — директория для редактирования файлов.

Staging Area (область индексирования или Индекс) — файл, в котором содержится информация о том, что попадёт в следующий коммит.

Repository (каталог Git) — место, где Git хранит метаданные и базу объектов всего проекта.

Секции проекта Git

Конфигурация

Команда git config позволяет настраивать параметры конфигурации Git, которые можно задать на трех уровнях:

  1. --system Сохраняет общие для всех пользователей параметры в установочный файл /etc/gitconfig.
  2. --global Сохраняет параметры настроек пользователя в файл C:\Users\<username>\.gitconfig.
  3. [--local] Сохраняет параметры для конкретного проекта в файл <project>/.git/config.

git config <name> Получить значение настройки по имени.

git config <name> <value> Установить параметр name со значением value.

git config --unset <name> Удалить параметр.

git config --list Список значений всех установленных настроек.

git config --global -e Открыть для редактирования глобальный файл настроек.

Примеры

git config --global user.name "Sergey Des" Установить имя пользователя глобально.

git config --global core.editor "code -w" Сделать VS Code редактором по умолчанию.

git config --global log.date format-local:'%Y-%m-%d %H:%M:%S' Изменить формат вывода даты по умолчанию.

git config --global grep.patternType perl Сделать регулярные выражения Perl-совместимыми по умолчанию.

git config --global commit.verbose true По умолчанию добавлять в комментарий git commit изменения diff.

git config merge.ff false Запретить слияние Fast-forward (аналог флага --no-ff).

git config --global branch.master.mergeoptions '--no-ff' Запретить Fast-forward для ветки master.

git config --global core.autocrlf true Конвертировать переносы строк CRLF в LF.

Перевод строки в Windows кодируется двумя байтами 0d 0a, обозначаемыми как CRLF (carriage return + line feed), соответствует символам \r\n. Unix-системы (Mac, Linux), а также Git-репозиторий кодируют перевод строки одним байтом 0a (LF), поэтому на Mac и Linux core.autocrlf ставят в другое значение (input или false).

git config rerere.enabled true Включить reuse recorded resolution (запоминать, как были разрешены конфликты, чтобы при возникновении такого же конфликта снова они были разрешены автоматически).

git config pretty.my format:'%C(yellow)%h %C(dim green)%cd %C(cyan)%s%d %C(#667788)[%an]' Добавить формат вывода.

git config format.pretty my И сделать его форматом по умолчанию.

Псевдонимы

git config alias.<name> <command> Добавить псевдоним name для команды command.

git config alias.<name> '!<first>; <second>' Добавить псевдоним для нескольких команд.

git config --list | grep alias Вывести список всех псевдонимов.

Примеры

git config --global alias.last 'log -1 HEAD' Назначить глобальный псевдоним last для вывода текущего коммита (HEAD указывать не обязательно).

git config alias.sayhi '!echo "hello"; echo "from git"' Назначить псевдоним, который будет выводить hello, а затем, на следующей строке, from git.

git config --global alias.lg "log --pretty=format:'%C(#f3f89d)%h %C(#418d61)%cd %C(reset)|%C(#F78972)%d %C(#9aedf1)%s %C(#667788)[%an]' --date=format:'%F %R'" Задать псевдоним для красивого вывода git log.

Файл .gitignore

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

К шаблонам в файле .gitignore применяются следующие правила:

  • Пустые строки, а также строки, начинающиеся с #, игнорируются
  • Стандартные шаблоны являются глобальными и применяются рекурсивно для всего дерева каталогов
  • Чтобы избежать рекурсии, используется слеш / в любом месте кроме конца шаблона
  • Чтобы применять правила только к каталогам, добавляется слеш / в конец шаблона
  • * соответствует нулю или более символам в имени одного файла или директории
  • ** соответствует произвольному пути, но не части имени
  • [abc] соответствует любому символу из указанных в скобках
  • ? соответствует одному произвольному символу
  • [0-9] соответствуют одному символу из диапазона
  • a/**/z указывает на то, что могут быть вложенные каталоги (например, a/z, a/b/z, a/b/c/z, и тд)
  • ! отменяет игнорирование, если только каталог с этим файлом не игнорируется целиком
Примеры

*.a Исключить все файлы с расширением .a.

!lib.a Но отслеживать файл lib.a даже если он подпадает под исключение выше.

doc/**/*.txt Игнорировать все .txt файлы в каталоге doc/.

Вспомогательные команды

git check-ignore -v <file> Если файл попадает под правило в .gitignore, выводит строку с шаблоном, который за это отвечает (номер строки обернут в двоеточие).

Чтобы применить шаблоны в .gitignore к уже отслеживаемым файлам, необходимо выполнить команды git rm --cached <file> + git commit.

git update-index --skip-worktree <file> Временнно прекратить отслеживание файла в репозитории.

git update-index --no-skip-worktree <file> Возобновить отслеживание.

git ls-files -v . | findstr "^S" Найти все временно неотслеживаемые файлы.

.git/info/exclude

Правила игнорирования, которые не должны передаваться в репозиторий, можно указать в файле <project>/.git/info/exclude.

Основы Git

Создание Git-репозитория

git init Создает пустой Git-репозиторий.

git clone <url> Клонирует репозиторий, добавляя его под именем origin.

rm -rf .git Удаляет локальный репозиторий.

Отслеживание изменений

git add

git add <file> Добавить под версионный контроль новый файл или индексировать измененный.

git add -p <file> Индексировать только часть изменений в файле. Для каждого измененного фрагмента можно выбрать y (yes), n (no) или другие варианты (можно посмотреть, введя ?).

git add -f <file> Добавить файл в Индекс даже если он игнорируется .gitignore.

git add . Добавить в Индекс все изменения в текущей директории.

git add -A Добавить в Индекс все изменения, начиная с корня проекта.

git add -u Добавить в Индекс все изменения в отслеживаемых файлах, начиная с корня проекта.

git status

git status Отображает, состояние каких файлов изменилось с момента последнего коммита.

git status --short (или -s) Отображает результат git status в виде двух столбцов, в левом указывается статус файла, а в правом модифицирован ли он после этого. Неотслеживаемые файлы помечены ??, файлы в Индексе как A, измененные M и тд.

Коммит

git commit Фиксирует изменения в репозитории из Индекса. Открывает редактор с пустой строкой сверху и закомментированным результатом работы git status.

git commit -C <hash> Делает коммит, беря описание и автора из уже существующего коммита hash. С флагом откроется редактор для изменения описания. Может использоваться после git reset --soft @~ когда в последний коммит забыли добавить какие-то изменения, при этом вместо hash обычно указывается ORIG_HEAD. С флагом --reset-author берет из hash только сообщение.

git commit --amend Заменяет последний коммит, применяя изменения из Индекса и открывает редактор с сообщением из последнего коммита. Соответствует командам git reset --soft @~ + git commit -c ORIG_HEAD. С флагом --reset-author делает текущего коммитера автором. С флагом --no-edit отменяет открытие редактора.

Примеры

git commit -am 'Add changes' Коммит всех отслеживаемых изменений.

git commit --author='John Smith <john@me.com>' --date='2023-08-15 15:00' Коммит с указанными автором и датой.

Флаги

-m <message> Позволяет указать сообщение message без открытия редактора.

-v Добавить в комментарий к коммиту дельту diff изменений.

--author Позволяет указать данные автора в формате name <email>.

--date Указать дату автора.

Игнорирование индексации

git commit <file> Коммит уже отслеживаемого файла, позволяет обойтись без git add.

git commit -a (или --all) Коммит всех уже отслеживаемых файлов, позволяет обойтись без git add.

Хороший коммит

Очень важно, чтобы коммит добавлял только одну вещь. Это свойство называют атомарностью (atomic).

Коммит должен быть консистентным (consistent), то есть логически завершенным изменением проекта.

Первая строка описания коммита считается его заголовком. Ее рекомендуется делать до 50 символов в длину, точка в конце не ставится. После заголовка, через двойной перевод строки, идет его описание. Ширину описания делают не более 72 символов для удобства просмотра в консоли.

Удаление и переименование отслеживаемых файлов

Удаление файлов

git rm <file> Удаляет файл из рабочей директории и сохраняет изменения в Индекс (эквивалентно rm + git add).

git rm --cached <file> Удаляет файл из Индекса, файл становится неотслеживаемым.

Флаги

-r Разрешает удалять директории.

-f Удаляет файл не только из рабочей директории, но и из Индекса.

Переименование файлов

git mv <name1> <name2> Переименовывает файл и сохраняет изменения в Индекс. Если name2 содержит другой путь, файл будет перемещен.

Очистка с git clean

git clean удаляет все неотслеживаемые файлы. Обычно используется с флагами:

  • -n Показать список файлов, которые будут удалены
  • -f Обязательный флаг для удаления файлов
  • -d Выбрать не только файлы, но и директории
  • -x Файлы, которые игнорируются .gitignore
Пример

git clean -nd Просмотр файлов и директорий, которые будут удалены командой git clean -fd.

Удаление "лишних" файлов и незакоммиченных изменений

Для приведения проекта к тому же состоянию, который есть в репозитории, нужны две команды: git reset --hard + git clean -dxf.

git stash

git stash Собирает изменения в рабочей директории и Индексе, архивирует их в Git, очищая статус.

git stash -u Позволяет архивировать неотслеживаемые файлы.

git stash save '<title>' Сохранить изменения под заголовком title.

git stash list Просмотр припрятанных изменений.

git stash apply <num> Извлекает изменения, которые хранятся под номером num (или 0, если num не указан) в рабочую директорию и Индекс.

git checkout stash@{<num>} -- <file> Применить git stash apply <num> только для отслеживаемого файла <file>.

git stash pop <num> Выполняет git shash apply <num> и очищает архив под указанным номером.

Примеры

git stash save 'my changes' -u Сохранить все изменения, включая неотслеживаемые файлы под именем my changes.

git stash apply Применить последнее изменение, не удаляя его из архива.

git stash pop 2 Применить изменение, сохраненное под номером 2 и удалить его из архива.

git checkout stash@{0} -- index.html Достать из последних припрятаных изменений только файл index.html.

Ветвление

git branch

Создание и удаление веток

git branch <branch> <hash> Создает ветку branch с указателем на коммит hash, или, если он не указан, на текущий коммит. С флагом -f позволяет переместить существующую ветку.

git branch -d <branch> Удаляет ветку branch, если она объединена с текущей. Иначе для удаления потребуется флаг -D.

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

git branch --move <oldname> <newname> Изменяет имя ветки с oldname на newname.

Просмотр информации о ветках

git branch Выводит названия существующих веток.

git branch -v Выводит названия веток и последний коммит в каждой из них.

git branch --merged Выводит ветки, объединенные с текущей. Можно узнать такие ветки и удалить все, кроме текущей. Наработки из них уже включены в текущую ветку, так что ничего не потеряется.

git branch --no-merged Выводит ветки, не объединенные с текущей.

Ветки в удаленных репозиториях

git branch -r Просмотр только веток из удаленных репозиториев.

git branch -a Просмотр всех веток в локальном и подключенных удаленных репозиториях.

git branch -vv Просмотр локальных веток вместе с последним коммитом и ветками слежения.

git checkout

Переключение между ветками

git checkout <hash> Переключение между коммитами по идентификатору (ветка, коммит, тег и тд).

git checkout -b <branch> <hash> Создает новую ветку и переключается на нее. Если задан hash, новая ветка будет указывать на него.

git checkout -B <branch> <hash> Позволяет переместить указатель ветки branch к идентификатору hash.

git checkout - Обращается к рефлогу и переключается на предыдущую активную ветку.

Откат состояния файлов

git checkout -f <hash> Отменяет все изменения с момента последнего коммита. Если указан hash, переключается на него.

git checkout <hash> <file> Восстанавливает состояние файла на момент коммита hash и добавляет изменения в Индекс.

git checkout -- <file> Восстанавливает состояние файла на момент текущего коммита, если он не был изменен в Индексе. Двойной дефис явно указывает Git, что это путь, а не ветка или тег. Аналог команды git restore <file>.

git reset

Жесткий reset

git reset --hard <hash> Передвигает указатель текущей ветки на коммит hash и обновляет файлы в рабочей директории и Индексе (сбрасывает состояние файлов на момент коммита hash). Отменяет незакоммиченные изменения.

git reset --hard ORIG_HEAD Отменяет предыдущую команду (незакоммиченные изменения возвращены не будут).

Мягкий reset

git reset --soft <hash> Передвигает указатель текущей ветки на коммит hash, не меняя файлы в рабочей директории и Индексе. Обычно используется чтобы отменить последний неудачный коммит, не меняя файлы.

git reset --soft ORIG_HEAD Отменяет предыдущую команду.

Смешанный reset

git reset <hash> Передвигает указатель текущей ветки на коммит hash, обновляя файлы только в Индексе (не меняет состояние файлов в рабочей директории). Отменяет изменения в Индексе.

git reset <hash> <file> Изменяет файл в Индексе на момент коммита hash. Указатель ветки не передвигается.

git reset -- <file> Отменяет изменения файла в Индексе. Аналог команды get restore --staged <file>. Если file не указан, отменяет все изменения в Индексе.

Просмотр

Указатели

Теги

Тег — это метка, которая всегда указывает на один и тот же коммит.

Легковесные теги содержат только контрольную сумму коммита; аннотированные хранят дополнительное сообщение и информацию о авторе тега.

git tag Просмотр имеющихся тегов в алфавитном порядке.

git tag <tag> <hash> Создание легковесного тега на коммите hash.

git tag -d <tag> Удаление тега (или нескольких тегов).

git show <tag> Просмотр коммита вместе с сообщением, автором и датой аннотированного тега.

Примеры

git tag v2 Создание легковесного тега v2 на текущем коммите.

git tag -l -n "v1.8.5*" Вывести все теги, начинающиеся с v1.8.5 вместе с сообщением.

git tag v1.0.0 -a -m 'Version 1.0.0' fe33 Создание аннотированного тега на коммите fe33.

Флаги

-a Указывается для создания аннотированного тега.

-m <message> При создании аннотированного тега позволяет ввести сообщение без открытия редактора.

--contains <hash> Показать только теги, которые содержат в своей цепочке коммит hash.

-n<число> Просмотр тега вместе с сообщением. Числом задается количество строк сообщения, по умолчанию 1.

-l '<template>' (или --list '<template>') Вывести теги по заданному шаблону.

Ссылка на текущий коммит

HEAD (или @) Указатель на текущий коммит.

ORIG_HEAD Указатель на HEAD до передвижения, находится в файле .git/ORIG_HEAD.

Модификаторы

Модификаторы задаются после указателя hash и позволяют работать с коммитом относительно запрашиваемого вместо него самого. Могут применяться несколько раз.

~<n> Фигурирующий в команде hash заменяется на родительский n раз подряд.

^<n> Используется для коммитов слияния, имеющих более одного родителя, позволяет выбрать n-го родителя.

Каретка ^ и тильда ~ без значения означают одно и то же.

Примеры

git show @~ Просмотр данных предпоследнего коммита.

git diff HEAD^2 Сравнивает содержимое коммита, с которым произошло слияние и рабочей директории.

git log @^^ (или git log @~2) Выведет историю коммитов, не включая последние два.

git reflog

История переключения веток

Перемещение указателя HEAD каждый раз записывается в файл .git/logs/HEAD (журнал рефлогов) вместе с описанием того, что произошло. Рефлоги используются для восстановления данных и поиска потерянных коммитов.

git reflog <branch> Выводит все рефлоги. Если указана ветка, выводит рефлоги только для нее.

Для обращения к записям из рефлога можно использовать не только hash, но и фигурные скобки.

Примеры

git branch feature HEAD@{6} Создание ветки feature, указывающей на коммит, соответствующий седьмому с конца (отсчет идет с нуля) перемещению HEAD.

git show HEAD@{'2023-08-06 14:00:00 +0300'} Выводит информацию о ближайшем коммите, сделанном до этой даты.

Флаги

-<n> Вывести только n последних записей.

--date Выводит рефлоги вместе с датой. Необходимо задать значение, например, iso или short.

--no-decorate Выводит рефлоги без текущих указателей (веток, тегов и тд).

Сборка мусора

git gc Инициирует сборку мусора (удаление устаревших недостижимых коммитов). С флагом --prune=now очистит все коммиты. Однако, коммиты, достижимые из рефлога останутся.

git reflog expire --expire=all --all Удаление всех коммитов из рефлога.

Рефлоги хранятся 90 дней для достижимых веток, если это не переопределено переменной gc.reflogExpire, и 30 для недостижимых, если это не переопределено переменной gc.reflogExpireUnreachable.

Если коммит недостижим и в рефлоге о нем нет записей, он хранится в памяти как минимум 2 недели с момента его создания, если это не переопределено настройкой gc.pruneExpire. Такие коммиты можно найти с помощью команды git fsck --unreachable.

Если к коммиту можно получить доступ, то и его родительские коммиты тоже остаются в памяти.

git show

git show <hash> Выводит данные о коммите hash. Если он не указан, выведет данные текущего коммита.

git show <hash>:<file> Просмотр файла на момент коммита hash. Если не указывать hash, выведет текущую версию файла в Индексе.

git show :/<str> Поиск самого свежего коммита, в описании которого есть строка str.

Примеры

git show master~ Просмотр родительского коммита ветки master.

git show :file.txt Просмотр индексированной версии файла file.txt.

Флаги

-q (или --quiet) Выводит информацию без изменений diff.

git diff

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

git diff <hash1> <hash2> (или git <hash1>..<hash2>) Отображает изменения между hash1 и hash2.

git diff <hash1>...<hash2> Ищет ближайший общий для hash1 и hash2 родительский коммит и отображает, что изменилось в hash2 с момента этого коммита.

git diff <hash> Сравнивает содержимое рабочей директории и репозитория на момент коммита hash.

git diff --staged <hash> (или git diff --cached <hash>) Сравнивает содержимое Индекса с коммитом hash.

git diff Отображает изменения, не добавленные в Индекс между текущим коммитом и рабочей директорией.

git diff -- <file> Показывает изменения только для определенного файла, работает со всеми формами git diff.

Сравнение файлов

git diff <hash1>:<file1> <hash2>:<file2> Сравнивает два файла из разных (необязательно) коммитов.

git diff --no-index <file1> <file2> Сравнивает любые два файла. Для работы команды репозиторий не требуется!

Примеры

git diff master feature Выводит все изменения, сделанные в feature относительно ветки master.

git diff HEAD (или git diff @) Отображает все изменения между текущим коммитом и рабочей директорией.

git diff --cached Выводит только проиндексированные изменения, которых нет в текущем коммите.

git diff . Отображает только не добавленные в Индекс изменения в текущей директории.

git diff --color-words -U0 index.html Изменения в index.html рабочей директории по словам, без контекста.

Флаги

-U<n> (или --unified=<n>) Задать количество строк контекста (до и после), по умолчанию 3.

--word-diff Показывать различия по словам (вместо различий по строкам).

--color-words Показывать различия по словам без дополнительных скобок и знаков +, -.

--name-only Вывести только имена различающихся файлов.

По умолчанию слово в Git - это любая последовательность символов без пробела, однако, такое определение может быть удобно не всегда. В файле <project>/.gitattributes можно указать diff-драйвера, определяющие, что такое слово. Для некоторых языков существуют встроенные драйвера, для остальных можно написать свой. Пример содержимого файла:

*.html diff=html *.css diff=css

Делать .gitattributes отслеживаемым не нужно, изменения будут применены и без этого.

git log

git log Выводит историю коммитов, достижимых из HEAD.

git log <hash> Выводит историю коммитов для одного или нескольких идентификаторов.

git log <hash1> ^<hash2> (или git log <hash2>..<hash1>) Выводит коммиты для hash1, недостижимые из hash2.

git log <hash1>...<hash2> Выводит коммиты, достижимые для hash1 и hash2, но не для них обоих одновременно.

git log -- <file> Опция <file> указывается последней. Выводит только те коммиты, которые меняют указанный файл (или файлы). Фильтр по файлам работает со всеми вышеперечисленными вызовами git log.

git log --follow -- <file> Если файл был переименован, выведет коммиты и после, и до переименования.

Примеры

git log ..feature (или git log HEAD..feature) Показывает все коммиты ветки feature после ответвления от текущей ветки.

git log feature.. (или git log feature..HEAD) Показывает все коммиты в текущей ветке с момента последнего общего коммита с feature.

git log master...feature --boundary --graph Отображает в виде графа коммиты в ветках master и feature с момента их последнего общего коммита, включая этот коммит.

git log --all file.txt Показать все коммиты, меняющие file.txt.

Флаги

--boundary Включает в вывод последний общий для двух указателей коммит.

--first-parent Для всех коммитов слияния выводит только их первого родителя.

--all Вывод коммитов, достижимых для всех веток и тегов.

--graph Рисует данные в виде графа, отображающего структуру изменений. Для больших репозиториев лучше использовать одну из графических утилит git gui.

-p (или --patch) Добавляет в вывод изменения diff между коммитами.

--abbrev-commit Сокращает идентификатор коммитов.

--pretty Задает формат вывода. Значения:

  • medium Значение по умолчанию
  • oneline Выводит коммиты в одну строку
  • full Вместо даты коммита выводит коммитера
  • fuller Выводит полную информацию об авторе и коммитере

--oneline Сокращение для --pretty=oneline --abbrev-commit.

Формат дат

--date Задает формат вывода даты. Значение short будет выводить только дату.

--relative-date (или --date=relative) Отображает дату в относительном формате.

--date=format:'<str>' Для задания пользовательского формата вывода даты используется вспомогательная функция strftime, не описанная в документации Git. Например, %F выведет дату, %R время.

Формат указателей

--decorate Задает, как будут выводиться указатели на коммиты. Значения:

  • short Значение по умолчанию
  • no Указатели на коммиты выводиться не будут
  • full Вывод указателей вместе с их расположением

--no-decorate Соответствует опции --decorate=no.

Другие флаги

--stat Выводит измененные файлы и количество измененных в них строк.

--shortstat Отображает только количество изменений/вставок/удалений.

--name-only Показывает только список измененных файлов.

--name-status Показывает список файлов c кратким обозначением того, что они добавлены/изменены/удалены.

Фильтр по сообщениям

--grep <str> Поиск по ключевым словам в коммите. Флаг --grep можно указать несколько раз.

--grep <str> -i Регистронезависимый поиск.

--grep <regexp> -P Позволяет использовать совместимые с Perl регулярные выражения.

--grep <str> -F Отключить поиск по регулярным выражениям, str будет интерпретироваться как обычная строка (даже если в конфигурации grep.patternType установлен в true).

Дополнительные флаги

--all-match Поиск коммитов, удовлетворяющих всем указанным --grep шаблонам одновременно.

Примеры

git log --grep add --grep hi --all Выведет коммиты, в которых есть слово add или hi (или оба).

git log --grep add --grep hi --all-match Выведет коммиты, в которых есть оба слова hi и add.

git log --grep 'h(i|ello)' -P -i Выведет коммиты со словами hi и hello в любом регистре.

Фильтр по изменениям в коммите

-S <str> Выводит коммиты, изменяющие строку str в их содержимом.

-G<regexp> Позволяет отфильтровать коммиты по изменениям содержимого в них. Специальные символы необходимо экранировать с помощью \.

-L <start>,<end>:<file> Выводит все коммиты, в file которых были измены строки от start до end (включительно) и покажет эти строки в формате diff.

-L '/<regexp1>/','/<regexp2>/':<file> Выведет все коммиты, в которых были изменения между regexp1 и regexp2 в файле file.

Примеры

git log -GsayHi -p Вывод изменений diff коммитов, в которых была изменена строка sayHi.

git log -G'function sayHi\(' Вывод коммитов, в которых изменяется вызов функции sayHi.

git log -L 3,6:index.html Вывести коммиты, в которых менялись строки с 3 по 6 в index.html и показать эти изменения.

git log -L '/<head>/','/<\/head>/':index.html Поиск коммитов, изменяющих содержимое тега head в index.html.

git log -L '/^function sayHi/','/^}/':script.js Поиск коммитов, изменяющих функцию sayHi в script.js.

Другие фильтры

-<n> Ограничить количиство выводимых коммитов числом n.

--author Фильтровать коммиты по имени или email автора.

--committer Фильтровать коммиты по имени или email коммитера.

--before (или --until) Фильтрация коммитов до определенной даты включительно.

--after (или --since) Фильтрация коммитов, начиная с определенной даты.

Примеры

git log --author=sergeydes@ -1 Вывести последний коммит автора, email которого начинается с sergeydes@.

git log --before '2023-08-15 08:30:00 +02' Вывести коммиты до указанной даты.

git log --since '2 weeks 1 day' Поиск коммитов, сделанных менее 2 недель и 1 дня назад.

Задать другой формат вывода коммита

git log --pretty=format:'<str>' Позволяет задать свой формат вывода в строке str. Параметры:

  • %h Сокращенный хэш коммита. %H выведет полный хэш
  • %t Сокращенный хэш дерева. %T выведет полный хэш
  • %p Сокращенный хэш родителя. %P выведет полный хэш
  • %an Имя автора. %ae выведет email автора
  • %ad Дата автора. %ar выведет относительную дату автора
  • %cn Имя коммитера. %ce выведет email коммитера
  • %cd Дата коммитера. %cr выведет относительную дату коммитера
  • %s Заголовок сообщения коммита
  • %d Указатели на коммит
  • %C(<color>) Задает цвет для остатка строки
Примеры
git log --pretty=format:'%h - %an, %ar : %s' git log --pretty=format:'%C(yellow)%h %C(dim green)%cd %C(reset)| %C(cyan)%s%d %C(#667788)[%an]' --date=format:'%F %R'

git blame

git blame <file> Позволяет узнать, кто и когда написал строки кода в указанном файле.

Опции

--date Позволяет настроить формат вывода даты.

-L <start>,<end> Позволяет вывести только определенные строки кода.

Пример

git blame file.txt --date=short -L 5,8 Вывести информацию о строках 5-8 в file.txt с датой в формате short.

Слияние коммитов

git merge

git merge <hash> Сливает текущую ветку с hash, создает коммит слияния и переносит туда указатель текущей ветки.

git merge-base <hash1> <hash2> Выведет общий для двух указатей хэш коммита, который будет использоваться при слиянии.

git reset --merge (или git merge --abort (после merge без флага --squash)) Позволяет отменить слияние и откатить состояние файлов на момент до его начала вместе с незакоммиченными изменениями.

git merge --continue Соответствует команде git commit, работает только из состояния слияния.

Флаги

--log В описание коммита слияния добавить описания всех сливаемых коммитов.

--squash Вместо коммита слияния создает обычный коммит со всеми изменениями и добавляет в описание информацию о сливаемых коммитах.

--no-commit Перейти в состояние прерванного слияния чтобы исправить семантический (смысловой) конфликт.

--no-ff Создать коммит слияния, даже если возможно слияние перемоткой.

--ff Добавить возможность слияния перемоткой, если в конфигурации таковая отключена.

--no-edit Отменяет открытие редактора.

Пример

git merge --no-ff --no-edit feature Выполнить полноценное слияние с веткой feature без изменения описания коммита.

Команды для разрешения конфликта

git checkout --ours <file> Применит изменения к файлу из текущей ветки.

git checkout --theirs <file> Применит изменения к файлу из сливаемой ветки.

git checkout --merge <file> Вернет версию файла с маркерами конфликта.

git checkout --conflict=diff3 --merge <file> Добавит маркер base в файл с конфликтом.

git show с коммитами слияния

В процессе слияния

В состоянии прерванного слияния в Индексе находится сразу 3 версии файла.

git show :1:<file> Покажет версию файла base.

git show :2:<file> Покажет версию файла ours.

git show :3:<file> Покажет версию файла theirs.

После слияния

С коммитом слияния, имеющим сразу двух (или более) родителей, git show работает иначе, показывая только те изменения diff, с которыми возник конфликт при слиянии. Если нужны различия между родителями, удобнее использовать git diff.

Особенности merge

Можно выделить 2 вида слияний:

  1. Слияние перемоткой (Fast-forward). Если текущая ветка сливается с коммитом, до которого можно добраться, двигаясь по истории вперёд, Git передвинет указатель текущей ветки к заданной.
  2. Истинное (трехстороннее) слияние. Git ищет base коммит, общий для обоих веток, и добавляет к нему изменения из ours, текущей ветки, и theirs, ветки с которой идет слияние. Создается новый коммит, называемый коммитом слияния. Если файл менялся только в одной ветке, в результат слияния попадет измененная версия файла.
Конфликт слияния

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

Git запоминает коммит, с которым идет слияние в файле .git/MERGE_HEAD.

git cherry-pick

git cherry-pick <hash> Применяет к текущему коммиту изменения diff, сделанные в <hash>. При этом будет создан новый коммит с тем же описанием и информацией об авторе.

git cherry-pick <hash1>..<hash2> (или <hash2> ^<hash1>) Позволяет выбрать диапазон и применить все изменения из этого диапазона к текущему коммиту. При этом будет сделано соответствующее число новых коммитов.

Пример

git cherry-pick master~2..master Применить изменения, взятые из последних двух коммитов ветки master.

Флаги

-e (или --edit) Изменить описание коммита.

-n (или --no-commit) Добавить все изменения в Индекс, но не делать коммит.

-x Добавить в описание коммита строку c <hash> скопированного коммита.

Команды при возникновении конфликта

git cherry-pick --abort Отменить применение изменений и вернуть состояние файлов обратно.

git cherry-pick --continue Продолжить выполнение cherry-pick, когда конфликт разрешен.

git cherry-pick --quit Остановиться на текущем состоянии, даже если не все изменения были применены.

git rebase

git rebase <hash> Перебазирование текущей ветки относительно hash.

git rebase <hash> <hash2> Перебазирование hash2 относительно hash (git checkout hash2 + git rebase hash).

git rebase --onto <hash> <hash1> Перебазирование относительно hash только тех коммитов из текущей ветки, которые следуют за hash1.

git rebase --onto <hash> <hash1> <hash2> Перебазирование из hash2, относительно hash, только коммитов после hash1 (git checkout hash2 + git rebase --onto hash hash1).

git rebase -x '<command>' <hash> Позволяет указать произвольную команду, которая будет выполняться после каждого перебазированного коммита, обычно это запуск тестов. Если команда завершится со статусом, отличным от 0, типичным для упавших тестов, перебазирование остановится и проблемный коммит можно будет исправить.

Флаги

--rebase-merges Перебазирует только основную часть ветки если в переносимой ветке есть коммиты слияния (применяются изменения только первых родителей таких коммитов).

--no-ff Все коммиты будут скопированы (заменены на такие же), даже если ничего не изменялось.

Интерактивное перебазирование

git rebase -i <hash> Перебазирование относительно hash с гибкой настройкой опций. Можно поменять порядок коммитов (поменяв местами строки в открывшемся файле git-rebase-todo), изменить коммиты или их описание, объединить, разбить на несколько, удалить и тд.

git rebase --edit-todo Посмотреть оставшийся список действий и отредактировать его, если нужно. Основные опции:

  • pick Опция по умолчанию, применяет коммит без изменений
  • reword Изменить только описание коммита
  • edit Приостанавливает слияние, позволяя изменить коммит
  • squash Объединить коммит с предыдующим, сохраняя описания обоих коммитов
  • fixup Объединить коммит с предыдущим, не сохраняя описание текущего коммита
Пример

git reflog feature Найти старую вершину feature, чтобы отменить rebase переносом указателя feature обратно. В простых ситуациях, когда конфликтов не было, можно использовать git reset --hard ORIG_HEAD.

Другие флаги

--fixup=<hash> Используется вместе с командой git commit чтобы при следующем интерактивном перебазировании с флагом --autosquash Git автоматически поставил этот коммит после коммита hash (который нужно исправить) с опцией fixup. --squash=<hash> делает то же самое, но для hash поставит опцию squash.

--autosquash Берет все коммиты, сделанные с флагом --fixup или --squah и добавляет их в список в нужном месте с соответствующей опцией.

Команды при возникновении конфликта

git rebase --abort Отмена перебазирования с возвращением в исходное состояние.

git rebase --quit Отмена перебазирования, файлы в рабочем каталоге и указатель HEAD остаются как есть.

git rebase --continue Продолжить перебазирование, вызывается после разрешения конфликта, когда необходимые изменения в Индекс уже добавлены.

git rebase --skip Пропускает применение текущего изменения (коммита) и переходит к следующему.

В процессе перебазирования Git переходит в состоянии detached (отделенного) HEAD, так как указатель HEAD переносится не к ветке, а к коммиту напрямую, относительно которого выполняется перебазирование.

Особенности rebase

Команда rebase берет изменения из перебазируемой ветки и применяет их поверх другой, аналогично команде cherry-pick, при этом указатель текущей ветки переносится в новое место.

При перебазировании Git пропускает коммиты слияния. Поэтому если в этих коммитах были какие-то правки, они применены в итоге не будут.

Отличия rebase от merge
  1. Упрощение истории разработки.
  2. Можно использовать только для приватных веток, с которыми работаете только вы.
  3. Операция слияния безопасна, так как не перезаписывает существующие коммиты. При перебазировании возможны ошибки в получившихся коммитах (например, если в другой ветке было изменено имя функции), при которых конфликта слияния не возникнет, но получившиеся коммиты окажутся "сломанными". Избежать такой ситуации помогают автоматизированные тесты.

git revert

Команда отменяет коммиты, которые нельзя удалить, так как они были отправлены другим людям.

git revert <hash> Создает обычный коммит, отменяющий изменения, сделанные в hash.

git revert <hash1>..<hash2> Задать диапазон коммитов, будет создано соответствующее число новых коммитов.

Пример

git revert 06d0 -m 1 Отменить изменения от первого родителя в коммите 06d0.

Флаги

-n (или --no-commit) Применить все изменения, но не делать коммит.

-m Указывает, изменения какого родителя нужно отменить, если это коммит слияния.

Команды при возникновении конфликта

git revert --abort Отменить применение изменений и вернуть состояние файлов обратно.

git revert --continue Продолжить выполнение revert, когда конфликт разрешен.

git revert --quit Остановиться на текущем состоянии, даже если не все изменения были применены.

git rerere

git rerere forget <file> Удаляет запись о том, как разрешался конфликт в файле <file>.

git checkout --merge Возвращает версию файла с маркерами конфликта.

REuse REcorded REsolution позволяет автоматически разрешать конфликты слияния таким же образом, как они были решены до этого. Для Git не важно, каким способом было сделано слияние. Если возникает повторяющийся конфликт, файлы в рабочей директории изменятся, как если бы он уже был разрешен, однако в Индекс их нужно будет добавить самостоятельно.

Все данные о разрешенных конфликтах хранятся в директории .git/rr-cache. Они хранятся 60 дней, если это не переопределено переменной rerere.rerereResolved.

Работа с удаленными репозиториями

git remote

git remote Отображает имена доступных удалённых репозиториев. С флагом -v показывает адреса для чтения и записи.

git remote add <remote> <url> Добавляет удаленный репозиторий и присваивает ему имя.

git remote remove <remote> Отключает удаленный репозиторий.

git remote rename <oldname> <newname> Переименовывает удаленный репозиторий.

git remote show <remote> Выводит информацию о репозитории.

git remote prune <remote> Удалить старые ветки слежения, которых больше нет в удаленном репозитории.

Пример

git remote add upstream https://github.com/RusJstudent/depthVSbreadth.git Добавление удаленного репозитория под именем upstream.

Просмотр

git ls-remote <remote> Полный список указателей на ветки и теги в удаленном репозитории.

git fetch и git pull

Команды git fetch и get pull получают изменения из удаленного репозитория.

git fetch <remote> Синхронизирует ветки слежения с удаленным репозиторием, передвигая их указатели.

git fetch --all Сихронизировать ветки слежения со всеми удаленными репозиториями.

git pull <remote> <branch> Синхронизирует изменения для ветки branch и пытается слить их с текущим кодом.

Примеры

git pull Сихронизирует изменения веток слежения с origin и включает их в локальную копию проекта.

git pull upstream master Получает все изменения для ветки master в репозитории upstream и делает merge.

Терминология

pull request — живой запрос на прием последних изменений из нашего удаленного fork репозитория в исходный, обычно называющийся upstream. При обновлении fork обновляется и pull request.

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

git push

Команда git push отправляет изменения на удаленный сервер.

git push <remote> <branch> Добавляет изменения на удаленный репозиторий.

git push -f Позволяет переписать историю в удаленной ветке, сихронизируя ее с локальной.

git push <remote> --delete <branch> Удаляет ветку из удаленного репозитория.

Добавление веток слежения

git push --set-upstream <remote> <branch> (или git push -u <remote> <branch>) Связывает локальную ветку branch с удаленной и выполняет push. В дальнейшем, для добавления измененений из такой ветки, достаточно команды git push.

Обмен тегами

git push <remote> <tag> Добавление тега в удаленный репозиторий.

git push <remote> --delete <tag> Удаление тега из удаленного репозитория.

git push <remote> --tags Добавление всех тегов на удаленный репозиторий, если их там нет.

git push <remote> --follow-tags Добавление только аннотированных тегов.