Ты прошёл весь курс. Ты знаешь объектную модель, индекс, rebase, rerere, reflog, подписи, partial clone. Но между знанием и ежедневной скоростью стоит одна скучная вещь: настройка git. Сырой Git из коробки в 2026 году всё ещё ведёт себя консервативно - создаёт ветку master с подсказкой, не подчищает удалённые ветки, не переиспользует разрешения конфликтов, требует руками выставлять upstream при первом push. Каждый день ты теряешь по чуть-чуть: лишний флаг тут, забытый --set-upstream там, конфликт, который уже разруливал на прошлой неделе.
Этот урок - капстоун. Мы соберём профессиональный gitconfig, ssh, подпись, глобальные ignore/attributes, pre-commit и фоновое обслуживание в один готовый сетап. И положим всё в dotfiles, чтобы новая машина поднималась за десять минут, а не за день. Это не косметика. Хорошее git окружение убирает целый класс ошибок и делает дорогую операцию (force-push, чистка веток, разбор конфликта) дешёвой и привычной.
Важно понимать иерархию конфигов, иначе будешь долго ловить призраков. Git читает четыре уровня и каждый следующий переопределяет предыдущий:
Код: Выделить всё
git config --show-origin --get core.editor
# file:/etc/gitconfig system (на всю машину)
# file:/Users/you/.gitconfig global (твой, главный)
# file:.git/config local (этот репозиторий)
# плюс worktree и командный -c
Код: Выделить всё
git config --list --show-origin | grep pull.rebase
# file:/Users/you/.gitconfig pull.rebase=true

Профессиональный gitconfig: identity, поведение, алиасы
Сердце сетапа - твой глобальный ~/.gitconfig. Разберём по секциям, что в нём должно быть и почему именно так. Это и есть оптимальная настройка git для рабочего дня.
Код: Выделить всё
[user]
name = Имя Фамилия
email = you@example.com
[init]
defaultBranch = main
[pull]
rebase = true
[fetch]
prune = true
pruneTags = true
[push]
autoSetupRemote = true
followTags = true
[rerere]
enabled = true
[branch]
sort = -committerdate
[column]
ui = auto
[diff]
colorMoved = zebra
algorithm = histogram
mnemonicPrefix = true
renames = copies
[merge]
conflictStyle = zdiff3
[rebase]
autosquash = true
autostash = true
updateRefs = true
push.autoSetupRemote=true - маленькая, но очень приятная штука: с 2.37 она есть, но по умолчанию выключена. С ней первый push новой ветки сам создаёт upstream, и ты забываешь про git push -u origin HEAD навсегда. rerere.enabled=true - reuse recorded resolution: Git запоминает, как ты разрулил конфликт, и при повторе того же конфликта (типично при долгом rebase или регулярном слиянии) подставляет решение сам. rebase.updateRefs (с 2.38) - спасение для stacked-веток: при rebase нижней ветки автоматически двигаются и все промежуточные ярлыки. merge.conflictStyle=zdiff3 показывает в конфликте общего предка, а не только две стороны - в разы понятнее, что реально разошлось.
Дальше - алиасы. Не превращай конфиг в свалку, держи 5-7 рабочих лошадок:
Код: Выделить всё
[alias]
s = status -sb
lg = log --graph --abbrev-commit --decorate \
--format=format:'%C(bold blue)%h%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)'
last = log -1 HEAD --stat
undo = reset --soft HEAD~1
unstage = restore --staged
amend = commit --amend --no-edit
cleanup = "!git branch --merged main | grep -vE '\\*|main|master' | xargs -r git branch -d"
sync = "!git switch main && git pull && git fetch --prune"
Код: Выделить всё
$ git cleanup
Deleted branch feature/login (was 3a4f1c2).
Deleted branch hotfix/typo (was 9b2e8d1).
Один конфиг, две личности: includeIf для work и personal
Типичная боль: на рабочих репозиториях надо коммитить с корпоративной почтой и подписывать корпоративным ключом, а на пет-проектах - личной. Раньше люди забывали переключиться и пушили в рабочий монорепо под gmail. Решение - условное включение includeIf по пути каталога. Раскладываешь репозитории по папкам и Git сам подхватывает нужную identity.
Код: Выделить всё
# ~/.gitconfig (общий хвост)
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
[includeIf "gitdir:~/personal/"]
path = ~/.gitconfig-personal
# ~/.gitconfig-work
[user]
email = you@company.com
signingkey = ~/.ssh/id_work.pub
Код: Выделить всё
$ cd ~/work/api && git config user.email
you@company.com
$ cd ~/personal/blog && git config user.email
you@gmail.com
Подключение и подпись - вторая половина сетапа. Генерим современный ed25519-ключ (отдельный на работу и на личное - так удобнее ротировать):
Код: Выделить всё
ssh-keygen -t ed25519 -C "you@company.com" -f ~/.ssh/id_work
ssh-keygen -t ed25519 -C "you@gmail.com" -f ~/.ssh/id_personal
Код: Выделить всё
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_work
IdentitiesOnly yes
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_personal
IdentitiesOnly yes
Подпись 2026 - это SSH-подпись, простой рекомендуемый дефолт (GPG остался для корпоративного легаси, Sigstore/gitsign - для CI-ботов). Никакой возни с keyserver, подписываешь тем же ключом, которым пушишь:
Код: Выделить всё
[gpg]
format = ssh
[gpg "ssh"]
allowedSignersFile = ~/.config/git/allowed_signers
[user]
signingkey = ~/.ssh/id_work.pub
[commit]
gpgsign = true
[tag]
gpgSign = true
Код: Выделить всё
# ~/.config/git/allowed_signers
you@company.com ssh-ed25519 AAAAC3NzaC1lZDI1...work
you@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1...personal
Код: Выделить всё
$ git commit -m "feat: setup signing"
$ git log --show-signature -1
commit 7f2a9c1 (HEAD -> main)
Good "git" signature for you@company.com with ED25519 key SHA256:abcd...
Глобальный .gitignore, .gitattributes и pre-commit
Мусор не должен попадать в каждый репозиторий по отдельности. Заведи глобальный ignore для машинно-специфичных вещей (артефакты ОС, файлы IDE), которым не место в проектном .gitignore:
Код: Выделить всё
git config --global core.excludesFile ~/.config/git/ignore
Код: Выделить всё
# ~/.config/git/ignore
.DS_Store
Thumbs.db
.idea/
.vscode/
*.swp
.env.local
.direnv/
Глобальный .gitattributes лечит вечную боль переносов строк и бинарных диффов. Нормализуем concovки строк и помечаем бинарники, чтобы Git не пытался показывать их как текст:
Код: Выделить всё
git config --global core.attributesFile ~/.config/git/attributes
Код: Выделить всё
# ~/.config/git/attributes
* text=auto eol=lf
*.png binary
*.pdf binary
*.lock -diff
package-lock.json -diff linguist-generated
Фреймворк pre-commit - это ловушка ошибок до того, как они попадут в историю. Кладёшь .pre-commit-config.yaml в репозиторий и ставишь один раз хуки:
Код: Выделить всё
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-merge-conflict
- id: check-added-large-files
- id: detect-private-key
Код: Выделить всё
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
$ git commit -m "wip"
trailing-whitespace.................Failed
- files were modified by this hook
detect-private-key..................Passed
Фоновое обслуживание и dotfiles-репозиторий
Раньше все вручную дёргали git gc. В 2026 это легаси-путь. Современное - git maintenance, который сам по расписанию делает лёгкое обслуживание (с 2.54 дефолтная стратегия ручного обслуживания - geometric repacking, без полной сборки мусора):
Код: Выделить всё
$ git maintenance start
$ git config --get-regexp maintenance
maintenance.auto false
maintenance.strategy incremental
И финальный аккорд - dotfiles git. Весь сетап выше бесполезен, если живёт только на одной машине. Превращаем конфиги в версионируемый репозиторий. Чистый способ без симлинков - bare-репозиторий поверх домашней папки:
Код: Выделить всё
git init --bare $HOME/.dotfiles
alias dot='git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dot config status.showUntrackedFiles no
dot add ~/.gitconfig ~/.ssh/config ~/.config/git/
dot commit -m "dotfiles: git setup"
dot remote add origin git@github-work:you/dotfiles.git
dot push -u origin main
Типичные грабли
- push.autoSetupRemote включён, но ты на отделившейся ветке с чужим именем - push создаст upstream не туда. Проверяй git status -sb перед первым пушем новой ветки.
- includeIf не срабатывает: забыл косую черту в конце gitdir-пути или репозиторий лежит вне ожидаемой папки. Диагностика - git config user.email из самого репо.
- SSH-подпись стоит, а GitHub пишет Unverified: публичный ключ добавлен в Authentication keys, но не в Signing keys - это РАЗНЫЕ списки.
- allowedSignersFile не настроен - git log --show-signature ругается на неизвестного подписанта, хотя подпись валидна. Это про верификацию, не про создание подписи.
- Положил приватный SSH-ключ в публичный dotfiles-репозиторий. Если случилось - немедленно ротируй ключ, удаления из истории мало.
- core.excludesFile задан, но игноришь там node_modules - на другой машине у коллеги их не игнорит. Машинно-специфичное в глобальный, общекомандное в проектный.
- Создай ~/.gitconfig с секциями user, init (defaultBranch=main), pull.rebase, fetch.prune, push.autoSetupRemote, rerere.enabled и алиасами undo, cleanup, lg.
- Сгенерируй ed25519-ключ, добавь его публичную часть в Signing keys аккаунта, включи gpg.format=ssh и commit.gpgsign=true.
- Сделай тестовый репозиторий, закоммить и проверь подпись через git log --show-signature -1 - убедись, что видишь Good signature.
- Заведи глобальные ignore и attributes в ~/.config/git/, проверь, что .DS_Store больше не попадает в git status.
- Запусти git maintenance start в репозитории и убедись через git config --get-regexp maintenance, что задачи зарегистрированы.
- Инициализируй bare dotfiles-репозиторий, добавь туда ~/.gitconfig (но НЕ приватные ключи) и сделай первый коммит.
- Чем reset --soft HEAD~1 (алиас undo) отличается от reset --hard HEAD~1 и почему для отмены последнего коммита берут именно soft?
- Почему в ~/.ssh/config критичен IdentitiesOnly yes, когда у тебя два ключа для одного хоста github.com?
- В чём разница между Authentication keys и Signing keys на GitHub и как она проявляется в бейдже Verified?
- Почему node_modules кладут в проектный .gitignore, а .DS_Store - в глобальный core.excludesFile?
Профессиональный сетап - это не магия, а дисциплина: один продуманный gitconfig (identity, поведение, алиасы), SSH с host-алиасами и подписью, глобальные ignore/attributes, pre-commit как ловушка ошибок, git maintenance в фоне и всё это в dotfiles под версией. Собрав это один раз, ты разворачиваешь готовое git окружение на новой машине за десять минут, а не настраиваешь по крупицам неделями. Это финальный кирпич курса: теперь знание объектной модели и rebase подкреплено инструментом, который не даёт ошибиться в рутине.