Первый репозиторий: init, add, commit, status

Рейтинг: 72.2% · 10 голосов
Самый подробный курс по Git - от первого коммита до объектной базы и packfiles. Терминал и первый репозиторий, ветки и слияние, конфликты, удалённая работа и форджи (GitHub, GitLab), rebase и переписывание истории, спасение кода через reflog и fsck, stash и worktree, bisect и blame, подмодули и монорепо, хуки и подпись коммитов, внутреннее устройство и масштаб. Для новичков и профи. Актуально на 2026 (Git 2.54, дорожная карта 3.0).
Ответить
Аватара пользователя
Pavel_Git
Сообщения: 52
Зарегистрирован: 11 май 2026, 05:31

Первый репозиторий: init, add, commit, status

Сообщение Pavel_Git »

Оглавление курса (52)
  1. Что такое контроль версий и почему победил Git
  2. Установка Git на Windows, macOS и Linux и первая настройка
  3. Терминал и как спрашивать у Git: выживание в командной строке
  4. Ментальная модель Git: три состояния, коммит-снимок и граф
  5. Первый репозиторий: init, add, commit, status (вы здесь)
  6. Просмотр изменений: status, diff и индексация по частям
  7. История проекта: git log, диапазоны и поиск
  8. .gitignore: что не должно попасть в репозиторий
  9. .gitattributes: окончания строк, бинарники и атрибуты
  10. Ветки как указатели: branch, switch и detached HEAD
  11. Слияние веток: fast-forward против трёхстороннего merge
  12. Конфликты слияния: анатомия и уверенное разрешение
  13. Практикум: твой первый день с Git от нуля до push
  14. Удалённые репозитории: remote, fetch, базовый pull и refspec
  15. git push: безопасная отправка и защита от перезаписи
  16. Клонирование: shallow, partial clone, bundle и backfill
  17. GitHub, GitLab и форки: pull request, rulesets и защита веток
  18. Рабочие процессы команды: GitFlow, GitHub Flow, trunk-based
  19. Merge queue и merge trains: безопасное вливание в trunk
  20. Культура code review и Conventional Commits
  21. git reset: три дерева и отмена индексации и коммитов
  22. git revert: безопасная отмена в общей истории
  23. Правка последнего коммита: git commit --amend
  24. git rebase: пересадка истории и золотое правило
  25. Интерактивный rebase: переписать серию коммитов
  26. git cherry-pick: перенос отдельных коммитов
  27. Stacked diffs: цепочка зависимых PR
  28. Массовое переписывание истории: git filter-repo и git replace
  29. git reflog: журнал, который помнит всё
  30. Восстановление утерянных коммитов, веток и файлов
  31. Откат опасных операций: reset --hard, сломанный rebase, плохой merge
  32. git stash: тайник для незавершённой работы
  33. git worktree: несколько рабочих деревьев одного репозитория
  34. git bisect: бинарный поиск регрессии
  35. git blame, mailmap и археология кода
  36. Теги, релизы, archive и bundle
  37. Подмодули: внешние репозитории внутри проекта
  38. Subtree, монорепозитории и sparse-checkout
  39. Git LFS и большие файлы
  40. Вспомогательные команды: clean, mv, rm, restore
  41. Псевдонимы и кастомизация .gitconfig
  42. Хуки Git: автоматизация на клиенте и сервере
  43. Подпись коммитов и тегов: SSH, GPG и Sigstore
  44. Внутреннее устройство I: объектная база Git
  45. Внутреннее устройство II: ссылки, HEAD, notes и reftable
  46. Внутреннее устройство III: индекс, packfiles, gc и обслуживание
  47. От SHA-1 к SHA-256: переход на новый хеш
  48. Огромные репозитории: partial clone, FSMonitor, Scalar
  49. Git в CI/CD: shallow, кеш, merge_group и безопасность
  50. Куда движется Git: дорожная карта 3.0 и экосистема
  51. Профессиональный setup: собираем рабочее окружение Git
  52. 30+ типичных ошибок Git и как из них выбираться
Боль, которую мы закрываем

Ты сохранил файл. Нажал Ctrl+S, увидел, что точка в заголовке окна пропала - значит, записалось на диск. И вот тут новичок спотыкается о первую и самую коварную стену Git: для Git твой сохранённый файл всё ещё не существует. Сохранение на диск и сохранение в историю - две разные вселенные. Ты можешь редактировать файл хоть сто раз, а Git будет упрямо твердить: ничего не закоммичено, изменения потеряются. Почему? Потому что между диском и историей стоит барьер, который называется индекс (он же staging area). Эта глава - про то, как создать репозиторий git с нуля, как продавить через него файл и почему между add и commit есть смысл. Разберём четыре команды, на которых стоит всё остальное: git init, git status, git add, git commit. И главное - выработаем привычку, которая спасёт тебя тысячу раз: смотреть в компас после каждого шага.

Изображение

git init: что появляется в .git

Создать git репозиторий - это одна команда. Заходишь в пустую папку проекта и пишешь:

Код: Выделить всё

$ mkdir hello && cd hello
$ git init
Initialized empty Git repository in /home/dev/hello/.git/
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:   git config --global init.defaultBranch <name>
Обрати внимание на хинт. На 2026 год ванильный Git всё ещё создаёт ветку с именем master и честно предупреждает, что дефолт скоро поменяют. Встроенным дефолтом main станет только в Git 3.0 (ожидается к концу 2026). Поэтому пока поставь имя сам, раз и навсегда, для всех будущих репозиториев:

Код: Выделить всё

$ git config --global init.defaultBranch main
Теперь главное: что вообще сделал init? Он создал одну скрытую папку - .git. Это и есть весь репозиторий. Удалишь её - останется обычная папка с файлами, вся история испарится. Скопируешь .git в другое место - получишь клон истории. Заглянем внутрь:

Код: Выделить всё

$ ls -F .git/
HEAD  config  description  hooks/  info/  objects/  refs/

$ cat .git/HEAD
ref: refs/heads/main
Разбор по косточкам, без зубрёжки - просто чтобы магия перестала быть магией:
  • HEAD - указатель "где я сейчас". Это текстовый файл, в нём строчка ref: refs/heads/main. То есть HEAD показывает на ветку main. Сама ветка ещё не существует как файл - её создаст только первый коммит.
  • objects/ - хранилище всех данных: содержимое файлов, деревья каталогов, коммиты. Сейчас пусто. Каждый раз, когда ты коммитишь, сюда добавляются объекты.
  • refs/heads/ - тут лежат ветки. Каждая ветка - это файлик с одним хешем коммита внутри. Пока пусто.
  • config - локальные настройки именно этого репозитория.
  • hooks/ - скрипты-перехватчики (про них позже в курсе).
Запомни картину: репозиторий - это .git. Всё остальное в папке проекта называется рабочий каталог (working directory) - это просто твои файлы, как они лежат на диске прямо сейчас.

git status - главный компас новичка

Прежде чем что-то делать, заведи рефлекс: после каждой команды смотри git status. Это не команда "на всякий случай", это твой навигатор. Он отвечает на три вопроса разом: на какой я ветке, что изменилось, и что попадёт в следующий коммит. Спроси его сразу после init:

Код: Выделить всё

$ git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

nothing added to commit but untracked files present (use "git add" to track)
Пока репозиторий пуст, поэтому "No commits yet". Создадим файл и спросим снова:

Код: Выделить всё

$ echo "print('hello')" > app.py
$ git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        app.py

nothing added to commit but untracked files present (use "git add" to track)
Вот он, момент истины. Файл app.py лежит на диске, ты его сохранил. А Git говорит: Untracked - неотслеживаемый. Я вижу, что ты что-то насоздавал, но в моей истории этого нет, и в коммит оно не попадёт, пока ты явно не попросишь. В цветном терминале строчка app.py будет красной. Красный цвет в status значит одно: "есть в рабочем каталоге, нет в индексе". Запомни этот цвет - он будет преследовать тебя, пока ты не сделаешь add.

Индекс как барьер номер один: метафора до всякого add

Здесь спотыкается каждый. Давай разберёмся по-человечески, ПОЧЕМУ Git не коммитит твои файлы сразу, а требует какой-то лишний шаг.

В Git между рабочим каталогом (твои файлы на диске) и историей (коммиты) стоит промежуточный слой - индекс, он же staging area, он же "индекс подготовленных изменений". Это не файлы и не история. Это черновик твоего следующего коммита. Физически он лежит в .git/index - один бинарный файл, список того, что войдёт в коммит, когда ты нажмёшь "отправить".

Метафора первая - корзина в интернет-магазине. Полки магазина - это весь твой рабочий каталог, все файлы. Корзина - это индекс. Касса - это коммит. Ты ходишь по магазину и кидаешь в корзину ровно то, что хочешь купить именно сейчас. Положил молоко и хлеб в корзину (git add) - но колбасу оставил на полке, передумал. На кассе (git commit) ты платишь только за содержимое корзины. Молоко с хлебом уходят в чек (в историю), колбаса остаётся лежать на полке нетронутой. Без корзины касса не знает, что ты вообще хочешь купить - именно поэтому add нужен, даже если файл давно сохранён на диск.

Метафора вторая, для тех, кто пишет письма. Рабочий каталог - это черновик, который ты правишь. Индекс - это то, что ты уже вставил в окно нового письма, готовое к отправке. Коммит - кнопка "Отправить". Ты можешь дописывать черновик сколько угодно, но получатель увидит только то, что было в письме в момент нажатия "Отправить". Скопировал в письмо два абзаца из черновика (add), отправил (commit) - ушли только они.

Зачем вообще этот лишний слой, почему нельзя коммитить всё сразу? Потому что он даёт тебе контроль над тем, ЧТО войдёт в коммит. Ты поправил три разных вещи в проекте, но хочешь сделать два аккуратных коммита по смыслу. Индекс позволяет собрать в один коммит только связанные изменения, а остальное оставить на потом. Это основа чистой истории, и позже, в уроке про git add -p, мы научимся складывать в корзину даже не файлы целиком, а отдельные куски одного файла. Но фундамент - вот этот: диск, корзина, чек. Три состояния, три разных места.

git add: из рабочего каталога в индекс

Кладём файл в корзину:

Код: Выделить всё

$ git add app.py
$ git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   app.py
Смотри, что поменялось в компасе. Раздел стал называться Changes to be committed - "изменения, которые попадут в коммит". Строчка app.py теперь зелёная и с пометкой new file. Зелёный цвет в status значит "лежит в индексе, готово к коммиту". Файл переехал из untracked в staged. На диске он не изменился ни на байт - изменился только индекс, наша корзина.

Состояния по шагам, чтобы картинка в голове была чёткой:
  • Шаг 0 (создали файл): диск - есть, индекс - пусто. Status: Untracked, красный.
  • Шаг 1 (git add): диск - есть, индекс - есть. Status: Changes to be committed, зелёный, new file.
Маленький, но важный нюанс про staging как снимок. Допустим, после add ты ещё раз поправил app.py. Git тут же это заметит и покажет файл сразу в ДВУХ разделах:

Код: Выделить всё

$ echo "# v2" >> app.py
$ git status
Changes to be committed:
        new file:   app.py
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
        modified:   app.py
Это не баг и не глюк. Это прямое доказательство, что индекс - отдельный слой. В корзине лежит версия файла на момент первого add. На полке (на диске) уже лежит более новая версия. Закоммитишь сейчас - в историю уйдёт та, что в корзине, без строчки # v2. Чтобы догнать корзину до диска, надо снова git add app.py. Этот двойной показ - твой друг: он честно говорит, что версия в коммите и версия на диске разошлись.

git commit: из индекса в историю

Догнали корзину и пробиваем чек:

Код: Выделить всё

$ git add app.py
$ git commit -m "Добавил точку входа app.py"
[main (root-commit) a1b2c3d] Добавил точку входа app.py
 1 file changed, 2 insertions(+)
 create mode 100644 app.py
Разбор вывода:
  • main (root-commit) - коммит лёг в ветку main. root-commit значит, что это самый первый коммит, у него нет родителя. Заодно этим коммитом наконец-то создался файл .git/refs/heads/main.
  • a1b2c3d - короткий хеш коммита (у тебя будет другой). Полный хеш - сорок символов, это адрес коммита в истории.
  • 1 file changed, 2 insertions(+) - статистика. Один файл, две добавленные строки.
Проверяем компас сразу после коммита (рефлекс, помнишь?):

Код: Выделить всё

$ git status
On branch main
nothing to commit, working tree clean
"Working tree clean" - чистое дерево. Самая приятная фраза в Git: рабочий каталог, индекс и последний коммит совпадают. Корзина пуста, всё оплачено, полки соответствуют чеку. Полный жизненный цикл файла пройден: untracked -> staged -> committed.

Флаг -m задаёт сообщение прямо в строке. Если написать git commit без -m, Git откроет редактор (по дефолту тот, что в core.editor, часто vi или nano), чтобы ты набрал сообщение там. Удобно для длинных сообщений с телом. Если в редакторе сохранить пустое сообщение и выйти, Git отменит коммит - "Aborting commit due to empty commit message". Сменить редактор на привычный можно один раз:

Код: Выделить всё

$ git config --global core.editor "nano"
Хорошее первое сообщение - не "fix", не "asdf", не "изменения". Пиши в повелительном наклонении, как приказ что сделает коммит: "Добавь логин по токену", "Почини падение при пустом вводе". Первая строка - до ~50 символов, суть. Если нужны детали - пустая строка и абзац-пояснение ниже. Это не занудство: через полгода в git log ты сам себе скажешь спасибо, что писал по-человечески.

git clone: когда репозиторий уже есть

Не всегда ты создаёшь репозиторий с нуля. Часто он уже живёт на GitHub или GitLab, и тебе надо забрать его к себе. Для этого git clone:

Код: Выделить всё

$ git clone https://github.com/owner/project.git
Cloning into 'project'...
remote: Enumerating objects: 128, done.
remote: Counting objects: 100% (128/128), done.
Receiving objects: 100% (128/128), 42.10 KiB, done.
Resolving deltas: 100% (50/50), done.
Что произошло за один шаг: Git создал папку project, внутри неё сделал init (та самая .git), скачал всю историю в objects, прописал ссылку на исходный сервер под именем origin и выложил рабочие файлы последней версии. Тебе не надо ни init, ни add - после клона у тебя сразу чистое дерево и полная история. Про origin, ветки и связь с сервером - отдельные уроки впереди; сейчас держи в голове, что clone это init + закачка истории + выкладка файлов, всё разом.

Типичные грабли новичка
  • Забыл add. Поправил файл, сразу git commit -m "...", а в ответ "nothing to commit, working tree clean" или "no changes added to commit". Git закоммитил пустоту или вообще ничего: изменения остались на диске, в корзину ты их не положил. Лечится взглядом в git status ДО коммита. Видишь красное и "Changes not staged" - значит, надо add.
  • Identity не настроен. Первый в жизни коммит часто падает так:

Код: Выделить всё

$ git commit -m "first"
Author identity unknown

*** Please tell me who you are.

Run
  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"
Git не знает, кем подписать коммит. Имя и почта вшиваются в каждый коммит навсегда. Настрой один раз глобально - и забудь:

Код: Выделить всё

$ git config --global user.name "Ivan Petrov"
$ git config --global user.email "ivan@example.com"
  • Пустой коммит по ошибке. git commit без изменений в индексе ничего не создаст и поругается. Если коммит без изменений нужен осознанно (например, дёрнуть CI) - есть флаг --allow-empty, но это редкий специальный случай, не дефолт.
  • Закоммитил мусор. git add . хватает всё подряд, включая лог-файлы, секреты, папки сборки. Привычка смотреть git status перед add спасает от того, чтобы случайно положить в корзину то, чему там не место. Фильтр через .gitignore - тема ближайшего урока.
Мини-лаба: повтори руками

Пройди весь цикл сам, и обязательно вызывай git status после КАЖДОГО шага - смотри, как меняется компас.

Код: Выделить всё

# 1. Настрой identity и дефолтную ветку (один раз на машину)
git config --global user.name "Твоё Имя"
git config --global user.email "ty@example.com"
git config --global init.defaultBranch main

# 2. Создай репозиторий
mkdir lab-git && cd lab-git
git init
git status                      # On branch main, No commits yet

# 3. Создай файл и посмотри состояние untracked
echo "hello git" > readme.txt
git status                      # readme.txt красный, Untracked

# 4. Положи в индекс (корзину) и сравни вывод
git add readme.txt
git status                      # readme.txt зелёный, Changes to be committed, new file

# 5. Закоммить и проверь чистое дерево
git commit -m "Добавь readme проекта"
git status                      # nothing to commit, working tree clean

# 6. Поправь файл, посмотри modified, повтори add+commit
echo "вторая строка" >> readme.txt
git status                      # modified, Changes not staged (красный)
git add readme.txt
git commit -m "Дополни readme второй строкой"

# 7. Загляни внутрь репозитория
cat .git/HEAD                   # ref: refs/heads/main
ls .git/refs/heads/            # main
Если на шаге 6 ты сделаешь только echo, а потом сразу commit без add - получишь "no changes added to commit". Это и есть та самая грабля номер один. Прочувствуй её специально - тогда в реальном проекте узнаешь с первого взгляда.

Контрольные вопросы
  • Файл сохранён на диск, но git status показывает его красным в разделе Untracked. Почему Git не возьмёт его в коммит автоматически и какая команда это исправит?
  • Ты сделал git add app.py, потом ещё раз отредактировал app.py. Status показывает файл в двух разделах сразу. Что попадёт в коммит, если сделать commit прямо сейчас, и почему?
  • Что конкретно лежит в .git/HEAD сразу после git init и почему файла .git/refs/heads/main ещё нет до первого коммита?
  • Чем git clone отличается от git init и какие шаги он делает за тебя одной командой?
Итог

Четыре команды - и ты уже умеешь главное. git init создаёт .git, и весь репозиторий живёт там. git status - твой компас, смотри в него после каждого шага, это не паранойя, а профессиональная привычка. Между диском и историей стоит индекс - корзина покупок, черновик письма, отдельный слой, который ты наполняешь через git add и пробиваешь через git commit. Жизненный цикл любого файла: untracked -> staged -> committed, и красный/зелёный цвет в status всегда честно говорит, на какой ты стадии. А git clone забирает готовый репозиторий целиком. Дальше будет глубже, но фундамент - вот этот, и он никуда не денется до самого конца курса.
👍4 ❤️2 🔥 😄 🤔1
Аватара пользователя
niccole
Сообщения: 1
Зарегистрирован: 13 май 2026, 23:58

Re: Первый репозиторий: init, add, commit, status

Сообщение niccole »

Вот про корзину наконец дошло. Я месяц не понимал зачем add, если файл уже сохранён. Спасибо, метафора в голове щёлкнула.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
wasm1337
Сообщения: 1
Зарегистрирован: 18 май 2026, 02:24

Re: Первый репозиторий: init, add, commit, status

Сообщение wasm1337 »

А двойной показ файла в status это реально жиза. Поймал ровно эту ловушку вчера: добавил, потом дописал, закоммитил - и половины правок нет. Теперь понятно почему.
👍1 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Ментальная модель Git: три состояния, коммит-снимок и граф
Следующая глава →
Просмотр изменений: status, diff и индексация по частям

Все главы курса «Git профессионально: от первого коммита до внутреннего устройства»

Поделиться темой: ✈ Telegram VK
Похожие запросы: Git команды для начинающихgit commit: фиксация измененийgit clone: клонирование репозитория

Вернуться в «Git профессионально: от первого коммита до внутреннего устройства»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя