git git_clone commit git_status git_add git_commit git_push git_config
Шпаргалка
Вся практика этого шага умещается в одиннадцать команд:
| Команда | Что делает |
|---|---|
git init | превратить папку в репозиторий |
git status | показать, что сейчас происходит |
git add файл | отобрать изменения для коммита |
git commit -m "..." | сохранить снимок с сообщением |
git log --oneline | история коммитов в одну строку |
git diff | что изменилось с последнего коммита |
git branch | список веток |
git switch имя | переключиться на ветку |
git switch -c имя | создать ветку и переключиться |
git merge имя | влить ветку в текущую |
git branch -d имя | удалить влитую ветку |
git clone | склонировать репозиторий откуда-то |
| git rm —cached | Убрать файл из отслеживания, не удаляя его с диска |
| git clone | Скопировать удаленный репозиторий к себе целиком |
| git push | Отправить свои коммиты на удаленный репозиторий |
| git pull | Забрать с удаленного репозитория чужие коммиты |
Создание git
- Открыть страницу вашего репозитория
- Скопируйте ссылку для клонирования репозитория
- Открыть консоль GIT (файл git-bash.exe) и выполните команду клонирования репозитория:
# Вместо моей ссылки укажите свою
git clone http://10.0.1.22:3000/Chopov_I_A/Linux_Chopov.git
- В первый раз обычно нужно
git config --global user.name "John Doe"
git config --global user.email johndoe@example.comРепозиторий за одну команду
mkdir myserver
cd myserver
git init
git status
On branch main
No commits yet
nothing to commitКогда непонятно, что происходит с репозиторием, первым делом смотрят git status. Это безопасная команда уровня ls, ее можно дергать сколько угодно.
Первый коммит
Создадим файл конфига:
echo "listen 80;" > nginx.conf
git status
Untracked files:
nginx.confGit заметил новый файл, но пометил его как untracked: файл лежит в папке, но за его историей Git пока не следит. Чтобы файл попал в историю, нужен коммит, а делается он в два шага:
git add nginx.conf
git commit -m "Базовый конфиг nginx"История уже существует, посмотрим на нее:
git log —oneline
a3f8c21 (HEAD -> main) Базовый конфиг nginx
Набор букв и цифр слева – идентификатор коммита, по нему к этому снимку можно будет вернуться когда угодно.
Цикл изменений
Теперь главный ритм работы с Git. Поменяем конфиг:
echo "listen 8080;" > nginx.conf
git status # подскажет: modified, nginx.conf изменен
git diff # покажет, что именно изменилось
- listen 80;
+ listen 8080;Это тот самый дифф, что мы видели раньше, только теперь он ваш: строка с минусом ушла, строка с плюсом пришла. Привычка смотреть git diff перед коммитом спасает от случайных изменений, которые вы не собирались сохранять.
Дальше знакомые два шага:
git add nginx.conf
git commit -m "Перенес сайт на порт 8080"
git log --oneline
9b2e110 (HEAD -> main) Перенес сайт на порт 8080
a3f8c21 Базовый конфиг nginxВетка без риска для рабочей версии
Сейчас оба коммита живут в ветке main. Допустим, мы хотим попробовать перевести сайт на защищенное соединение, но не уверены, что получится, и трогать рабочий конфиг не хотим. Это ровно та ситуация, под которую придуманы ветки.
Важная деталь: ветка – это не копия директории и не отдельная версия проекта на диске, а легкая метка, указатель на коммит, поэтому ветки создаются мгновенно и ничего не весят. Создадим ветку и сразу в нее переключимся:
git switch -c ssl-experiment
Команда git switch переключает ветки, а флаг -c заодно создает новую. Проверить, где вы находитесь, можно через git branch: текущая ветка помечена звездочкой. Теперь экспериментируем:
echo "listen 443 ssl;" > nginx.conf
git add nginx.conf
git commit -m "Включил SSL"Этот коммит ушел в ветку ssl-experiment, а main остался стоять на месте:

И самое наглядное в ветках. Вернитесь в main и загляните в файл:
git switch main
cat nginx.conf
listen 8080;Эксперимента в файле нет. Git физически подменяет содержимое рабочей папки под ту ветку, в которой вы находитесь: в main лежит версия main, а если переключиться обратно в ssl-experiment, SSL вернется. Одна папка, несколько параллельных состояний проекта.
Мерж вливает результат
Допустим, эксперимент удался, и SSL-конфиг должен стать основным. Слияние всегда делается стоя в той ветке, в которую вливают изменения, поэтому сначала переключаемся в main:
git switch main
git merge ssl-experimentДальше возможны два сценария. Если main с момента создания ветки не менялся (наш случай), слияние проходит незаметно: Git просто передвигает main вперед, на последний коммит ветки, и никаких новых коммитов не появляется. Если же за время эксперимента в main успели появиться свои коммиты, например от коллеги, Git создаст отдельный коммит слияния, который соединит обе линии истории в одну.
Влитая ветка больше не нужна, удалим ее:
git branch -d ssl-experiment
Конфликты, когда Git просит помощи
Один случай Git не может разрешить сам: обе ветки изменили одну и ту же строку файла по-разному. Скажем, в main кто-то поставил listen 8080;, а в вашей ветке та же строка стала listen 443 ssl;. Какой вариант правильный, знаете только вы, поэтому Git останавливает слияние и вставляет прямо в файл маркеры с обоими вариантами:
<<<<<<< HEAD
listen 8080;
=======
listen 443 ssl;
>>>>>>> ssl-experimentСверху версия текущей ветки, снизу версия вливаемой. Разрешается конфликт руками: открываете файл, оставляете правильный текст, убираете маркеры, затем git add и git commit, и слияние завершено. Если что-то пошло не так, git merge --abort отменит слияние целиком и вернет все как было.
Выглядит конфликт страшнее, чем есть на деле: Git ничего не сломал и ничего не потерял, он показал два варианта и ждет вашего решения.
.gitignore: что нельзя коммитить
Вернемся к git status . В ранее примере репозиторий был стерильным: одна папка, один файл nginx.conf. В настоящем проекте та же команда сразу после git init покажет совсем другую картину:
Untracked files:
app.py
.env
node_modules/
app.log
.DS_StoreGit честно предлагает взять под контроль все, что нашел в папке. Но в историю проекта должно попасть далеко не все из этого списка. app.py – да, это код. А вот .env с паролями, гигабайтная папка node_modules и лог приложения в истории не нужны, а кое-что из этого там еще и опасно. Разберемся, что отсекать и как сказать об этом Git.
Что не должно попадать в Git
Лишнее в репозитории делится на несколько понятных групп.
-
Первое и самое важное – это секреты. Пароли от баз данных, токены доступа, приватные ключи, файлы вроде
.envс настройками подключения. -
Вторая группа – то, что генерируется из кода и восстанавливается командой. Папка зависимостей
node_modules, каталоги сборкиbuildиdist, кэши вроде__pycache__. Эти файлы не пишут руками, их создает инструмент по описанию проекта. Хранить их в Git бессмысленно: они весят много, постоянно меняются и в любой момент собираются заново. -
Третья группа – мусор и временные файлы. Логи (
app.log,*.log), временные файлы, дампы. Они меняются каждую секунду работы программы, и их история не несет никакого смысла. -
И последнее – личные и системные файлы, к проекту отношения не имеющие.
.DS_Storeсоздает Finder на macOS,Thumbs.db– проводник Windows, а папки.ideaи.vscodeхранят настройки редактора конкретного разработчика. Коллеге они не нужны, а в истории только шумят.
Файл .gitignore
Чтобы Git перестал замечать ненужное, в репозиторий кладут файл с именем .gitignore. Это обычный текстовый файл со списком того, что Git должен игнорировать: такие файлы не показываются в git status, не попадают под git add и, значит, не уходят в коммиты.

Обратите внимание на последнюю строку: сам .gitignore в историю как раз попадает. Он часть проекта, и правила должны быть одинаковыми у всей команды, поэтому его коммитят наравне с кодом.
Как пишут правила
Внутри .gitignore идет по одному правилу на строку. Базового набора хватает почти всегда:
# строки с решеткой — комментарии
.env # конкретный файл по имени
*.log # любой файл с расширением .log
node_modules/ # целая директория (косая черта в конце)
secrets/ # и эта тожеИмя файла означает именно этот файл. Звездочка * заменяет любую часть имени, поэтому *.log накрывает все логи разом. Косая черта в конце говорит, что речь о директории со всем содержимым. Этих приемов достаточно, чтобы описать почти любой проект, а готовые шаблоны .gitignore под конкретный язык легко найти и взять за основу.
Ловушка, которую .gitignore не закрывает
.gitignore действует только на файлы, которые Git еще не отслеживает. Если файл уже попал хотя бы в один коммит, добавление его в .gitignore не сделает ничего: Git продолжит следить за ним как ни в чем не бывало.
Чтобы перестать отслеживать уже закоммиченный файл, его убирают из-под контроля отдельно:
git rm —cached .env # убрать из отслеживания, сам файл на диске оставить
После этого его еще нужно занести в .gitignore, иначе Git снова предложит его добавить. Но есть нюанс важнее: из прошлых коммитов файл при этом никуда не девается.
Секреты в истории остаются навсегда
Git тем и ценен, что ничего не забывает, и в случае с секретами это оборачивается против вас. Если пароль или ключ хоть раз попал в коммит, он остается в истории навсегда. Удалить файл новым коммитом недостаточно: старый коммит с секретом по-прежнему лежит в репозитории, и из него все можно достать.
Для публичных репозиториев это не теория. Открытые репозитории постоянно сканируют боты, и выложенный по ошибке ключ, например от облака AWS, находят и пускают в дело буквально за минуты, а со счетом за чужие траты потом разбирается владелец. GitHub даже встроил защиту, которая умеет распознавать секреты и блокировать такой коммит на отправке, но полагаться стоит не на нее, а на привычку не коммитить лишнее.
Поэтому если секрет все-таки утек в репозиторий, чистки истории мало. Единственное надежное решение – отозвать сам секрет: сменить пароль, перевыпустить ключ, сделать утекшее значение недействительным. Тогда даже найденная в истории копия уже ничего не открывает.
Как держать секреты вне репозитория
Сложилась простая практика. Настоящие секреты держат в файле .env, который занесен в .gitignore и у каждого разработчика свой. А рядом коммитят его шаблон, обычно .env.example, тот же список настроек, но с пустыми значениями:
# .env — в .gitignore, с настоящими значениями, в Git не идет
DB_PASSWORD=s3cr3t-real-password
# .env.example — коммитится, это шаблон без секретов
DB_PASSWORD=Так новый человек в проекте видит, какие настройки нужны, но не получает чужих паролей, а сами секреты в историю не попадают. В реальной доставке секреты вообще не лежат в файлах рядом с кодом, а подставляются отдельно, переменными окружения и хранилищами секретов.