Перейти к основному содержимому

Справочник-шпаргалка по Git

Play ITЗагрузка интерактивного демо…


Назначение

CLI, конфигурация и типовые сценарии Git. Учебный курс: раздел.


Краткое пояснение

git push отправляет ваши коммиты на удалённый репозиторий (GitHub, GitLab и т.д.). git pull подтягивает обновления с сервера и обновляет файлы в проекте; git fetch забирает коммиты с сервера, но рабочую папку не меняет. Схема "куда что двигается" — в Как работать с Git. git switch — современный способ переключиться на другую ветку; то же делает классический git checkout (имя ветки или коммита). Ниже — 12 команд, которые стоит держать под рукой; углублённый справочник — в частях 1–8 этой страницы.


12 команд на каждый день

Типичный день в терминах Git: правки → statusaddcommitpush; перед работой — pull или fetch; для фичи — отдельная ветка, переключение и слияние. Пошаговый разбор цикла — в Как работать с Git; ветки и PR — в Ветвление и слияние.

КомандаЗачемПример
1git initСоздать новый репозиторий в текущей папке (появляется .git)mkdir railsapp && cd railsappgit init
2git addПодготовить изменения к коммиту (индекс / staging)git add README.md · git add .
3git commitЗафиксировать то, что в индексе, с сообщениемgit commit -m "Initial commit"
4git pushОтправить локальные коммиты на серверgit push origin main
5git pullЗабрать с сервера и влить в текущую ветку (fetch + merge)git pull origin main
6git remoteПривязать, посмотреть или переименовать удалённый репозиторийgit remote add origin <url> · git remote -v
7git branchСписок веток, создать или удалить веткуgit branch · git branch feature-login
8git fetchСкачать новые коммиты с сервера без изменения рабочих файловgit fetch origin
9git switch / git checkoutПереключиться на ветку (или снять с ветки файл из старого коммита)git switch feature-login · git checkout main
10git mergeВлить другую ветку в текущуюgit switch maingit merge feature-login
11git statusЧто изменено, что в индексе, на какой вы веткеgit status · git status -sb
12git resetСдвинуть ветку к другому коммиту (осторожно с --hard)git reset --soft HEAD~1 · см. опасные команды
Современные имена

С Git 2.23 переключение веток чаще пишут как git switch и git switch -c имя вместо git checkout / git checkout -b. Смысл тот же

в старых статьях и на схемах встречается слово checkout.

Мини-сценарий "с нуля до push":

mkdir myapp && cd myapp
git init
echo "# My App" > README.md
git add README.md
git status
git commit -m "Первый коммит"
git remote add origin https://github.com/USER/myapp.git
git push -u origin main

Мини-сценарий "ветка фичи":

git fetch origin
git switch -c feature-login
# правки, add, commit…
git switch main
git merge feature-login
git push origin main

Расширенный список команд и флагов — в Команды Git для повседневной разработки. Ошибки и восстановление — Типовые ситуации. Те же мини-сценарии с построчными таблицамилабораторная шпаргалка (с нуля до push, ветка фичи).


Быстрый старт

git clone <url>
cd <repo>
git status
git diff
git add -A
git commit -m "msg"
git switch -c feature
git merge main
git push -u origin HEAD

Справочные таблицы

Содержание справочника


Часть 1. Архитектура и внутреннее устройство

1.1. Объектная модель Git

Git хранит все данные в виде неизменяемых объектов четырёх типов — blob, tree, commit, tag. Все объекты идентифицируются SHA-1-хешем их содержимого (в современных версиях Git допускается SHA-256, но пока не является стандартом).

  • Blob (binary large object) — представляет содержимое файла без имени и метаданных. Имя файла хранится в tree.
  • Tree — похож на директорию: содержит список имён файлов/поддиректорий и соответствующих им SHA-хешей blob или других tree. Обеспечивает структуру файловой системы на момент коммита.
  • Commit — ссылается на один tree (состояние файловой системы), содержит метаданные — автора, дату, сообщение, а также ссылку на родительский(-ые) коммит(ы). Первоначальный коммит не имеет родителей; при слиянии — два или более.
  • Tag — объект, содержащий ссылку на commit (или другой объект), имя, необязательное сообщение и цифровую подпись (если используется git tag -s). Лёгкие теги (git tag v1.0) — это просто ссылки в refs/tags/, не создающие отдельный объект.

Все объекты физически хранятся в .git/objects/: сначала 2 символа хеша — имя подкаталога, остальные 38 — имя файла. Для экономии места Git применяет zlib-сжатие и пакует объекты в pack-файлы (*.pack) при выполнении git gc, git repack или при передаче по сети (git push/fetch).


1.2. Ссылки (refs) и их роль

Ссылки в Git — это текстовые файлы, содержащие SHA-хеш (обычно 40-символьный). Они делятся на категории:

  • HEAD — специальная ссылка, указывающая на текущую позицию: либо на ветку (ref: refs/heads/main), либо напрямую на коммит (состояние detached HEAD).
  • Ветки (refs/heads/*) — подвижные указатели на коммиты. При создании коммита ветка, на которую ссылается HEAD, автоматически продвигается вперёд.
  • Удалённые ветки (refs/remotes/*) — зеркала веток с удалённых репозиториев, обновляются только при git fetch или git pull. Не являются локальными ветками, но могут быть использованы как точки отсчёта (git checkout origin/main → detached HEAD).
  • Теги (refs/tags/*) — либо лёгкие (ссылки), либо аннотированные (отдельные объекты).
  • Заметки (notes) — механизм добавления произвольных метаданных к коммитам без изменения их хеша (git notes add).

В .git/packed-refs хранятся сжатые ссылки — Git использует его для ускорения доступа при большом количестве веток/тегов.


1.3. Индекс (staging area) — не просто "буфер"

Индекс — это бинарный файл (.git/index), описывающий точное состояние, которое будет зафиксировано в следующем коммите. Он содержит:

  • пути файлов (в кодировке UTF-8);
  • статусы (mode, тип);
  • SHA-1 blob для каждого пути;
  • временные метки и размеры (для быстрого определения изменился ли файл);
  • этапы слияния (в случае конфликтов — 3 записи на файл — base, ours, theirs).

Индекс не является просто "списком добавленных файлов": он хранит полное дерево, включая удалённые файлы и конфликты. Это позволяет Git мгновенно реконструировать коммит без перечитывания файловой системы.

git status сравнивает три состояния:

  1. HEAD ↔ индекс → что будет закоммичено;
  2. индекс ↔ рабочая директория → что можно добавить.

Просмотр различий:

git status
git diff # рабочая директория ↔ индекс
git diff --staged # HEAD ↔ индекс (то же, что --cached)

Часть 2. Базовые операции и их семантика

2.1. Инициализация и клонирование

git init [--bare]

Создаёт новый репозиторий в текущей директории. Без --bare создаётся рабочая копия с подкаталогом .git. С --bare создаётся только содержимое .git — такой репозиторий нельзя использовать для редактирования, только для push/pull. Используется для "центральных" репозиториев на серверах.

git clone <url> [<dir>]
git clone --depth 1 <url> # shallow clone
git clone --branch <branch> <url>
git clone --recurse-submodules <url>

Углубление shallow-клона:

git fetch --unshallow

git clone выполняет четыре действия:

  1. Создаёт директорию и инициализирует репозиторий (git init);
  2. Добавляет remote origin по указанному URL;
  3. Загружает все объекты и ссылки (git fetch);
  4. Создаёт локальную ветку, соответствующую remote.<origin>.HEAD (обычно main или master), и проверяет её.

Опция --depth N создаёт "мелкий" репозиторий — без полной истории, только последние N коммитов. Удобно для CI/CD или быстрой сборки, но ограничивает возможности git log, git blame, git bisect. Углубление — см. блок выше.


2.2. Фиксация изменений — от add до commit

git add <pathspec>...
git add -u # только уже отслеживаемые (modified/deleted)
git add -A # все изменения (новые, изменённые, удалённые)
git add -p # интерактивное добавление по ханкам

git add читает содержимое файлов, создаёт blob-объекты (если их ещё нет), обновляет записи в индексе. Для больших файлов Git проверяет, изменились ли только временные метки и размер — если нет, пересчёт хеша пропускается (ускорение).

Важно: git add не удаляет физически файлы из рабочей директории — только помечает их на удаление в индексе. Удаление из репозитория и с диска:

git rm --cached path/to/file # убрать из индекса, файл остаётся на диске
git rm path/to/file # убрать из индекса и удалить файл
git commit [-m "message"] [--amend] [--no-edit] [-v]

Создаёт новый commit-объект:

  • tree берётся из текущего состояния индекса;
  • родитель — текущий HEAD;
  • автор/коммитер — из user.name/user.email;
  • сообщение — либо из -m, либо из редактора (core.editor).

При --amend текущий HEAD перезаписывается — создаётся новый коммит с тем же родителем, что и предыдущий HEAD, но с обновлённым tree и/или сообщением. Предыдущий коммит остаётся в объектной базе, пока не будет удалён сборщиком мусора. Это локальная операция, безопасна до push; после — требует --force.

Флаг -v (--verbose) добавляет в редактор diff коммита — помогает проверить вносимые изменения перед фиксацией.


Часть 3. Ветвление, слияние и перебазирование

3.1. Модель ветвления в Git — указатели, а не копии

В отличие от систем, где ветка — это физическая копия файлов (например, SVN), в Git ветка — это подвижная ссылка на коммит. Создание ветки мгновенно, поскольку выполняется только запись ссылки в refs/heads/<name> и обновление HEAD (при переключении). Никакие файлы при этом не копируются и не дублируются.

git branch <branch-name> [<start-point>]

Создаёт новую ссылку <branch-name>, указывающую на коммит, заданный <start-point> (по умолчанию — текущий HEAD). Не переключает на неё.

git checkout <branch-name>
git switch <branch-name> # современная альтернатива
git switch -c <new-branch> # = git checkout -b

Команда checkout исторически совмещала переключение веток и восстановление файлов. В Git 2.23+ рекомендуется использовать switch для смены веток и restore для манипуляций с файлами — это повышает читаемость и безопасность.

При переключении Git:

  1. Обновляет HEAD, чтобы он ссылался на новую ветку;
  2. Обновляет индекс и рабочую директорию в соответствии с tree, на который указывает эта ветка;
  3. Если в рабочей директории есть несохранённые изменения, которые конфликтуют с целевым состоянием, переключение отклоняется — это защита от потери данных.

Состояние detached HEAD возникает, когда HEAD указывает напрямую на коммит (например, git checkout abc123 или git checkout origin/main). В этом режиме новые коммиты создаются, но ни одна ветка не продвигается. Сохранить "висячие" коммиты:

git branch rescue abc123
git switch main

3.2. Слияние (merge) — интеграция изменений

git merge <branch>
git merge --no-ff <branch>
git merge --squash <branch>
  • Fast-forward (ff) — происходит, если текущая ветка является предком целевой. Git просто перемещает указатель вперёд, не создавая нового коммита. История остаётся линейной.
  • True merge — создаётся новый коммит с двумя родителями: текущий HEAD и <branch>. Запускается, если ветки расходились. Это единственный способ сохранить информацию о параллельной разработке.

Флаг --no-ff всегда создаёт merge-коммит, даже если возможен fast-forward. Откат всей feature-ветки одним коммитом:

git revert -m 1 <merge-commit>

Флаг --squash объединяет все изменения из <branch> в индекс текущей ветки, но не создаёт коммит и не сохраняет историю источника. Подходит для интеграции экспериментальных или "грязных" веток, когда детали промежуточных коммитов не важны.


Стратегии слияния

Git поддерживает несколько встроенных стратегий:

  • resolve — базовая стратегия для двух веток;
  • recursive (по умолчанию) — обрабатывает самослияния (например, при rebase), поддерживает --ours, --theirs;
  • octopus — для слияния более двух веток одновременно (только если возможно без конфликтов);
  • ours — полностью игнорирует изменения из других веток, сохраняя текущее дерево; используется в специфических сценариях интеграции;
  • subtree — пытается обнаружить, что одна ветка является поддеревом другой (редко используется вручную).

3.3. Перебазирование (rebase) — линеаризация истории

Схемы "до / после merge / после rebase" и практические правила выбора — в Ветвление и слияние.

git rebase <base>
git rebase -i <base>
git rebase --onto <newbase> <oldbase> <branch>
git rebase --continue / --abort / --skip

rebase переносит серию коммитов из одной линии истории на другую, пересоздавая их с новыми хешами. Это достигается путём:

  1. Временного сохранения патчей (git format-patch);
  2. Сброса ветки до <base>;
  3. Последовательного применения патчей с возможной адаптацией.

Поскольку хеши меняются, rebase меняет историю. Это допустимо только для локальных, неопубликованных коммитов. После rebase опубликованной ветки:

git push --force-with-lease

Интерактивное перебазирование (-i)

Открывает редактор со списком коммитов (от старых к новым), где каждая строка имеет вид:

pick abc123 commit message

Доступные команды:

  • pick — применить коммит как есть;
  • reword — изменить сообщение;
  • edit — остановиться для редактирования (можно изменить файлы, сделать git add, git commit --amend);
  • squash — объединить с предыдущим коммитом, сохраняя его сообщение;
  • fixup — объединить, но отбросить своё сообщение;
  • drop — пропустить коммит;
  • exec <command> — выполнить shell-команду после коммита (например, make test).

Это мощный инструмент для "причёсывания" истории перед интеграцией — удаление отладочных коммитов, группировка связанных изменений, унификация формулировок.


rebase --onto — перенос поддиапазона

Сценарий — у вас есть feature, ответвившаяся от main, но часть изменений уже была вмёрджена в main через другую ветку. Вы хотите перебазировать только новые коммиты.

git rebase --onto main <last-common-commit> feature

Это отрежет цепочку коммитов после <last-common-commit> и наложит её на main.


3.4. Конфликты — диагностика и разрешение

Конфликт возникает, когда Git не может автоматически объединить изменения в одном и том же участке файла. Рабочая директория остаётся в состоянии конфликта, а в индексе появляются три записи на файл:

  • stage 1 — общая база (&lt;&lt;&lt;&lt;&lt;&lt;< HEAD в файле);
  • stage 2 — текущая ветка (ours);
  • stage 3 — входящие изменения (theirs).

Команды:

git status # показывает конфликтующие файлы
git diff --ours / --theirs / --base # сравнить с каждой стороной
git checkout --ours <file> # взять версию текущей ветки
git checkout --theirs <file> # взять версию входящей ветки
git add <file> # после ручного разрешения — пометить как resolved
git mergetool # запустить GUI-инструмент (meld, kdiff3 и др.)

После разрешения всех конфликтов — git add и git commit (для merge) или git rebase --continue (для rebase). Важно — git add удаляет записи stage 2 и 3, оставляя только stage 0 — это сигнал системе, что конфликт разрешён.


Часть 4. Работа с удалёнными репозиториями

4.1. Remote — концепция и управление

Remote — это сокращённое имя для URL репозитория, используемое в командах fetch, push, pull.

git remote add <name> <url>
git remote rename <old> <new>
git remote remove <name>
git remote set-url <name> <newurl>
git remote -v # показать все remotes с URL

Каждый remote имеет набор конфигурационных параметров в .git/config:

[remote "origin"]
url = https://github.com/user/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
pushurl = ... # отдельный URL для отправки
push = ... # правила по умолчанию (редко используется)

Запись fetch определяет, как и куда сопоставляются ссылки при git fetch. По умолчанию — все локальные ветки в refs/remotes/origin/.


4.2. Fetch и push — асимметричные операции

git fetch [<remote>] [<refspec>...]
git fetch --prune # удалить локальные ссылки на удалённые ветки, которых больше нет
git fetch --tags # явно получить теги (по умолчанию — не все)

fetch только загружает объекты и обновляет удалённые ветки, не затрагивая рабочую директорию. Это безопасная операция.

refspec — шаблон +<src>:<dst>, где + означает force-update. Примеры:

git fetch origin main:fixes/main # локальная ветка fixes/main ← origin/main
git fetch origin :temp # temp ← HEAD на origin (редко, бэкап)
git push [<remote>] [<refspec>...]
git push --force-with-lease # безопасный force-push
git push --set-upstream origin main # установить tracking

Без refspec push отправляет текущую ветку, но только если она имеет upstream-связь. Иначе — ошибка.

--force перезаписывает удалённую ветку, игнорируя её текущее состояние. --force-with-lease проверяет, что локальная копия удалённой ветки (origin/main) совпадает с её состоянием на сервере. Это предотвращает случайную перезапись чужих коммитов.


4.3. Pull — fetch + merge (или rebase)

git pull
git pull --rebase
git config pull.rebase true # сделать rebase по умолчанию

git pull — это ярлык для git fetch + git merge FETCH_HEAD. Вариант с --rebase делает git rebase, что сохраняет линейную историю.

Рекомендация: в feature-ветках — pull --rebase, чтобы избежать лишних merge-коммитов. В shared-ветках (например, main) — только fetch + ручное merge, чтобы явно контролировать интеграцию.


Часть 5. Отладка и восстановление состояния

Пошаговые сценарии "что делать, если…" (ошибки с ветками, push, merge, секреты) — в отдельной главе Типовые ситуации с Git. Ниже — справочник по командам.


5.1. git reflog — журнал изменений ссылок

reflog — это локальный журнал операций, затрагивающих HEAD, ветки и другие ссылки. Записи сохраняются локально и не передаются при push/fetch. По умолчанию хранятся 90 дней (для достижимых объектов) или 30 дней (для недостижимых — garbage-collectable). Это основной инструмент восстановления после "потери" коммитов.

git reflog
git reflog show <branch> # reflog для конкретной ветки
git reflog expire --expire=now --all && git gc # очистка (осторожно!)

Формат записи:
abc123 HEAD@{1}: commit: fix typo
def456 HEAD@{2}: checkout: moving from main to feature

Каждая запись содержит:

  • SHA-1 состояния, в котором была ссылка после операции;
  • номер операции (@&#123;n&#125;);
  • тип операции и контекст.

Примеры восстановления

Типовые сценарии (ищите нужную запись в git reflog):

# Случайный git reset --hard
git reset --hard HEAD@{1}

# Коммит в detached HEAD — сохранить веткой
git branch rescue HEAD@{n}

# Отмена сломанного git rebase
git reset --hard HEAD@{k}

Подробнее по каждому случаю:

  1. Случайный git reset --hard — в reflog ищем запись перед reset (часто HEAD@{1}).
  2. Коммит в detached HEAD — сохраняем нужный HEAD@&#123;n&#125; в ветку rescue.
  3. Отмена сломанного git rebase — возвращаемся к HEAD@&#123;k&#125; до начала rebase.

Важно: reflog работает только с локальными операциями. Если репозиторий клонирован заново — reflog теряется.


5.2. git reset — изменение положения HEAD, индекса и рабочей директории

Команда reset имеет три режима, определяемых флагом (или отсутствием):

РежимHEADИндексРабочая директорияПрименение
--softОтмена коммита, но сохранение изменений в индексе (например, чтобы изменить сообщение или добавить файлы)
--mixed (по умолчанию)Отмена коммита и выгрузка изменений из индекса в рабочую директорию (подготовка к повторной подготовке коммита)
--hardПолный возврат в состояние коммита — все несохранённые изменения теряются
git reset --soft HEAD~1 # отменить последний коммит, оставить изменения в индексе
git reset HEAD~2 # отменить два коммита, изменения — в рабочей директории
git reset --hard origin/main # синхронизировать локальную ветку с удалённой (опасно!)

⚠️ Предупреждение: --hard без бэкапа может привести к безвозвратной потере данных. Перед --hard:

git stash push -m "backup before reset"
git branch backup-$(date +%Y%m%d)

5.3. git revert — безопасная отмена изменений

В отличие от reset, revert не перезаписывает историю. Он создаёт новый коммит, который вносит противоположные изменения по отношению к указанному коммиту.

git revert <commit>
git revert -n <commit> # подготовить изменения, но не коммитить
git revert -m 1 <merge-commit> # отменить merge (указать, какую родительскую ветку сохранить)

Для merge-коммита обязательна опция -m <parent-number> (1 — наша ветка, 2 — входящая). Без неё revert откажет: Git не знает, в какую сторону "откатывать" двухродительский коммит.

revert — единственный рекомендуемый способ отмены изменений в публичных ветках, поскольку он сохраняет целостность истории и не нарушает работу других разработчиков.


5.4. git cherry-pick — выборочное применение коммитов

Применяет изменения из одного или нескольких коммитов как новые коммиты в текущую ветку. Полезно при backport’е исправлений или извлечении отдельных функций без полного слияния.

git cherry-pick <commit>
git cherry-pick A^..B # диапазон (исключая A, включая B)
git cherry-pick --continue / --abort / --skip

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

  • Создаются новые коммиты с новыми хешами;
  • Если коммит уже был применён ранее (например, через merge), Git распознаёт это по содержимому изменений и пропускает дубликат (apply с --skip);
  • При конфликтах — как при rebase:
git add .
git cherry-pick --continue

Ограничение: cherry-pick не переносит связи — если коммит ссылался на issue или другой коммит через fixes #123, это не восстанавливается автоматически.


5.5. git bisect — бинарный поиск по истории для локализации ошибки

Автоматизирует процесс нахождения первого "плохого" коммита, в котором появился баг.

git bisect start
git bisect bad HEAD # текущее состояние — сломано
git bisect good v1.0 # известная хорошая точка
git bisect good # или bad
git bisect reset # выйти

Можно автоматизировать с помощью скрипта:

git bisect run ./test.sh

где test.sh возвращает:

  • 0 — коммит хороший;
  • 1–124, 126–127 — коммит плохой;
  • 125 — пропустить (например, сборка сломана не по нашей вине).

bisect особенно эффективен в больших проектах с длинной историей — вместо линейного просмотра 1000 коммитов требуется ~10 шагов.


Часть 6. Продвинутые темы

6.1. git worktree — параллельные рабочие копии

Позволяет иметь несколько рабочих директорий, связанных с одним репозиторием — без клонирования. Каждая worktree имеет своё дерево файлов, но разделяет общую объектную базу и ссылки.

git worktree add ../feature-branch feature
git worktree list
git worktree remove ../feature-branch
git worktree prune # удалить "мёртвые" worktree (например, после rm -rf)

Ограничения:

  • Нельзя иметь две worktree на одну и ту же ветку;
  • Нельзя удалить main worktree (ту, где лежит .git);
  • Индексы и HEAD — изолированы.

Практическое применение:

  • Тестирование сборки на main, пока ведётся разработка в feature;
  • Поддержка нескольких версий (например, v1-support, v2-dev) одновременно.

6.2. git submodule и git subtree — управление зависимостями

Submodule

Подмодуль — это отдельный репозиторий, встроенный в поддиректорию. В основном репозитории хранится только SHA-1 коммита подмодуля.

git submodule add <url> [<path>]
git submodule update --init --recursive
git submodule foreach 'git checkout main'

Плюсы: полная изоляция, чёткая привязка к версии.
Минусы — сложность обновления (git submodule update --remote), необходимость явного init, частые ошибки при клонировании (--recurse-submodules обязателен).


Subtree

Объединяет историю подпроекта в основную ветку через merge с --squash или subtree-стратегию.

git subtree add --prefix=lib/foo <repo> <ref>
git subtree push --prefix=lib/foo <repo> <branch>

Плюсы: единая история, нет внешних зависимостей при клонировании.
Минусы — история подпроекта "размазывается", сложнее выделить изменения, относящиеся только к нему.

Рекомендация: для статичных библиотек — subtree; для активно развивающихся, независимых компонентов — submodule или внешние пакетные менеджеры (npm, NuGet, pip).


6.3. git replace и git filter-repo — переписывание истории

git replace

Создаёт локальную замену одного объекта другим, без изменения хешей. Не влияет на push.

git replace <old-commit> <new-commit>
git replace -d <commit> # удалить замену
git filter-branch -- --all # применить замены рекурсивно (устаревшее)

Практическое применение: исправление авторства, исправление сообщений без пересборки всей истории.


git filter-repo (современная замена filter-branch)

Инструмент для безопасного, быстрого и гибкого переписывания истории. Требует установки отдельно (не входит в стандартную поставку).

Частые задачи:

  • Удаление файла из всей истории:
git filter-repo --path secrets.json --invert-paths
  • Изменение email во всех коммитах:
git filter-repo --email-callback 'return email.replace(b"old", b"new")'
  • Удаление тегов, веток, уменьшение размера репозитория.

⚠️ После filter-repo отправьте переписанную историю и предупредите команду:

git push --force-with-lease

Все участники должны переклонировать репозиторий.


Часть 7. Конфигурация, оптимизация и работа с большими репозиториями

7.1. Уровни конфигурации и приоритеты

Git поддерживает три уровня настроек, которые применяются иерархически (нижестоящий переопределяет вышестоящий):

УровеньКомандаФайлОбласть действия
Системныйgit config --system/etc/gitconfigВсе пользователи системы
Глобальныйgit config --global~/.gitconfig или ~/.config/git/configТекущий пользователь
Локальныйgit config.git/configТолько текущий репозиторий

Проверить, откуда берётся конкретная настройка:

git config --show-origin --get user.email

Ключевые параметры:

  • user.name, user.email — обязательны для commit и tag;
  • core.editor — редактор для сообщений (vim, code --wait, nano);
  • core.autocrlf — управление окончаниями строк:
    • true (Windows): LF → CRLF при checkout, CRLF → LF при commit;
    • input (Unix/macOS): CRLF → LF при commit, но не обратно;
    • false: без преобразований (только если вы контролируете окружение явно);
  • core.safecrlf — предупреждение при невозможности обратного преобразования;
  • core.filemode — учитывать ли биты исполнения (false на Windows);
  • core.precomposeunicode (macOS) — корректная работа с именами файлов в UTF-8 (включено по умолчанию с Git 2.20+);
  • init.defaultBranch — имя ветки по умолчанию (main, master);
  • pull.rebase, branch.autosetuprebase — поведение по умолчанию для pull;
  • credential.helper — кеширование учётных данных (например, cache, store, manager-core на Windows).

Для временного использования параметров — переменные окружения:
GIT_AUTHOR_NAME="CI Bot" git commit --amend --no-edit


7.2. .gitattributes — управление поведением по файлам

Файл .gitattributes (в корне или поддиректориях) задаёт правила обработки файлов при операциях. Имеет приоритет над глобальными настройками.

Часто используемые директивы:

АтрибутНазначение
text=autoGit сам решает, текстовый ли файл; при checkout нормализует EOL
text eol=lfПринудительно использовать LF при checkout (для скриптов, .sh, .py)
text eol=crlfПринудительно CRLF (.bat, .cmd)
binaryОтключает EOL-конверсию и diff (эквивалентно -text -diff)
diff=customИспользовать пользовательский драйвер diff (например, для JSON)
merge=customКастомная стратегия слияния (например, merge=union для списков)
linguist-language=PythonПодсказка для GitHub Language Stats

Пример:

*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.json diff=json
CHANGELOG diff

Для включения JSON-pretty diff:

git config diff.json.textconv "jq -S ."

Теперь git diff file.json будет показывать семантические различия, а не побайтовые.


7.3. Оптимизация и обслуживание репозитория

Сборка мусора и упаковка

Git автоматически запускает сборку мусора при достижении порогов (по умолчанию — после 65536 loose-объектов или 50 pack-файлов). В активных репозиториях — вручную:

git gc --aggressive --prune=now
  • --aggressive — более тщательная упаковка (медленнее, но лучше сжатие);
  • --prune=now — немедленно удалить объекты старше указанного времени (по умолчанию — 2 недели).

Для очень больших репозиториев:

git repack -d -l -A --window=250 --depth=250
  • -d — удалить старые pack-файлы;
  • -l — использовать только локальное сжатие (без --delta-base-offset);
  • -A — оставить достижимые loose-объекты;
  • --window, --depth — параметры поиска дельт (выше — лучше сжатие, но дольше).

Анализ размера

Определить, что занимает место:

git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print substr($0,6)}' \
| sort -k2 -n -r \
| head -n 10

git branch --format='%(refname:short)' | while read b; do
echo -n "$b: "
git ls-tree -r -l $b | awk '{sum += $4} END {print sum/1024/1024 " MB"}'
done

Если обнаружены большие бинарники — рассмотрите git filter-repo для их удаления или переход на Git LFS.


7.4. Работа с большими репозиториями — sparse-checkout, partial clone

Sparse-checkout

Позволяет клонировать и обновлять только часть файловой структуры, экономя время и дисковое пространство.

git clone --filter=blob:none --sparse <url> # частичная загрузка объектов + sparse
cd repo
git sparse-checkout set dir1/ dir2/file.txt
git sparse-checkout init --cone # режим "cone" (иерархический, быстрее)

В режиме --cone (по умолчанию с Git 2.25+) правила применяются иерархически: если включена src/, то включаются все поддиректории. Управление наборами путей:

git sparse-checkout add src/components/
git sparse-checkout remove legacy/
git sparse-checkout set dir1/ dir2/file.txt

Partial clone и promisor remotes

Git 2.19+ поддерживает частичную загрузку объектов:

git clone --filter=blob:none <url> # не загружать blob-объекты (только trees/commits)
git clone --filter=tree:0 <url> # не загружать деревья глубже корня

При необходимости объект подгружается "лениво" при checkout, log -p, grep. Особенно эффективно с серверами, поддерживающими uploadpack.allowFilter (GitHub, GitLab ≥ 12.5).

Для CI-сборок — значительное ускорение клонирования при сохранении полной истории.


Часть 8. Анти-паттерны и типичные ошибки

8.1. "Сломанный" .gitignore

  • Ошибка: добавить файл в индекс, потом прописать его в .gitignore.
    Последствие: файл продолжает отслеживаться.
    Исправление:
git rm --cached <file>
git add .gitignore
git commit -m "stop tracking <file>"
  • Ошибка: игнорировать файлы через git update-index --assume-unchanged или --skip-worktree.
    Последствие — изменения не видны в status, но при checkout, reset --hard — перезаписываются.
    Когда допустимо: только для локальных override-файлов (например, appsettings.Разработка.json), и только если точно понимаете разницу между assume-unchanged (оптимизация производительности) и skip-worktree (намеренное игнорирование изменений).

8.2. Использование git push --force без --with-lease

--force перезаписывает удалённую ветку независимо от её текущего состояния. Если другой разработчик успел запушить изменения — они потеряются.

Правильно:

git push --force-with-lease origin feature
git push --force-with-lease=feature:feature

8.3. Смешивание merge и rebase в shared-ветках

Если ветка develop используется несколькими людьми, её нельзя перебазировать. Это нарушает линейность и приводит к дублированию коммитов при последующих pull.

Правило: переписывание истории допустимо только для локальных веток, не имеющих upstream или не опубликованных.


8.4. "Забытый" git add перед commit

Создаёт коммит без изменений или с устаревшим состоянием индекса.

Профилактика — перед каждым коммитом:

git status
git diff
git diff --staged
git add path/to/file
git commit -m "message"
  • git commit -a — только для уже отслеживаемых файлов (новые не попадут в коммит);
  • pre-commit hook может проверять непустой diff.

8.5. Неправильное использование git stash

git stash push -m "WIP" --include-untracked
git stash apply
git stash drop
  • Без --include-untracked новые файлы не сохраняются;
  • После конфликта при pop безопаснее apply, затем drop вручную;
  • Долгоживущие stash — плохая практика; для длительного хранения используйте ветки.

Ошибки

СитуацияЧто проверить
Команда не найденаPATH, установка пакета, alias
Permission deniedпользователь, группа, sudo, ACL
Неверная версиясм. "Совместимость", --version

Совместимость

ОбластьПримечание
Версииактуальные LTS/стабильные релизы Git
Платформыофициальная матрица поддержки вендора
СтандартыRFC, ISO, спецификация API — см. таблицы выше

В подборках

Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:

СправочникиСправочник по CSS, Справочник по JavaScript, Справочник по HTML, Справочник по Node, Справочник по SQL, Справочник по React.