Skip to content

Instantly share code, notes, and snippets.

@dmitry-osin
Created January 16, 2026 22:54
Show Gist options
  • Select an option

  • Save dmitry-osin/6fc19508e936b8e06f2a9c4c38189e89 to your computer and use it in GitHub Desktop.

Select an option

Save dmitry-osin/6fc19508e936b8e06f2a9c4c38189e89 to your computer and use it in GitHub Desktop.
GIT от новичка до эксперта на русском

Уровень 1. Глава 1: Архитектура Git и Настройка

1. Философия: Централизованные vs Распределенные

Большинство старых систем (например, SVN или Perforce) — Централизованные (CVCS). Это значит, что история хранится на одном сервере. Если сервер упал — работа встала. Если нет интернета — вы не можете сохранить версию.

Git — это Распределенная система (DVCS). Когда вы делаете git clone, вы не просто качаете последние файлы. Вы скачиваете весь репозиторий целиком, каждый файл, каждый коммит за всю историю проекта.

  • Плюс: Ваш локальный компьютер — это полноценный бэкап.
  • Плюс: 99% операций (коммит, просмотр истории, переключение веток) происходят локально и мгновенно, интернет не нужен.

2. Главная концепция: Три состояния (The Three States)

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

  1. Working Directory (Рабочая директория): Это ваша папка с файлами, которую вы видите в редакторе кода. Здесь вы пишете код. Это "песочница".
  2. Staging Area (Index / Область подготовленных файлов): Это промежуточная зона. Сюда вы добавляете только те изменения, которые хотите включить в следующий снимок. Представьте это как "коробку", которую вы наполняете перед отправкой.
  3. Repository (.git directory): Место, где Git хранит базу данных всех версий (коммитов). Когда вы делаете коммит, содержимое "коробки" (Staging Area) навсегда сохраняется здесь.

3. Жизненный цикл файла

Файл в вашей папке может находиться в одном из 4 состояний:

  1. Untracked (Неотслеживаемый): Новый файл, про который Git еще не знает. Он не попадет в коммит, пока вы явно не скажете Git следить за ним.
  2. Unmodified (Неизмененный): Файл, который уже есть в базе Git, и вы его не трогали с момента последнего коммита.
  3. Modified (Измененный): Файл есть в базе, вы его отредактировали, но еще не подготовили к коммиту (не положили в Staging Area).
  4. Staged (Подготовленный): Измененный файл, который вы отметили как готовый к коммиту.

4. Практика: Первичная конфигурация

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

Откройте терминал.

Настройка личности (Identity)

# Устанавливаем имя автора (будет видно в истории)
# --global означает, что настройка применится для всех проектов текущего пользователя ОС
git config --global user.name "Ivan Ivanov"

# Устанавливаем email
# Важно: если вы работаете с GitHub/GitLab, этот email должен совпадать с тем, 
# на который зарегистрирован аккаунт, чтобы коммиты привязались к профилю.
git config --global user.email "ivan@example.com"

Настройка редактора

Когда вы делаете коммит без сообщения, Git открывает текстовый редактор. По умолчанию это часто Vim, из которого новичку трудно выйти. Лучше настроить что-то привычное (VS Code, Nano, Notepad++).

# Назначить VS Code основным редактором для Git
# --wait говорит терминалу ждать, пока вы не закроете окно редактора
git config --global core.editor "code --wait"

Настройка переносов строк (Line Endings)

Это критически важно, если в команде работают люди на разных ОС (Windows и macOS/Linux).

  • В Windows конец строки — это CRLF (Carriage Return + Line Feed).
  • В macOS/Linux — это LF (Line Feed).

Если не настроить, Git будет видеть изменения в каждой строке файла просто потому, что кто-то открыл его на другой ОС.

Для Windows:

# При коммите конвертировать CRLF в LF, при выгрузке (checkout) — обратно в CRLF.
git config --global core.autocrlf true

Для macOS / Linux:

# При коммите конвертировать CRLF в LF (на всякий случай), при выгрузке ничего не трогать (оставлять LF).
git config --global core.autocrlf input

Имя главной ветки

Раньше главной веткой по умолчанию была master. Сейчас индустрия переходит на main. Чтобы при создании новых проектов сразу создавалась main:

git config --global init.defaultBranch main

Проверка настроек

Чтобы увидеть все, что мы сейчас настроили:

git config --list

Итог главы: Мы разобрались, что Git хранит все локально, поняли концепцию "Рабочая папка -> Индекс -> Репозиторий" и настроили Git, чтобы он знал, кто мы и как обрабатывать файлы.


Уровень 1. Глава 2: Базовый цикл работы (The Daily Routine)

В этой главе мы пройдем полный цикл: создание репозитория, написание кода, подготовка изменений и их фиксация. Это те команды, которые вы будете вводить 90% времени.

Представим, что мы начинаем новый проект.

1. Создание репозитория: init vs clone

У вас есть два пути начать работу с Git:

А. Начать с нуля (git init) Если у вас есть локальная папка с кодом (или пустая папка), и вы хотите добавить в нее Git.

# Создаем папку проекта
mkdir my-project
cd my-project

# Инициализируем Git
git init

Что произошло: Внутри папки появилась скрытая директория .git. Именно в ней живет база данных Git. Пока вы не удалите эту папку, история вашего проекта в безопасности.

Б. Скачать существующий (git clone) Если проект уже есть на сервере (GitHub/GitLab/Bitbucket), вы его клонируете.

# Скачивает проект целиком, создавая папку с именем репозитория
git clone https://github.com/user/repo.git

2. Проверка состояния: git status

Это ваша главная команда. В любой непонятной ситуации вводите git status. Она показывает, что сейчас происходит в вашей Рабочей директории и Индексе.

Давайте создадим файл:

echo "Hello World" > file.txt

Теперь спросим у Git, что он видит:

git status

Вывод: Git скажет Untracked files: file.txt. Это состояние Untracked. Git видит файл, но не следит за ним. Если вы удалите файл сейчас, Git не сможет его восстановить.


3. Индексация: git add

Чтобы изменение попало в историю, его нужно сначала перенести в Staging Area (Индекс). Это как собрать товары в коробку перед тем, как заклеить её скотчем.

# Добавить конкретный файл в индекс
git add file.txt

# ИЛИ добавить ВСЕ измененные и новые файлы в текущей папке (чаще всего используют это)
git add .

Снова проверяем:

git status

Вывод: Changes to be committed. Файл теперь горит зеленым (в большинстве терминалов). Это состояние Staged. Файл в "коробке", готов к отправке.


4. Фиксация изменений: git commit

Это момент истины. Мы делаем "снэпшот" (слепок) состояния всех файлов, находящихся в Staging Area, и сохраняем его в историю навсегда.

# -m означает "message" (сообщение)
git commit -m "Initial commit"

Что произошло:

  1. Git взял всё из Staging Area.
  2. Упаковал это в объекты.
  3. Присвоил коммиту уникальный ID (хеш, например a1b2c3d).
  4. Сдвинул указатель текущей ветки (main) на этот новый коммит.

Важное отступление: Как писать хорошие сообщения

Хороший коммит-месседж спасает жизни.

  • Плохо: "fix", "update", "changed code".
  • Хорошо: "Add login functionality", "Fix NPE in UserAuth service".

Стандарт индустрии — использовать повелительное наклонение (Imperative mood), как будто вы приказываете коду:

  • (Make it) Add feature X
  • (Make it) Fix bug Y
  • (Make it) Remove file Z

5. Цикл изменений (Edit -> Add -> Commit)

Давайте изменим наш файл.

echo "New line" >> file.txt
  1. Проверяем: git status. Вывод: modified: file.txt. Файл отслеживается, но изменен.
  2. Смотрим разницу: git diff. Покажет конкретные добавленные строки.
  3. Индексируем: git add . Переносим изменения в Staging Area.
  4. Коммитим: git commit -m "Update file.txt content"

Лайфхак: Если файлы уже отслеживаются (не новые), можно пропустить git add и сделать сразу коммит:

# Флаг -a (all) автоматически делает add для всех modified файлов перед коммитом
git commit -a -m "Update content shortcut"

Но будьте осторожны: это не добавит новые (untracked) файлы.


6. Просмотр истории: git log

Как посмотреть, что мы натворили?

# Показать полную историю
git log

Вы увидите:

  • Хеш коммита (SHA-1).
  • Автора.
  • Дату.
  • Сообщение.

Если история длинная, используйте компактный вид:

# --oneline: один коммит — одна строка (короткий хеш + сообщение)
git log --oneline

Пример вывода:

a1b2c3d Update content shortcut
f4e5d6c Initial commit


Итог главы

Ваш повседневный цикл выглядит так:

  1. Поработали с кодом.
  2. git status — посмотрели, что изменилось.
  3. git add . — подготовили изменения (собрали коробку).
  4. git commit -m "Описание" — сохранили версию (заклеили коробку и отправили на склад).

Уровень 1. Глава 3: Файл .gitignore

Это последняя глава первого уровня. После нее вы будете полностью готовы к "одиночному плаванию".

В любом проекте есть мусор. Это файлы, которые генерируются автоматически или являются локальными настройками, и им не место в репозитории. Примеры:

  • Папки скомпилированного кода (bin, build, target, node_modules).
  • Временные файлы IDE (.idea, .vscode).
  • Системные файлы (.DS_Store на Mac, Thumbs.db на Windows).
  • Логи (*.log).
  • Секреты и конфиги с паролями (.env).

Если вы закоммитите эти файлы, вы "загрязните" историю и будете мешать коллегам (у них могут быть другие настройки IDE или ОС).

Для решения этой проблемы существует файл .gitignore.


1. Как это работает

Git проверяет этот файл каждый раз перед командой git status или git add. Если файл подпадает под правило в .gitignore, Git делает вид, что этого файла не существует. Он даже не покажет его в списке Untracked files.

Важно: .gitignore работает только для Untracked файлов. Если вы уже успели закоммитить файл, а потом добавили его в игнор — Git продолжит следить за ним. (Как это исправить — ниже).

2. Синтаксис

Создайте в корне проекта файл с именем .gitignore (точка в начале обязательна). Это обычный текстовый файл.

Пример содержимого для Java-проекта:

# Игнорировать все файлы с расширением .log
*.log

# Игнорировать папку target со всем содержимым
target/

# Игнорировать файлы .class, где бы они ни находились
**/*.class

# Игнорировать конкретный файл
secret_config.properties

# Исключение из правил (знак восклицания)
# Игнорировать все .md файлы, КРОМЕ README.md
*.md
!README.md

Разбор символов:

  • * — любые символы.
  • / в конце — означает директорию.
  • ! — "не игнорировать" (инверсия).
  • # — комментарий.

3. Глобальный .gitignore

Есть мусор, который создаете лично вы (ваша ОС или редактор), а не проект. Например, macOS создает .DS_Store в каждой папке. Заставлять каждого коллегу добавлять это в .gitignore проекта — дурной тон.

Лучше настроить глобальный список игнорирования на вашем компьютере:

  1. Создайте файл ~/.gitignore_global в домашней папке.
  2. Добавьте туда системный мусор (.DS_Store, Thumbs.db).
  3. Сообщите Git об этом файле:
git config --global core.excludesfile ~/.gitignore_global

Теперь эти файлы будут игнорироваться во всех ваших проектах.

4. Типичная проблема: "Git все равно видит файл!"

Ситуация: Вы случайно закоммитили папку build/ или файл конфига. Потом спохватились, добавили build/ в .gitignore, но при команде git status Git все равно показывает изменения в этой папке.

Причина: .gitignore игнорирует только новые файлы. Если файл уже в базе (tracked), Git обязан отслеживать изменения в нем.

Решение: Нужно удалить файл из индекса (перестать следить), но оставить его на диске (не удалять физически).

# Удалить из индекса (--cached), но оставить файл на месте
git rm --cached filename

# Если нужно перестать следить за целой папкой
git rm -r --cached foldername/

После этого сделайте коммит: git commit -m "Stop tracking build folder". Теперь правило из .gitignore начнет работать.


Полезный инструмент

Не пишите .gitignore вручную с нуля. Есть сайт gitignore.io. Вы просто вводите свои технологии (например: Java, IntelliJ IDEA, Maven, Windows), и он генерирует идеальный файл, учитывающий все нюансы.


Итог Уровня 1

Поздравляю! Мы закрыли блок "Фундамент". ✅ Вы понимаете архитектуру (Working Dir -> Index -> Repo). ✅ Вы настроили Git под себя. ✅ Вы умеете создавать коммиты. ✅ Вы умеете прятать мусор через .gitignore.


Уровень 2. Глава 1: Магия ветвления (Branching)

В старых системах (SVN) создание ветки означало физическое копирование всех файлов проекта в новую папку. Это было долго и занимало место. В Git ветка (branch) — это просто подвижный указатель (ссылка) на один конкретный коммит. Это файл весом в 41 байт. Поэтому создание веток происходит мгновенно, даже если в проекте миллион файлов.

Ветвление позволяет создавать "параллельные вселенные" для разработки новых функций, не ломая основной код (main).


1. Как это устроено (Pointer mechanics)

Представьте историю коммитов как цепочку бусин.

  • Коммит знает, кто его родитель.
  • Ветка (напр. main) — это стикер, приклеенный к последней бусине.
  • HEAD — это "лазерная указка", которая говорит: "Вы находитесь здесь". Обычно HEAD указывает на активную ветку.

Когда вы делаете новый коммит, ветка (стикер), на которую указывает HEAD, автоматически переклеивается на новую бусину.

2. Создание и переключение

Раньше для всего использовалась команда git checkout. Но она была перегружена (делала и переключение веток, и восстановление файлов). В современных версиях Git (2.23+) появились специализированные команды.

Старая школа:

# Создать ветку и переключиться
git checkout -b feature-login

Новая школа (рекомендуется):

# Создать ветку (branch)
git branch feature-login

# Переключиться на неё (switch)
git switch feature-login

# Создать И сразу переключиться (create)
git switch -c feature-login

Теперь все изменения, которые вы делаете и коммитите, будут наращивать историю ветки feature-login, а ветка main останется на месте.

3. Слияние (Merging)

Вы закончили работу в feature-login и хотите вернуть изменения в main. Сначала нужно перейти в ту ветку, КУДА мы хотим влить изменения:

git switch main
git merge feature-login

Здесь возможны два сценария:

Сценарий А: Fast-forward (Перемотка)

Если за то время, пока вы работали в feature-login, в ветке main не появилось новых коммитов, Git делает простую вещь: он берет указатель main и "перематывает" его вперед до уровня feature-login.

  • Результат: Линейная история.
  • Новый коммит: Не создается.

Сценарий Б: Merge Commit (Истинное слияние)

Если main тоже ушла вперед (например, коллега успел что-то запушить), история разветвилась. "Перемотать" нельзя. Git вынужден:

  1. Взять верхушку main.
  2. Взять верхушку feature-login.
  3. Найти их общего предка.
  4. Создать новый коммит слияния (Merge Commit), у которого будет два родителя.

В этот момент может открыться редактор для ввода сообщения коммита (обычно: Merge branch 'feature-login'). Просто сохраните и закройте.

4. Удаление веток

Ветка нужна только пока идет работа. После слияния указатель feature-login больше не нужен (история уже в main).

# Безопасное удаление (delete)
# Git не даст удалить ветку, если изменения из неё еще не слиты в текущую ветку.
git branch -d feature-login

# Принудительное удаление (Delete Force)
# Используется, если вы зашли в тупик, работа не нужна, и вы хотите просто выбросить ветку.
git branch -D feature-login

Практическое задание

Попробуйте этот сценарий в своем тестовом репозитории:

  1. git switch -c new-feature (создали ветку).
  2. Создайте файл, сделайте коммит.
  3. git switch main (вернулись назад).
  4. Заметьте, что файл исчез! (Git восстановил состояние main).
  5. git merge new-feature (влили изменения).
  6. git branch -d new-feature (удалили указатель).

Итог главы: Мы научились создавать параллельные потоки разработки. Пока все это происходило локально на вашем компьютере.


Уровень 2. Глава 2: Удаленные репозитории (Remotes)

Пока что весь ваш код жил только на вашем жестком диске. Если диск сгорит — проект пропадет. Чтобы этого не случилось и чтобы работать в команде, нам нужен сервер (GitHub, GitLab, Bitbucket).

В терминологии Git сервер — это Remote.


1. Связь с внешним миром

Связь локального репозитория с сервером настраивается одной командой.

# git remote add <короткое_имя> <url>
git remote add origin https://github.com/myname/myproject.git
  • Что такое origin? Это не магическое слово, а стандартное имя по умолчанию для "основного сервера". Вы можете назвать его backup, gitlab или prod, но все привыкли к origin.
  • Проверка: git remote -v покажет список всех подключенных серверов.

HTTPS vs SSH

Как Git будет авторизовываться на сервере?

  1. HTTPS: Просто, но при каждом пуше нужно вводить логин/токен (или настраивать Credential Helper).
  2. SSH: Выбор профессионалов. Вы генерируете пару ключей (ssh-keygen), публичный кладете в настройки GitHub, приватный остается у вас. Git общается с сервером без паролей.

2. Отправка изменений: git push

Вы сделали коммиты локально. На сервере их еще нет. Нужно "толкнуть" их туда.

Первый пуш (настройка связи):

# -u (или --set-upstream) связывает вашу локальную ветку main 
# с веткой main на сервере origin.
git push -u origin main

После того как связь установлена (благодаря -u), в будущем достаточно писать просто:

git push

Git сам поймет, куда и какую ветку отправлять.


3. Получение изменений: Fetch vs Pull

Это самый важный теоретический момент главы. Многие новички используют git pull вслепую, не понимая, что это составная команда.

В Git есть Tracking branches (следящие ветки). Это копии состояния сервера на вашем компьютере. Они называются origin/main, origin/feature. Вы не можете их редактировать, они обновляются только при связи с сервером.

А. git fetch (Разведка)

Эта команда стучится на сервер, скачивает все новые коммиты, обновляет ваши следящие ветки (origin/main), но НЕ трогает ваши рабочие файлы. Это безопасно. Вы можете посмотреть, что там написали коллеги, не ломая свою работу.

git fetch origin
# Теперь можно сравнить свою работу с тем, что пришло:
git diff main origin/main

Б. git pull (Штурм)

Это комбинация двух команд: fetch + merge. Она скачивает изменения И тут же пытается влить их в вашу текущую ветку.

git pull origin main
# Равносильно:
# 1. git fetch origin
# 2. git merge origin/main

Совет эксперта: Если вы долго не обновлялись, лучше сделать fetch, посмотреть изменения через git log origin/main, и только потом делать merge. Но для рутины pull вполне подходит.


4. Типичный сценарий работы в команде

Представьте, что вы и ваш коллега работаете над одной веткой.

  1. Коллега делает push.
  2. Вы пытаетесь сделать push, но Git выдает ошибку: "Rejected (non-fast-forward)".
  • Причина: На сервере есть коммиты, которых нет у вас. История на сервере ушла вперед. Вы не можете просто перезаписать её.
  1. Решение: Вы должны сначала забрать чужую работу и объединить её со своей.
git pull  # Скачать и слить
git push  # Теперь можно отправлять

Именно на шаге 3 (при git pull) чаще всего возникают конфликты. О них — в следующей главе.


Итог главы: Мы научились связывать локальный репозиторий с облаком (remote), отправлять код (push) и, главное, поняли разницу между аккуратным скачиванием (fetch) и скачиванием со слиянием (pull).


Уровень 2. Глава 3: Разрешение конфликтов (Conflict Resolution)

Конфликт — это не ошибка. Это ситуация, когда Git говорит: «Я вижу два изменения в одной и той же строке кода, и я недостаточно умен, чтобы понять, какое из них правильное. Человек, решай ты».

1. Анатомия конфликта

Конфликты чаще всего возникают при git merge или git pull. Представьте:

  • Вася в ветке main изменил строку 10 на print("Hello").
  • Петя в ветке feature изменил строку 10 на print("Hi").
  • При попытке слияния Git паникует.

Git останавливает процесс слияния и помечает проблемные файлы как Unmerged.

Внутри файла это выглядит так:

<<<<<<< HEAD
print("Hello")
=======
print("Hi")
>>>>>>> feature

  • <<<<<<< HEAD: Начало вашей версии (то, что было в текущей ветке).
  • =======: Разделитель.
  • >>>>>>> feature: Конец пришедшей версии (из ветки, которую вливаем).

2. Алгоритм решения

Не паникуйте. Вы ничего не сломали.

  1. Найти врага: git status покажет список файлов, где есть конфликты (они будут красными в секции Unmerged paths).
  2. Отредактировать: Откройте файл в редакторе. Вам нужно удалить маркеры (<<<, ===, >>>) и оставить только правильный код.
  • Вариант А (Ours): Оставить print("Hello").
  • Вариант Б (Theirs): Оставить print("Hi").
  • Вариант В (Both): Объединить (print("Hello"); print("Hi");).
  1. Сохранить: Сохраните файл в редакторе.
  2. Пометить как решенный: Это самое важное. Git не знает, что вы все исправили, пока вы не сделаете git add.
git add file.py
  1. Завершить: Сделайте коммит. Обычно Git сам подставляет сообщение "Merge branch ...".
git commit

Совет: Современные IDE (IntelliJ IDEA, VS Code) показывают конфликты в виде удобного интерфейса с тремя окнами ("Ваше", "Результат", "Их"), где можно просто кликать стрелочки, не удаляя маркеры вручную.


Итог Уровня 2

Поздравляю! Вы прошли самый сложный психологический барьер. ✅ Вы умеете ветвиться. ✅ Вы работаете с сервером. ✅ Вы не боитесь слова "КОНФЛИКТ".

Переходим к Уровню 3: Инструментарий "Time Travel". Мы научимся исправлять ошибки: отменять изменения в файлах, откатывать коммиты и спасать удаленное.


Уровень 3. Глава 1: Отмена изменений (Undo)

Git прощает почти все. Главное — знать правильную команду. В этой главе мы разберем три степени "отката": restore, reset и revert.

1. git restore: Локальная отмена (Ctrl+Z)

Сценарий: Вы писали код, все сломали, файл еще не закоммичен. Хотите вернуть файл к состоянию "как было в последнем коммите".

Раньше для этого использовали git checkout, но теперь есть специальная команда.

# Отменить изменения в файле в Рабочей директории (вернуть как было)
# Внимание: изменения пропадут безвозвратно!
git restore file.txt

# Сценарий: Вы случайно сделали 'git add', но передумали коммитить.
# Файл нужно убрать из Staging (Unstage), но оставить изменения в файле.
git restore --staged file.txt

2. git reset: Машина времени

Сценарий: Вы сделали коммит (или 5 коммитов), поняли, что это бред, и хотите "отмотать время назад", будто этих коммитов не было.

Команда reset перемещает указатель вашей ветки назад по истории. У неё есть три режима жесткости.

Предположим, мы хотим отменить последний коммит (HEAD~1):

А. Soft Reset (Мягкий) Самый безопасный.

git reset --soft HEAD~1
  • Коммит: Исчезает.
  • Изменения: Остаются в Staging Area (зеленые в status).
  • Зачем: Чтобы "пересобрать" коммит. Например, вы сделали коммит, забыли файл, сделали reset --soft, добавили файл и закоммитили снова (хотя для этого лучше amend, но логика такая).

Б. Mixed Reset (Стандартный) Работает по умолчанию.

git reset --mixed HEAD~1  # или просто git reset HEAD~1
  • Коммит: Исчезает.
  • Изменения: Остаются в Working Directory (красные в status), но убраны из индекса.
  • Зачем: Вы хотите продолжить работу над кодом, но разбить этот коммит на два разных.

В. Hard Reset (Жесткий) Опасно!

git reset --hard HEAD~1
  • Коммит: Исчезает.
  • Изменения: Уничтожаются. Файлы на диске возвращаются к состоянию прошлого коммита.
  • Зачем: "Всё сломалось, хочу вернуть как было вчера".

3. git revert: Безопасная отмена

Сценарий: Вы уже запушили плохой коммит на сервер (origin/main). Если вы сделаете reset и запушите снова (push --force), вы сломаете историю всем коллегам. В общей ветке запрещено переписывать историю.

Вместо удаления старого коммита, мы создаем новый коммит, который делает обратное действие (удаляет добавленные строки, добавляет удаленные).

# Создать "анти-коммит" для указанного хеша
git revert <commit_hash>

История пойдет вперед, но код вернется назад. Это безопасно для командной работы.


Резюме главы:

  • Не закоммитили? git restore.
  • Закоммитили локально? git reset (soft/mixed/hard).
  • Запушили? git revert.

Уровень 3. Глава 2: Временный карман (Stashing)

Сценарий: Вы находитесь в середине сложной задачи в ветке feature. Код "разобран": ничего не компилируется, повсюду print-ы. Вдруг пишет лид: "Срочный баг на продакшене! Бросай всё, чини!"

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

Решение: Stashing (Припрятать). Это временный буфер (стек), куда можно сложить текущие изменения, чтобы получить чистую рабочую директорию.

1. Основные команды

# 1. Спрятать изменения
git stash
# Теперь 'git status' покажет, что всё чисто.
# Можно переключаться на другую ветку, чинить баг и коммитить.

Когда вы вернулись обратно в свою ветку feature:

# 2. Вернуть изменения обратно
git stash pop
  • pop делает две вещи: применяет изменения и удаляет их из стека.
  • Если хотите применить, но оставить копию в стеке (на всякий случай): git stash apply.

2. Подводный камень: Untracked files

По умолчанию git stash прячет только отслеживаемые (tracked) файлы. Если вы создали новый файл и не сделали ему git add, команда git stash оставит его валяться в папке.

Чтобы спрятать всё, включая новые файлы:

git stash -u  # или --include-untracked

3. Работа с несколькими тайниками

Stash — это стек. Вы можете делать git stash много раз.

# Посмотреть список спрятанного
git stash list
# Вывод:
# stash@{0}: WIP on feature-login: ...
# stash@{1}: WIP on master: ...

Чтобы достать конкретный тайник (не последний):

git stash pop stash@{1}

Уровень 3. Глава 3: Навигация и Поиск (Sherlock Mode)

Git помнит всё. Проблема в том, как найти нужное в гигабайтах истории.

1. git diff: Что именно изменилось?

Просто git diff показывает разницу между Working Dir и Staging. Но это лишь вершина айсберга.

  • git diff: Работа vs Индекс (что я изменил, но не добавил?).
  • git diff --staged: Индекс vs Последний коммит (что я собираюсь закоммитить?).
  • git diff HEAD~1 HEAD: Сравнить последний коммит с предпоследним.
  • git diff branchA branchB: Сравнить две ветки.

2. git blame: Кто это сделал?!

Вы нашли кусок ужасного кода и хотите узнать автора.

git blame filename.java

Git покажет файл построчно, и напротив каждой строки будет имя автора и хеш коммита. Совет: В IDE (IntelliJ/VS Code) это работает удобнее через правый клик -> Annotate with Git Blame.

3. git grep: Поиск по всей истории

Обычный grep или Ctrl+F ищет только в текущих файлах. А если вы помните, что удалили функцию calculateTax() месяц назад, и она срочно понадобилась?

git grep "calculateTax" $(git rev-list --all)

Это найдет текст даже в удаленных файлах и старых коммитах.

4. git bisect: Бинарный поиск бага

Это "ядерное оружие" отладки. Ситуация: В версии v2.0 все работало. В v2.5 (спустя 100 коммитов) тесты падают. Вы не знаете, какой из 100 коммитов все сломал.

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

  1. Запускаем: git bisect start.
  2. Говорим, что сейчас всё плохо: git bisect bad.
  3. Говорим, где всё было хорошо: git bisect good v2.0.

Git сам переключит вас на середину истории (коммит №50). Вы проверяете (запускаете тест).

  • Если работает: говорите git bisect good. Git понимает, что ошибка во второй половине (51-100), и прыгает на №75.
  • Если не работает: говорите git bisect bad. Ошибка в первой половине (1-49), Git прыгает на №25.

За 6-7 шагов Git найдет тот самый коммит, который внес баг. В конце не забудьте: git bisect reset.


Итог Уровня 3: Мы закончили с инструментами исправления и поиска. Вы теперь можете отменять ошибки, прятать код в карман и находить иголку в стоге сена истории.


Уровень 4. Глава 1: Git Rebase (Переписываем историю)

Добро пожаловать в "Божественный режим". До этого момента мы только добавляли что-то в историю. Теперь мы будем её менять.

Главный инструмент здесь — Rebase (Перебазирование). Это то, что отличает аккуратного сеньора от джуниора, который оставляет после себя "спагетти" из коммитов.

1. Rebase vs Merge: Битва идеологий

Представьте ситуацию: вы отвели ветку feature от main. Пока вы работали, в main появились новые коммиты. Теперь вам нужно забрать эти обновления к себе.

У вас два пути:

А. Merge (Слияние)

  • Что делает: Создает специальный "Merge Commit", который связывает две истории.
  • Результат: История выглядит как "ромбик" или косичка.
  • Плюс: Это "честная" история. Видно, когда именно вы ответвились и когда слились.
  • Минус: Если таких веток много, история превращается в нечитаемый хаос.

Б. Rebase (Перебазирование)

  • Что делает: Git берет ваши коммиты из feature, временно откладывает их, обновляет базу ветки до актуального main, а затем накатывает ваши коммиты сверху по одному.
  • Результат: Абсолютно линейная история, как будто вы начали работу над фичей только что, от самого свежего main.
  • Плюс: Идеальная чистота истории.
  • Минус: Вы меняете хеши коммитов. История переписывается.

2. Как делать Rebase (Практика)

# 1. Переходим в свою ветку
git switch feature

# 2. Запускаем перебазирование на свежий main
git rebase main

Что происходит в этот момент: Git начинает применять ваши коммиты по очереди. Если в первом коммите конфликт — Git остановится.

Алгоритм при конфликте:

  1. git status (видим конфликт).
  2. Исправляем файл вручную.
  3. git add fixed_file.txt (помечаем как решенный).
  4. ВАЖНО: Не делайте git commit!
  5. Продолжаем процесс:
git rebase --continue

Паническая кнопка: Если вы запутались в конфликтах и хотите всё бросить:

git rebase --abort

Всё вернется к состоянию до начала ребейза.

3. Золотое правило Rebase

Так как Rebase создает новые коммиты (даже если контент тот же, хеш меняется), это деструктивная операция.

НИКОГДА не делайте rebase для публичных веток (например, main/master), которыми пользуются другие люди.

Если вы сделаете rebase ветки, которую уже скачал ваш коллега, у вас разойдутся истории, и восстановить это будет очень больно. Rebase — только для ваших личных, локальных веток перед отправкой кода.


Уровень 4. Глава 2: Интерактивный Rebase (Playbook)

Это самый мощный инструмент для "причесывания" кода. Если обычный rebase просто переносит ветку, то Interactive Rebase (-i) позволяет редактировать коммиты в процессе.

Сценарий: Вы сделали 4 коммита:

  1. "Start login logic"
  2. "WIP: Fix typo"
  3. "Finish login"
  4. "Forgot to add styles"

Вы хотите превратить это в один красивый коммит "Implement Login Feature" перед тем, как показать коллегам.

1. Запуск

# "Хочу отредактировать последние 4 коммита"
git rebase -i HEAD~4

Git откроет текстовый редактор (Vim/Nano/Code) со списком коммитов. Выглядит это так:

pick a1b2c Start login logic
pick d3e4f WIP: Fix typo
pick g5h6i Finish login
pick j7k8l Forgot to add styles

2. Команды редактора

В начале каждой строки стоит слово pick (оставить как есть). Вы можете менять эти слова на команды (Git подскажет их список внизу файла):

  • reword (r): Оставить коммит, но дать отредактировать сообщение.
  • edit (e): Остановить выполнение на этом коммите, чтобы вы могли поправить файлы (добавить/удалить что-то внутри кода).
  • squash (s): Слить этот коммит с предыдущим (верхним).
  • fixup (f): То же, что squash, но выкинуть сообщение коммита (идеально для исправлений опечаток).
  • drop (d): Удалить коммит вообще (будто его не было).

3. Реализация сценария (Squash)

Мы хотим слить всё в первый коммит. Редактируем файл так:

pick a1b2c Start login logic
squash d3e4f WIP: Fix typo      <-- Сливаем с верхним
squash g5h6i Finish login       <-- Сливаем с результатом выше
squash j7k8l Forgot to add styles <-- Сливаем с результатом выше

  1. Сохраняем и закрываем редактор.
  2. Git начнет применять изменения.
  3. Так как мы просили squash, Git откроет редактор еще раз и спросит: "Какое общее сообщение сделать для этого мега-коммита?".
  4. Мы пишем: "Implement Login Feature".
  5. Готово!

Теперь в истории (git log) вместо 4 мусорных коммитов у вас один идеальный.


Итог Уровня 4

Теперь вы владеете инструментами манипуляции историей.

  • rebase делает историю линейной.
  • rebase -i (squash/fixup) делает историю чистой

Уровень 5. Глава 1: Git под капотом (Internals)

Добро пожаловать в машинное отделение. Большинство разработчиков знают только "Фарфоровые" (Porcelain) команды: add, commit, checkout. Это красивые ручки и рычаги. Но чтобы стать экспертом и чинить репозитории, когда всё сломалось, нужно знать "Сантехнические" (Plumbing) команды и устройство базы данных Git.

Git — это Content-Addressable Filesystem (Файловая система, адресуемая по содержимому), построенная поверх обычной файловой системы.

1. Всё есть SHA-1

В основе Git лежит простая идея:

  1. Git берет контент (файл, структуру папки, сообщение коммита).
  2. Считает хеш (SHA-1) от этого контента.
  3. Использует этот хеш (40 символов) как имя файла.
  4. Сжимает контент (zlib) и кладет его в папку .git/objects.

Если у вас есть два файла с абсолютно одинаковым содержимым в разных папках проекта, Git сохранит только один объект (Blob) и будет ссылаться на него дважды. Это дедупликация "из коробки".


2. Четыре кита (Типы объектов)

В базе данных Git всего 4 типа объектов.

А. Blob (Binary Large Object)

Хранит содержимое файла.

  • Что внутри: Текст кода или бинарные данные.
  • Чего нет: Имени файла, прав доступа, времени создания.
  • Аналогия: Лист бумаги с текстом.

Б. Tree (Дерево)

Хранит структуру директории.

  • Что внутри: Список, сопоставляющий имена файлов с хешами их Blobs (или других Trees — подпапок).
  • Аналогия: Оглавление папки.

В. Commit (Коммит)

Хранит снэпшот состояния проекта.

  • Что внутри:
  • Ссылка на главный объект Tree (корень проекта).
  • Автор и дата.
  • Сообщение коммита.
  • Ссылка на Родителя (предыдущий коммит). Именно эта ссылка выстраивает цепочку истории.

Г. Tag (Тег)

Именованная метка.

  • Что внутри: Ссылка на конкретный Commit + сообщение тега + подпись GPG (если есть).

3. Лабораторная работа: Сантехника (Plumbing)

Давайте "вскроем" Git и посмотрим на объекты вручную, используя команду git cat-file.

Зайдите в любой репозиторий и выполните:

Шаг 1: Посмотрим на последний коммит

# -p (pretty print) показывает содержимое объекта в читаемом виде
git cat-file -p HEAD

Вывод:

tree a1b2c3d...       <-- Ссылка на "фотографию" файлов
parent e5f6g7h...     <-- Ссылка на прошлый коммит
author Ivan <...> 1705666...
committer Ivan <...> 1705666...

Fix login bug         <-- Сообщение

Шаг 2: Посмотрим на дерево (Tree) Скопируйте хеш из строки tree (в примере a1b2c3d...) и подставьте в команду:

git cat-file -p a1b2c3d

Вывод:

100644 blob 8h9i0j...    README.md
040000 tree 2k3l4m...    src

Видите? Git просто сопоставляет имя README.md с объектом-блобом 8h9i0j....

Шаг 3: Посмотрим на содержимое файла (Blob) Скопируйте хеш блоба 8h9i0j...:

git cat-file -p 8h9i0j

Вывод: Текст вашего README.md.

Вывод главы: Коммит — это просто обертка, указывающая на дерево, которое указывает на блобы. Вся магия Git — это граф ссылок.


4. Что такое ветка на самом деле? (Refs)

Многие думают, что ветка — это какая-то сложная структура. Давайте проверим. Зайдите в папку .git/refs/heads. Вы увидите файлы с названиями ваших веток (main, feature).

Откройте файл main в текстовом редакторе (или через cat .git/refs/heads/main). Что внутри?

e5f6g7h8... (40 символов хеша)

Всё. Ветка — это просто текстовый файл, в котором записан хеш одного коммита. Когда вы делаете git commit, Git:

  1. Создает объект коммита.
  2. Обновляет файл .git/refs/heads/main, записывая туда новый хеш.

А что такое HEAD? Это ссылка на ссылку. Откройте файл .git/HEAD:

ref: refs/heads/main

Это говорит Git'у: "Сейчас мы стоим на ветке main". Если сделать checkout на хеш (Detached HEAD), то в файле HEAD будет записан просто хеш.


5. Обслуживание: Garbage Collection

Так как Git создает новый объект на каждое изменение, папка .git/objects может разрастись. Плюс, если вы удалили ветку, коммиты, на которые она указывала, становятся "ничейными" (dangling).

Git умеет самоочищаться:

git gc

Эта команда:

  1. Удаляет осиротевшие объекты (которые недостижимы ни из одной ветки/тега).
  2. Упаковывает тысячи маленьких файлов-объектов в один большой сжатый Packfile (.pack + .idx), чтобы экономить место и ускорить работу сети.

В современных версиях Git gc запускается автоматически фоном, но полезно знать о его существовании.


Итог Уровня 5: Теперь вы видите Матрицу.

  • Нет никакой "магии". Есть хеши и ссылки.
  • Ветка — это просто стикер на коммите.
  • История — это связный список коммитов.

Уровень 6. Глава 1: Масштабирование (Big Data & Monorepos)

Git изначально создавался для исходного кода ядра Linux — тысяч маленьких текстовых файлов. Когда в репозиторий начинают класть видео, PSD-макеты или DLL-библиотеки, или когда проект разрастается до монорепозитория (как у Google или Facebook), стандартный Git начинает "захлебываться".

Эксперт должен уметь оптимизировать работу в таких экстремальных условиях.

1. Проблема бинарных файлов и Git LFS

Git хранит каждую версию каждого файла. Если вы изменили один пиксель в 100МБ файле texture.psd, Git сохранит новую копию весом 100МБ. Репозиторий пухнет мгновенно.

Решение: Git LFS (Large File Storage) Это расширение, которое заменяет большие файлы на маленькие текстовые указатели (pointer files). Сами тяжелые файлы хранятся на отдельном сервере.

Как это работает:

  1. Вы устанавливаете LFS: git lfs install.
  2. Говорите, за чем следить: git lfs track "*.psd". (Это создает запись в .gitattributes).
  3. Делаете add / commit как обычно.
  4. Git видит файл весом 1КБ (указатель), а LFS фоном грузит 100МБ на сервер.
  5. Когда коллега делает pull, он скачивает только те бинарники, которые нужны для текущей ветки (lazy loading).

2. Работа с огромными репозиториями (Monorepos)

Если репозиторий весит 10ГБ и содержит 50 микросервисов, делать полный git clone долго и бессмысленно, если вам нужно поправить только одну кнопку в админке.

Вот арсенал для работы с гигантами:

А. Shallow Clone (Поверхностный клон)

Идеально для CI/CD пайплайнов. Зачем качать историю за 10 лет, чтобы просто собрать билд?

# Скачать только последний коммит (без истории)
git clone --depth 1 <url>

Минус: Нельзя нормально мёржить ветки или смотреть git blame дальше одного коммита.

Б. Sparse Checkout (Частичное извлечение)

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

git clone --no-checkout <url> repo
cd repo
git sparse-checkout init --cone
# Говорим: "Мне нужна только папка backend/api"
git sparse-checkout set backend/api
git checkout main

Теперь у вас на диске только одна папка, хотя Git знает обо всем проекте.

В. Partial Clone / Blobless Clone (Новый стандарт)

В отличие от Shallow Clone, вы скачиваете всю историю коммитов и деревьев (это быстро), но не скачиваете содержимое файлов (блобы), пока они не понадобятся.

# Скачать историю, но не качать содержимое файлов
git clone --filter=blob:none <url>

Когда вы сделаете checkout, Git докачает содержимое только нужных файлов. git log работает быстро и полноценно.


3. Вложенные репозитории: Submodules vs Subtree

Частая задача: есть библиотека LibA, которая используется в проектах ProjectX и ProjectY. Копипастить код — плохо.

Подход 1: Git Submodules (Подмодули)

Это ссылка на конкретный коммит другого репозитория внутри текущего.

  • Создание: git submodule add <url> libs/LibA.
  • Проблема: Когда вы клонируете ProjectX, папка libs/LibA будет пустой.
  • Лечение: Нужно инициализировать подмодули:
git submodule update --init --recursive
  • Мнение: Подмодули считают "болью" из-за сложности управления версиями. Легко забыть обновить ссылку, и у команды перестанет собираться проект.

Подход 2: Git Subtree (Поддеревья)

Менее популярный, но более безопасный метод. Он просто вливает код другого проекта в папку вашего, сохраняя историю.

  • Для обычного разработчика это выглядит как просто файлы. Не нужно делать submodule init.
  • Сложнее настраивать для лида, но проще для команды.

Уровень 6. Глава 2: Безопасность и Чистка (Security)

В Enterprise-среде и Open Source доверие — это валюта. Как доказать, что код написали именно вы? И как удалить то, что не должны видеть посторонние?

1. Подпись коммитов (GPG / SSH Signing)

В Git любой может настроить user.name "Linus Torvalds" и делать коммиты. Чтобы подтвердить личность, используется криптография.

GitHub/GitLab помечают подписанные коммиты зеленым значком Verified.

Настройка (через SSH ключ — современный способ):

  1. Git 2.34+ поддерживает подпись теми же ключами, что и SSH-доступ.
  2. Конфигурация:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
# Автоматически подписывать все коммиты
git config --global commit.gpgsign true

Теперь каждый ваш коммит зашифрован вашим приватным ключом. Подделать это невозможно.

2. Хирургия истории: git filter-repo

Катастрофа: Вы случайно закоммитили файл aws_keys.json с паролями от облака. Ошибка новичка: Удалить файл новым коммитом. Почему это плохо: Файл остался в истории. Любой, кто сделает git checkout HEAD~1, увидит пароли. Боты сканируют GitHub на такие ошибки за секунды.

Нужно вырезать файл из всей истории, переписав хеши всех коммитов. Раньше использовали git filter-branch (медленно и сложно). Сейчас стандарт — утилита git-filter-repo (нужно ставить отдельно, Python-скрипт).

# Удалить файл password.txt из всех коммитов во всей истории
git filter-repo --path password.txt --invert-paths

Внимание: Это меняет все хеши. После этого нужно делать git push --force, и все коллеги должны будут переклонировать репозиторий.


Уровень 6. Глава 3: Методологии разработки (Workflows)

Git — это инструмент. Workflow — это правила игры для команды. Знание команд не поможет, если вы не договорились, как их использовать.

1. Git Flow (Классика)

Разработан Винсентом Дриссеном в 2010. Очень структурированный, но сложный.

  • Ветки: master (прод), develop (разработка), feature/*, release/*, hotfix/*.
  • Когда использовать: В проектах с редкими релизами (коробочный софт, раз в месяц/квартал).
  • Минус: Слишком бюрократичен для веб-разработки.

2. GitHub Flow (Простота)

  • Ветки: Только main (всегда стабильна) и feature-branches.
  • Цикл:
  1. Ветка от main.
  2. Коммиты.
  3. Pull Request (Code Review).
  4. Merge в main + Деплой.
  • Когда использовать: Веб-сервисы, стартапы, CI/CD.

3. Trunk Based Development (Скорость)

Выбор гигантов (Google) и современных DevOps команд.

  • Идея: Долгоживущих веток нет. Все коммитят прямо в main (или очень короткие ветки на 1-2 дня).
  • Как не сломать прод? Используются Feature Flags (код скрыт за условием if (featureEnabled)).
  • Плюс: Нет "ада слияния" (merge hell) перед релизом.

4. Conventional Commits

Соглашение о том, как писать сообщения, чтобы потом автоматически генерировать CHANGELOG и поднимать версию (SemVer).

Формат:

<тип>(<область>): <описание>

feat(auth): add google login support
fix(api): fix NPE in user controller
chore: update dependencies
docs: update readme


Итог Уровня 6: Вы вышли на уровень архитектора процессов. ✅ Вы знаете, как работать с гигабайтами данных (LFS, Sparse Checkout). ✅ Вы умеете защищать код (Signing) и чистить его (filter-repo). ✅ Вы понимаете, какую стратегию ветвления выбрать для команды.


Уровень 7. Глава 1: Продуктивность и Алиасы

Мы добрались до финала. Здесь мы превратим Git из «инструмента, с которым нужно бороться» в «продолжение ваших рук». Если вы вводите git checkout или git status полностью — вы теряете время.

1. Настройка Алиасов (Aliases)

Алиасы живут в глобальном конфиге ~/.gitconfig. Вы можете добавить их командой git config --global alias.<name> <command>, но проще и надежнее открыть файл в редакторе:

git config --global -e

Вставьте туда блок [alias]. Вот мой рекомендуемый "Набор джентльмена":

[alias]
    # -- 1. Сокращения для ленивых --
    s  = status
    st = status
    co = checkout
    sw = switch
    br = branch
    ci = commit
    df = diff
    
    # -- 2. Умные команды --
    
    # Unstage: Вернуть файл из индекса в рабочую папку (обратно add)
    unstage = restore --staged
    
    # Last: Посмотреть последний коммит кратко
    last = log -1 HEAD --stat
    
    # -- 3. Визуализация (Самый важный алиас) --
    # Рисует дерево ветвления прямо в консоли. Заменяет GUI-клиенты.
    lg = 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(bold yellow)%d%C(reset)' --all
    
    # -- 4. Спасение --
    # Показывает Reflog с датами в читаемом виде.
    # Используйте, если потеряли коммит или случайно удалили ветку.
    oops = reflog --format='%C(auto)%h %<|(20)%gd %C(blue)%cr%C(reset) %gs (%s)'

Теперь вместо git log --graph ... вы пишете просто git lg.


Уровень 7. Глава 2: Git Hooks (Автоматизация)

Хуки — это скрипты, которые Git запускает в ключевые моменты жизненного цикла. Они лежат в скрытой папке .git/hooks/. Если вы заглянете туда, вы увидите файлы с расширением .sample. Уберите .sample, сделайте файл исполняемым, и он начнет работать.

1. Ключевые хуки для разработчика

A. pre-commit (Вратарь)

Запускается до создания коммита. Если скрипт вернет ошибку (код выхода != 0), коммит не создастся.

  • Зачем: Запуск линтеров (ESLint, Checkstyle), форматирование кода (Prettier), запуск быстрых Unit-тестов.
  • Пример: "Не пускать коммит, если в коде осталось слово TODO или console.log".

B. commit-msg (Редактор)

Проверяет текст сообщения коммита.

  • Зачем: Обеспечение стандарта Conventional Commits или проверка наличия ID задачи из Jira.
  • Пример: Regex проверка, что сообщение начинается с [PROJ-123].

C. pre-push (Страж)

Запускается перед отправкой на сервер.

  • Зачем: Запуск тяжелых тестов, которые долго гонять на каждый коммит, но нельзя пропустить на сервер.

2. Проблема и Решение (Husky / pre-commit)

Хуки в папке .git/hooks не коммитятся. Они локальны. Вы не можете просто добавить их в репозиторий, чтобы они заработали у всей команды.

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

  • JS/Frontend: Библиотека Husky.
  • Python/General: Фреймворк pre-commit.

Пример (.pre-commit-config.yaml):

repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.3.0
    hooks:
    -   id: trailing-whitespace  # Удаляет лишние пробелы
    -   id: end-of-file-fixer    # Добавляет пустую строку в конец
    -   id: check-yaml           # Проверяет синтаксис YAML

Теперь любой, кто сделает git clone, получит эти проверки автоматически.


Уровень 7. Глава 3: .gitattributes (Тонкая настройка)

Файл .gitattributes позволяет задавать настройки Git для конкретных файлов или путей.

1. Нормализация окончаний строк

Чтобы раз и навсегда решить проблему "Windows vs Linux line endings", добавьте в корень проекта .gitattributes:

# Заставь Git автоматически нормализовать все текстовые файлы (в LF)
* text=auto

# Явно укажи, что эти файлы текстовые (даже если Git сомневается)
*.js text
*.java text

# Явно укажи, что это бинарники (не трогай переносы строк)
*.png binary
*.jpg binary

2. Linguist (Языковая статистика)

На GitHub есть цветная полоска "Languages". Иногда она врет (например, считает, что ваш проект на 90% состоит из JavaScript, потому что вы закоммитили папку jquery.min.js).

В .gitattributes можно исключить файлы из статистики:

# Не считай сгенерированные файлы и библиотеки в статистике языка
jquery.js linguist-vendored
dist/* linguist-generated

3. Merge Strategies

Для некоторых файлов (например, config.lock или автогенерируемых схем) конфликты слияния бессмысленны. Можно сказать Git: "В случае конфликта всегда бери мою версию".

database.xml merge=ours


🎉 Финал: Вы — Git Архитектор

Мы прошли путь от git init до настройки CI-пайплайнов и внутренней структуры блобов.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment