Git. Управление версиями проекта
14.06.2026
Теги: CLI • Git • GitHub • Команда • СистемаКонтроляВерсий
Git — система контроля версий, которая помогает следить за изменениями в файлах проекта. Она работает как «фотограф» исходного кода: каждый раз при выполнении коммита (commit), Git сохраняет моментальный снимок всех файлов. Эти снимки хранятся в репозитории (локальном хранилище), и можно вернуться к любой сохраненной версии.
Установка
- Windows — скачать и запустить установщик с git-scm.com
- Ubuntu/Debian — выполнить команду
sudo apt install git
Настройка
После установки выполняем команды в терминале
$ git config --global user.name "Your Name" $ git config --global user.email "somebody@example.com"
Это свяжет коммиты с именем и адресом почты автора.
Основные действия
Начало работы
git init— создать новый репозиторий в текущей директорииgit clone ссылка_на_репозиторий— клонировать существующий репозиторий с GitHub или GitLab
Ежедневные операции
git add файлилиgit add .— добавить изменения вstage areagit commit -m "Сообщение"— создать коммит с описанием измененийgit status— показать текущий статус файлов (изменённые, добавленные)git log— просмотр история коммитов
Работа с ветками (branch)
git branch— список ветокgit switch имя_ветки— переключиться на ветку (новый способ)git checkout имя_ветки— переключиться на ветку (старый способ)git switch -c имя_новой_ветки— создать новую ветку и переключиться на нееgit checkout -b имя_новой_ветки— создать новую ветку и переключиться на нееgit merge ветка— влить в текущую ветку изменения из другой ветки
Синхронизация с удалённым репозиторием
git push— отправка изменений на GitHub/GitLabgit pull— получение изменений из GitHub/GitLab
Полезные советы по работе с Git
- Файл
.gitignoreпозволяет исключить ненужные файлы - Коммиты лучше делать небольшими, с понятным комментарием
- Чаще использовать
git statusчтобы не потерять изменения
Как это работает
Git отслеживает изменения в файлах проекта через три основных области
- Git-директория — это директория
.git - Рабочая директория — директория проекта
- Stage Area — область подготовленных файлов
1. Git-директория или Repository
Это основное хранилище Git, расположенное в директории .git в корне проекта. Здесь хранится вся история проекта, включая коммиты, ветки, теги и метаданные. Git-директория — это «база данных» Git, которая сохраняет состояние проекта в разные моменты времени. Она не изменяется напрямую пользователем, а управляется командами Git (например, commit, merge).
2. Рабочая директория (Working Directory)
Это директория проекта, где идет работа, то есть создание и редактирование файлов. Она содержит все файлы и директории, включая те, которые не отслеживаются Git. Рабочая директория — это «живая» область, где идет работа над проектом. При изменении файлов здесь — Git сравнивает их с последним сохранённым состоянием в Git-директории.
3. Stage Area или Index
Это промежуточная область между рабочей директорией и Git-директорией. Здесь временно хранятся изменения, которые нужно включить в следующий коммит. Область подготовки позволяет точно контролировать, что попадет в историю Git, например, выбрать только часть изменённых файлов для коммита.
Связь между областями
- Рабочая директория → Stage Area
Разработчик изменяет файлы в рабочей директории, затем добавляет их вstage areaкомандойgit add. Это «подготовка» изменений к коммиту. - Stage Area → Git-директория
Командаgit commitпереносит изменения изstage areaв Git-директорию, создавая новый коммит в истории проекта. - Git-директория → Рабочая директория
Команды
git switchилиgit restoreмогут обновлять рабочую директорию до состояния из Git-директории (например, переключение веток).
Как файлы попадают под контроль Git?
- Команда
git initсоздаёт Git-директорию (.git) в проекте - Файлы в рабочей директории сначала не отслеживаются Git
- Команда
git add file.txtдобавляет файл вstage area— начинается отслеживание - После
git commitфайл сохраняется в Git-директории как часть истории проекта
Работа с ветками Git
Ветка — это независимая линия разработки в Git. Она позволяет работать над разными задачами параллельно без конфликтов. Основная ветка обычно называется main или master.
1. Создание и переключение веток
Устаревший синтаксис — с использованием checkout
# Создать новую ветку git branch branch_name # Переключиться на ветку git checkout branch_name # Создать и сразу переключиться на новую ветку git checkout -b branch_name
Современный синтаксис — с использованием switch
# Создать новую ветку git branch branch_name # Переключиться на ветку git switch branch_name # Создать и сразу переключиться на новую ветку git switch -c branch_name
2. Просмотр веток
# Показать список всех веток (локальных) git branch # Показать все ветки (включая удалённые) git branch -a # Показать последние коммиты на каждой ветке git branch -v
3. Слияние веток (merge)
Устаревший синтаксис — с использованием checkout
# Переключиться на ветку, которую хотим обновить git checkout master # Влить ветку feature в текущую ветку master git merge feature
Современный синтаксис — с использованием switch
# Переключиться на ветку, которую хотим обновить git switch master # Влить ветку feature в текущую ветку master git merge feature
4. Удаление веток
# Удалить локальную ветку (после её вливания в master) git branch -d branch_name # Удалить ветку принудительно (ветка не влита в master) git branch -D branch_name
5. Типовые примеры работы
Разработка нового функционала
# Начинаем с основной ветки master git switch master # Создаём ветку для разработки нового функционала git switch -c feature/login-system # Работаем над новым функционалом, делаем коммиты git add . git commit -m "Добавил базовую структуру логина" # После завершения работы возвращаемся в ветку master git switch master # Вливаем в master изменения из feature/login-system git merge feature/login-system # Удаляем ветку нового функционала, больше не нужна git branch -d feature/login-system
Исправление ошибки (hot-fix)
# Создаём ветку для исправления из master git switch master git switch -c hotfix/security-patch # Исправляем ошибку, выполняем коммиты git add . git commit -m "Исправлена уязвимость в обработке паролей" # Вливаем исправление в основную ветку git switch master git merge hotfix/security-patch
7. Конфликты при слиянии
Если при операции merge возникают конфликты (Git не может автоматически определить, какие изменения принимать), нужно
- Отредактировать файлы с конфликтами
- Выполнить
git addдля исправленных файлов - Завершить слияние командой
git commit
Файл .gitignore
Это текстовый файл, в котором перечислены файлы и папки, которые Git не будет отслеживать. Такие файлы не попадут в индекс и не появятся в истории проекта.
project/ ├── .gitignore ← главный, применяется ко всему проекту ├── src/ │ ├── .gitignore ← применяется только к этой директории │ └── app.js └── logs/
Синтаксис файла .gitignore
# Все файлы .env в любом месте .env # Все файлы с расширением .log *.log # Директория целиком node_modules/ # Файл только в корне проекта /config.json # Все файлы внутри директории, но не саму директорию logs/* # Исключение из правила — не игнорировать этот файл !important.log # Все .txt файлы в любой директории **/*.txt
Типичное содержимое для NodeJS проекта
node_modules/ dist/ .env *.log .DS_Store Thumbs.db
Типичное содержимое для Python проекта
__pycache__/ *.pyc .venv/ .env *.egg-info/ .DS_Store Thumbs.db
Файл .gitignore действует только на неотслеживаемые файлы. Если файл уже попал в индекс или в историю — .gitignore на него не действует.
# Файл уже отслеживается Git git status # modified: .env ← .gitignore не поможет # Нужно сначала убрать из индекса git rm --cached .env # И только потом добавить в .gitignore echo ".env" >> .gitignore git add .gitignore git commit -m "Remove .env from tracking"
Проверить — игнорируется ли файл
git check-ignore .env # Если файл игнорируется — вернёт его имя # Если не игнорируется — не вернёт ничего
Подробно — в каком файле .gititignore какое правило в какой строке сработало
# Содержимое .gitignore, две строки # *.log ← первая строка # !important.log ← вторая строка git check-ignore -v important.log # .gitignore:2:!important.log important.log # ↑ ↑ ↑ ↑ # файл строка правило совпавший файл
Можно создать .gitignore для всех репозиториев на компьютере — удобно для системных файлов.
# Указываем Git где искать глобальный gitignore git config --global core.excludesFile ~/.gitignore_global # Добавляем правила echo ".DS_Store" >> ~/.gitignore_global echo "Thumbs.db" >> ~/.gitignore_global
Шпаргалка по синтаксису
| Шаблон | Что игнорирует |
|---|---|
file.txt |
конкретный файл |
*.log |
все файлы с расширением |
folder/ |
директорию целиком |
/file.txt |
файл только в корне |
**/file.txt |
файл в любой поддиректории |
!file.txt |
исключение из правила |
Навигация по истории
Представь, что история коммитов — это список, где HEAD — это твоя текущая позиция. Если ты переключился на ветку master — тогда HEAD указывает на самый последний коммит в этой ветке.
Символ ~ (тильда) позволяет сказать Git — «отступи назад по истории на N шагов».
HEAD— текущий коммитHEAD~1— «родитель» текущего коммита (предыдущий)HEAD~2— «дедушка» (предыдущий-предыдущий)HEAD~5— отступить на 5 коммитов назад
Представь цепочку коммитов, где A — самый старый, а D — самый свежий
[A] <-- [B] <-- [C] <-- [D] (HEAD)
Если ты находишься в D, тогда
HEAD— это коммитDHEAD~1— это коммитCHEAD~2— это коммитBHEAD~3— это коммитA
Это удобно тем, что не нужно копировать длинный хеш коммита (например, a1b2c3d4...). Если ты знаешь, что ошибку допустил «пару коммитов назад», ты просто пишешь HEAD~2 и не тратишь время на поиск идентификаторов.
Иногда ты увидишь символ ^ — он означает «родитель». Разница между ~ и ^ становится заметна, только если у тебя есть merge-коммиты (узлы, где соединяются две ветки) — у них два родителя
HEAD^1— родитель из основной веткиHEAD^2— родитель из ветки, которую ты «вливал»
Основные команды
Команда git commit
При выполнении команды git commit, файлы из stage area попадают в историю в том состоянии, в котором они были на момент последнего выполнения git add.
-
Момент
git add. При выполнении командыgit add, «снимок» текущего состояния файла фиксируется и помещается вstage area. Это состояние не меняется автоматически, даже если файл редактировался в рабочей директории после выполненияgit add. -
Между
git addиgit commit. При редактировании файла после выполненияgit add— в рабочей директории будет новое состояние, ноstage areaсохранит старое состояние (до изменений). Чтобы включить новые изменения в коммит, нужно повторно выполнитьgit add. -
Момент
git commit. Коммит создается из содержимогоstage area, которое осталось неизменным с момента последнего выполненияgit add. В итоге, коммит может содержать состояние файлов, которое уже не соответствует состоянию в рабочей директории.
Пример git add и git commit
# 1. Начальное состояние файла: "Hello" echo "Hello" > file.txt git add file.txt # 2. Изменяем файл после add: "World" echo "World" >> file.txt # Рабочая директория: "HelloWorld" # Staging area: "Hello" # 3. Коммит без повторного git add git commit -m "Commit" # Коммит сохранит только "Hello"
Важные команды для проверки
git diff— сравнить рабочую директорию иstage areagit diff --staged— сравнитьstage areaс последним коммитом
Как отредактировать комментарий последнего коммита?
Если ты просто хочешь исправить опечатку или сделать сообщение более понятным, используй команду amend (с англ. «исправить»).
$ git commit --amend -m "Новое правильное сообщение"
Git возьмет последний коммит, изменит его сообщение на новое и сохранит под тем же (или новым) идентификатором. Это самый простой способ сделать историю «чистой».
Как «удалить» последний коммит и выполнить его снова?
Если ты понял, что забыл добавить файлы, которые должны были быть в этом коммите, или сделал что-то не так — используй reset.
$ git reset --soft HEAD~1
Опция --soft — означает «мягкий сброс». Git удаляет коммит из истории, но оставляет все твои файлы в индексе (stage area). Аргумент HEAD~1 предписывает «откатиться на один шаг назад».
После этой команды
- Твои файлы остались в «зеленом» состоянии (в индексе)
- Ты можешь добавить нужные файлы с помощью
git add - Снова выполнить коммит —
git commit -m "Исправленный коммит"
Команда git status
Самая важная команда, которую стоит вводить перед любым действием (перед коммитом, перед пушем, перед переключением веток). Она показывает текущее состояние рабочей директории и индекса (stage area).
Обычно вывод команды содержит
On branch master— показывает, в какой ветке ты сейчас находишься. Это первое, на что надо смотреть, чтобы не закоммитить код вmasterпо ошибке.Changes to be committed(зеленый цвет) — это файлы в индексе (stage area). Они готовы к коммиту. Если ты введешьgit commit, в него попадут именно эти изменения.Changes not staged for commit(красный цвет) — это файлы, которые ты изменил, но не добавил в индекс (не сделалgit add). Они не попадут в коммит, если сделаеть его прямо сейчас.Untracked files(красный цвет) — файлы, которые Git вообще видит впервые. Они не добавлены в индекс и «не под наблюдением».
$ git init hint: Using 'master' as the name for the initial branch. This default branch name ..... Initialized empty Git repository in /home/username/project/.git/
$ echo "Inintial content" > master.txt $ git status On branch master No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) master.txt nothing added to commit but untracked files present (use "git add" to track)
$ git add master.txt $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: master.txt
$ git commit -m "Initial commit" [master (root-commit) 0d9b137] Initial commit 1 file changed, 1 insertion(+) create mode 100644 master.txt $ git status On branch master nothing to commit, working tree clean
Когда проект становится большим, стандартный вывод git status может быть слишком длинным. Разработчики часто используют сокращенную версию — git status -s (или --short). Она выдает очень компактный отчет.
M— файл изменен (Modified)A— файл добавлен в индекс (Added)??— файл новый (untracked)
$ echo "Add content" >> master.txt $ echo "New file and content" > new-file-one.txt $ git add new-file-one.txt $ echo "New file and content" > new-file-two.txt $ git status -s M master.txt A new-file-one.txt ?? new-file-two.txt
Команда git diff
Команда git diff показывает разницу между состояниями файлов — что было добавлено или удалено.
-(красный цвет) — строки, которые были удалены+(зеленый цвет) — cтроки, которые были добавлены@@— в каком месте файла произошли изменения
[последний коммит] ─────────── [stage area] ────── [рабочая директория]
│ │ │ │ │ │ │
│ └── git diff --staged ──┘ │ └── git diff ──┘ │
│ │ │
└───────────────────────── git diff HEAD ─────────────────┘
1. Сравнить рабочую директорию и stage area
$ git diff
Показывает изменения в файлах, которые ещё не добавлены к коммиту через git add.
2. Сравнить stage area с последним коммитом
$ git diff --staged
Показывает изменения в файлах, которые уже добавлены к коммиту через git add.
--staged является синонимом для устаревшей опции --cached.
3. Посмотреть накопленные изменения
$ git diff HEAD
Можно сказать, что эта команда — что-то вроде суммы двух предыдущих. Удобно, если нужно посмотреть всё, что накопилось с последнего коммита, не думая о том, что где лежит.
4. Сравнить два коммита
Сравнение текущего состояния с тем, что было два коммита назад
$ git diff HEAD~2 HEAD
Команда показывает разнице между коммитом C и E
A → B → C → D → E (HEAD)
↑ ↑
HEAD~2 HEAD~1
Сравнение текущего состояния файла src/index.js — с тем состоянием, что было два коммита назад
$ git diff HEAD~2 HEAD -- src/index.js
Здесь -- — это универсальный разделитель в Linux командах. Без разделителя не всегда очевидно, является src/index.js файлом или указателем на коммит.
5. Сравнить две ветки
Сравнение двух веток — master и feature-branch
$ git diff master..feature-branch
Команда показывает разницу между двумя ветками — то есть, какие изменения нужно применить, чтобы из состояния master получить состояние feature-branch.
- Файлы, добавленные в
feature-branch - Файлы, изменённые в
feature-branch - Файлы, удалённые в
feature-branch
Тройная точка — показывает только то, что добавила feature-branch
$ git diff master...feature-branch
| Синтаксис | Поведение |
|---|---|
master..feature-branch |
Разница между верхушками (HEAD) веток |
master...feature-branch |
Разница от общего предка до feature-branch |
Три точки ... чаще используют при code review, так как она не учитывает изменения в master, которые не касаются ветки feature-branch.
6. Пример использования команды
git init echo "строка 1" > file.txt git add file.txt git commit -m "Initial commit"
# Добавляем строку 2 и выполняем git add echo "строка 2" >> file.txt git add file.txt # Добавляем строку 3 и не делаем git add echo "строка 3" >> file.txt
Теперь у нас такое состояние файла file.txt
[последний коммит] [stage area] [рабочая директория]
------------------------------------------------------------
строка 1 строка 1 строка 1
строка 2 строка 2
строка 3
Команда git diff — сравнение рабочей директории и stage area
строка 1 строка 2 +строка 3
Команда git diff --staged — сравнение stage area с последнии коммитом
строка 1 +строка 2
Команда git diff HEAD — сравнение рабочей директории и stage area c последним коммитом.
строка 1 +строка 2 +строка 3
7. Компактный вывод команды
Показывает не строки, а только список измененных файлов и количество добавленных-удаленных строк.
$ git diff --stat
Команда git rm
Команда удаляет файлы одновременно из индекса (stage area) и рабочей директории. Это отличает её от обычного rm — который удаляет только из файловой системы, не трогая Git.
| Команда | Working dir | Stage Area | Директория .git |
|---|---|---|---|
rm file.txt |
удалён | не тронут | не тронут |
git rm file.txt |
удалён | удалён | не тронут |
git rm --cached file.txt |
не тронут | удалён | не тронут |
# 1. Смотрим, какие файлы у нас есть ls # notes.txt config.json readme.md # 2. Удаляем файл в рабочей директории git rm notes.txt # 3. Статус — что готово к коммиту git status # Changes to be committed: # deleted: notes.txt ← удаление готово к коммиту # 4. Коммит — удаляем файл из проекта # (но этот файл останется в истории) git commit -m "Remove notes.txt"
Если файл имеет несохранённые изменения — Git откажет с ошибкой «the following file has local modifications».
Самый частый сценарий — случайно добавил файл в индекс (stage area)
# 1. Добавили всё подряд, без разбора git add . # 2. Увидели, что .env попал в индекс git status # Changes to be committed: # new file: feature.js # new file: utils.js # new file: .env ← не должен быть в коммите # 3. Убираем .env из индекса (stage area) git rm --cached .env # 4. Проверяем, что сейчас в индексе git status # Changes to be committed: # new file: feature.js # new file: utils.js ← только нужные файлы # # Untracked files: # .env ← файл остался на диске # 5. Все хорошо, выполняем коммит git commit -m "Add feature.js and utils.js"
Удалять можно не только файлы, но и директории
# 1. Структура директории для удаления ls -R temp/ # temp/log1.txt temp/log2.txt temp/cache/data.bin # 2. Без опции -r Git откажет в удалении git rm temp/ # fatal: not removing 'temp/' recursively without -r # 3. Опция -r для рекурсивного удаления git rm -r temp/ # rm 'temp/log1.txt' # rm 'temp/log2.txt' # rm 'temp/cache/data.bin' # 4. Директория удалена, выполняем коммит git commit -m "Remove temp directory"
Опция --force нужна, когда файл изменён, но изменения не закоммичены
# 1. Изменяем файл после последнего коммита echo "new line" >> important.txt git status # modified: important.txt ← есть несохранённые изменения # 2. Обычная команла git rm выдает ошибку git rm important.txt # error: the following file has local modifications: # important.txt # 3. Принудительно удаляем файл, опция -f git rm -f important.txt # файл удалён с диска + удален из индекса
Опция --dry-run позволяет проверить результат без реального удаления
# Посмотреть, что будет удалено git rm --dry-run -r logs/ # rm 'logs/error.log' # rm 'logs/access.log' # rm 'logs/debug/trace.log' # Все файлы остались на диске ls logs/ # error.log access.log debug/
Комбинирование нескольких опций
# Убрать всю папку из Git, но оставить файлы на диске git rm --cached -r node_modules/ # Принудительно убрать папку из индекса, оставив файлы # в рабочей директории и в истории проекта git rm --cached -r -f dist/ # Проверить рекурсивное удаление перед выполнением git rm --dry-run -r build/
Команда git log
Если git status показывает, что происходит прямо сейчас, то git log показывает, как ты пришел к текущему моменту. Если просто ввести git log, ты увидишь список всех коммитов, начиная с самого последнего. Каждый элемент списка содержит
- Хеш коммита
- Автор (имя и email)
- Дата и время
- Комментарий
1. Примеры использования
$ git log commit e7f3dd2ecc007a1c235645991282a1eb34b3c6d0 (HEAD -> master) Author: Evgeniy Tokmakov <tokmakov@gmail.com> Date: Fri Jun 5 13:49:16 2026 +0300 Second commit commit 0d9b1372a5c21fdbe5559be46d3dbcc9d2834341 Author: Evgeniy Tokmakov <tokmakov@gmail.com> Date: Fri Jun 5 13:32:12 2026 +0300 Initial commit
Компактный лог (одна строка на коммит)
$ git log --oneline e7f3dd2 (HEAD -> master) Second commit 0d9b137 Initial commit
Лог последних 5 коммитов
$ git log -n 5
2. Визуализация всех веток
Чтобы посмотреть, как это будет в терминале — нужно создать ветку, например feature. Эта ветку нужно влить в master после того, как в самом master будет выполнен коммит. Если между моментом создания feature и моментом ее вливания в master не будет коммита — Git выполнит Fast-forward.
# 1. Создаем новую ветку git switch -c feature # 2. Делаем новый коммит в этой ветке echo "New feature" > feature.txt git add feature.txt git commit -m "Feature commit" # 3. Переключаемся обратно на master git switch master # 4. Делаем другой коммит в master echo "Update master" >> master.txt git add master.txt git commit -m "Master commit" # 5. Вливаем feature в master git merge feature -m "Merging feature branch"
Компактный лог с визуализацией веток
$ git log --oneline --graph --all
--graph— рисует в консоли псевдографические «линии» веток (кто куда влился)--all— показывает историю всех веток, а не только той, где ты сейчас
* 9655b7c (HEAD -> master) Merging feature branch |\ | * b9c9481 (feature) Feature commit * | a207edd Master commit |/ * ebaa238 Second commit * 984d1d0 Initial commit
Команда git reset
Команда git reset — это «пульт управления» положением твоей текущей ветки. Если git commit создает новые записи в истории, то git reset перемещает указатель (HEAD) на уже существующие записи истории проекта.
У этой команды есть три главных «режима» (флага), которые определяют, что именно произойдет с файлами при перемещении указателя.
| Опция | История (HEAD) | Индекс (Staged) | Рабочие файлы |
|---|---|---|---|
--soft |
Меняется | Сохраняется | Сохраняются |
--mixed |
Меняется | Сбрасывается | Сохраняются |
--hard |
Меняется | Сбрасывается | Сбрасываются |
1. Режим «soft» (безопасный)
Перемещает указатель назад, но оставляет все файлы в stage area (индексе). Допустим, ты сделал коммит, но забыл добавить один файл или нашел опечатку.
$ git reset --soft HEAD~1
Файлы остались «зелеными» (в индексе), ты просто добавляешь нужный файл и делаешь новый коммит.
2. Режим «mixed» (средний)
Это режим по умолчанию — перемещает указатель назад, но «выбрасывает» файлы из stage area. Ты выполнил коммит, но понял, что не готов их сохранять, хочешь поработать над кодом еще немного.
$ git reset HEAD~1
Изменения все еще в файлах (ты ничего не потерял), но в stage area теперь пусто. Можно еще поработать, добавить файлы с помощью git add и выполнить коммит.
git reset в режиме soft/mixed никогда не меняет содержимое файлов, которые находятся в рабочей директории.
3. Режим «hard» (опасный)
Полностью меняет рабочую директорию, приводя её к состоянию указанного коммита. Ты начал эксперимент, запутался, все сломал. Хочешь вернуть проект к состоянию последнего коммита.
$ git reset --hard HEAD
Все, что ты «нагородил» в файлах с момента последнего коммита — исчезнет.
4. Пример использования команды
Ты наделал кучу изменений в 5 файлах, выполнил коммит, но хочешь разбить их на два разных коммита.
- Команда
git reset --soft HEAD~1— вернулся к состоянию перед коммитом. - Команда
git reset— теперь все файлы пропали из индекса (stage area). - Команда
git add file1.txt file2.txt, потом командаgit commit -m "Часть первая". - Команда
git add .(последние 3 файла), потом командаgit commit -m "Часть вторая".
Вместо первых двух команд можно выполнить одну (git reset HEAD~1) — но с двумя нагляднее. Мы убрали последний коммит из истории и откатились к состоянию перед выполнением последнего коммита. И теперь начинаем наводить порядок в истории, разбивая большой коммит на два маленьких.
5. Главное правило использования
Никогда не делай git reset --hard (и вообще любой reset), если ты уже отправил эти коммиты в общий репозиторий (GitHub/GitLab), с которым работают другие люди. Если ты «откатишь» историю у себя, а потом попытаешься отправить её на сервер, ты создашь хаос для своих коллег.
Команда reset — это инструмент для «причесывания» локальной истории перед отправкой в мир.
Команда git stash
Бывает, что нужно срочно переключиться на другую ветку, а текущая работа еще не готова к коммиту. Команда git stash прячет изменения в специальное хранилище, оставляя рабочую папку чистой. Позже изменения можно восстановить из этого хранилища командой git stash pop.
Представь — ты работаешь в feature, изменил файл file.txt. Эти изменения еще не закоммичены. Тут прилетает срочная задача — исправить баг. Ты вводишь git switch master. Что сделает Git?
- Если изменения не конфликтуют — Git просто «перенесет» твои правки из
featureвmaster. Теперь в веткеmasterлежат недоделанные куски кода — это плохо. - Если изменения конфликтуют — Git просто запретит тебе переключение и выдаст ошибку «Your local changes to the following files would be overwritten by checkout».
Как команда stash помогает решить эту проблему
- Ты в ветке
feature— работаешь над новой фичей, на руках «недострой». - Прилетает срочная задача — нужно переключиться на
master, создать веткуfix-bug. - Команда
git stash -u— ты прячешь «недострой» в «карман». Твоя рабочая директория теперь идеально чистая (соответствует последнему коммиту вfeature). - Команда
git switch master— теперь ты можешь спокойно переключиться, Git не ругается. - Команда
git switch -c fix-bug— создаешь ветку для исправления бага. - Делаешь фикс, коммитишь, мерджишь в ветку
master— готово. - Команда
git switch feature— возвращаешься в свою ветку. - Команда
git stash pop— достаешь «недострой» из кармана и продолжаешь с того же места.
Команда git stash игнорирует новые файлы, которые еще не добавлены под наблюдение Git с помощью git add. Рекомендуется использовать git stash -u, чтобы спрятать в «карман» все файлы.
Команда git stash pop означает «достать и удалить». Она достает файлы и сразу удаляет их в «кармане». Если что-то пошло не так (например, случился конфликт), заначка всё равно будет удалена, и восстановить её будет сложнее.
Команда git stash apply означает «достать и оставить». Она достает файлы, но при этом оставляет их в «кармане». Удалить файлы из «кармана» можно с помощью команды git stash drop.
В «кармане» может быть целый список «заначек» — stash@{0}, stash@{1}, stash@{2} и т.д. При каждом выполнении git stash — добавляется новый элемент. При каждом выполнении git stash pop — достается последний добавленный элемент.
git stash list— посмотреть список всех «заначек» в «кармане»git stash apply stash@{1}— достать конкретную «заначку» из спискаgit stash drop stash@{1}— удалить конкретную «заначку» из спискаgit stash clear— удаляет вообще все заначки в «кармане»
В Git нет жесткой привязки «заначки» к ветке, где она была сделана. Если ты понял, что начал делать фичу не в той ветке, ты можешь сделать git stash, переключиться в другую ветку и сделать git stash pop прямо там. Это самый простой способ «перенести» незаконченную работу из одной ветки в другую.
Команда git restore
Команда git restore появилась в Git 2.23 для того, чтобы разделить запутанные функции команды git checkout, которая раньше отвечала и за переключение веток, и за восстановление файлов.
Главная задача — «отменить» изменения, вернув файл к состоянию, в котором он был в определенном месте (коммите или индексе).
1. Исключить файл из stage area
Убрать файл из stage area, если ты случайно сделал git add, но еще не готов коммитить.
# 1. Создаём файл и выполняем коммит echo "Initial content" > file.txt git add file.txt git commit -m "Initial commit" # 2. Меняем файл и добавляем в индекс echo "Staged content" > file.txt git add file.txt # 3. Меняем файл, не добавляем в индекс echo "Unstaged content" > file.txt # Теперь есть три разных состояния: # HEAD: "Initial content" # Stage Area: "Staged content" # Рабочая папка: "Unstaged content" git status # Changes to be committed: file.txt ← "Staged content" # Changes not staged: file.txt ← "Unstaged content" # 4. Убираем файл из индекса git restore --staged file.txt # Результат: # HEAD: "Initial content" # Индекс: пусто, нет файлов для коммита # Рабочая папка: "Unstaged content" # "Staged content" потеряно безвозвратно!
Этот пример — не слишком удачная демонстрация возможностей команды. Потому как файл просто удаляется из stage area, при этом теряется то состояние файла, которое было в индексе.
2. Восстановить из stage area (индекса)
Восстанавливает файл в рабочей директории из stage area. Другими словами, отменяет изменения в рабочей директории, которые ещё не были добавлены в индекс. Все изменения после последнего git add — будут потеряны.
# 1. Создаем файл, фиксируем его и добавляем строку echo "Original content" > file.txt git add file.txt git commit -m "Initial commit" # 2. Добавляем еще одну строку, выполняем git add echo "Add content one" >> file.txt git add file.txt # 3. Добавляем ещё изменения, но не делаем git add echo "Add content two" >> file.txt # 4. Восстанавливаем из stage area (из индекса) git restore file.txt # 5. Файл вернулся к состоянию последнего git add cat file.txt # Original content # Add content one
3. Восстановить из последнего коммита
Восстанавливает файл в рабочей директории из последнего коммита. Другими словами, отменяет все изменения файла после последнего коммита. Команда перезаписывает только рабочую директорию и не трогает stage area. Если файл был добавлен в индекс — там останется старое содержимое.
# Восстанавливаем файл из последнего коммита git restore --source=HEAD file.txt # Файл вернулся к состоянию "Original content" cat file.txt
4. Вернуть состояние файла из конкретного коммита
Если ты хочешь полностью «выкинуть» текущую версию файла и заменить её на версию из прошлого.
# 1. Еще раз изменяем наш файл, заменяем содержимое echo "Experimental stuff" > file.txt git add file.txt git commit -m "Experimental commit" # 2. Возвращаем файл к состоянию предыдущего коммита git restore --source=HEAD~1 file.txt # 3. Файл вернулся к состоянию "Original content" cat file.txt
5. Восстановить директорию или весь проект
Аналогично можно восстановить отдельную директорию или даже весь проект — тогда вместо файла указываем директорию.
project/ <-- Корень репозитория ├── src/ │ ├── components/ │ │ ├── Button.js │ │ └── Header.js │ └── utils/ │ └── helpers.js ├── docs/ │ └── readme.txt └── package.json
Восстановить директорию components на момент предыдущего коммита
# Из директории src/components cd src/components git restore --source=HEAD~1 .
# Из любого места проекта git restore --source=HEAD~1 src/components
Восстановить весь проект целиком на момент предыдущего коммита
# Выполняем зз корня проекта git restore --source=HEAD~1 .
Хотя Git понимает полные пути к файлам (например, /home/user/project/src), лучше использовать пути относительно корня репозитория. Это делает команды переносимыми — они будут работать везде, независимо от того, в какой директории лежит проект.
Команда git worktree
Позволяет работать с несколькими ветками одного репозитория одновременно в разных рабочих директориях, без необходимости переключаться между ветками в одной директории.
Дополнительные рабочие директории создаются вне исходной рабочей директории — но они связаны с тем же репозиторием через общую .git директорию.
$ git worktree add path branch
Допустим, есть директория проекта /home/evgeniy/project/master с .git внутри
1. Создание новой ветки и рабочего дерева для нее
$ cd /home/evgeniy/project/master $ git worktree add ../feature-worktree feature-branch
Результат команды
/home/evgeniy/project/master— исходная рабочая директория/home/evgeniy/project/feature-worktree— новая рабочая директория
Обе используют один репозиторий .git из /home/evgeniy/project/master/.git
2. Создание рабочего дерева для существующей ветки
$ git worktree add ../hotfix-worktree hotfix-branch
3. Удаление worktree после завершения работы
$ git worktree remove ../hotfix-worktree
4. Просмотр всех существующих worktree
$ git worktree list
Вывод показывает все рабочие деревья, их пути и связанные ветки.
Команда git rebase
Представь, что у тебя есть две ветки — master и feature. Ты начал работать в feature, за это время в master появились новые коммиты.
Rebase — это способ переместить твои коммиты в ветке feature на верхушку (в конец) ветки master. То есть вместо того, чтобы «склеивать» две линии разработки через merge (создавая коммит слияния), ты «переписываешь» историю feature так, как будто ты начал работу от последнего состояния master.
A -- B -- M \ / C -- D
A -- B -- C' -- D'
Коммиты C' и D' — это новые версии C и D, с новыми хешами, но с тем же содержимым.
1. В чем отличие rebase от merge
Mergeсоздает дополнительный merge-commit, сохраняя полную историю обеих веток (они как бы «соединяются»). Появляются мусорные коммиты вида «Merge branch X into master».Rebase«выпрямляет» историю — каждый твой коммит применяется поверх последнего коммитаmaster, без лишних точек слияния. История проекта становится линейной и чистой.
При этом есть возможность решить все конфликты до того, как вливать feature в master.
mkdir project && cd project git init echo 'init project' > file.txt git add . git commit -m 'Initial commit'
git switch -c feature echo 'feature work' >> file.txt git add . git commit -m 'Feature update'
git switch master echo 'master update' >> file.txt git add . git commit -m 'Master update'
git switch feature git rebase master
2. Типичный сценарий использования
Ты работаешь в ветке feature, за это время коллеги обновили ветку master. Тебе нужно подтянуть их изменения к себе, выполнить перебазирование, решить конфликты.
1. Обновляем главную ветку
git switch master git pull
2. Возвращаемся в рабочую ветку
git switch feature
3. Запускаем перебазирование
git rebase master
Если конфликтов нет, магия свершилась — твои коммиты теперь в конце (или поверх) свежего master.
3. Что делать при конфликтах слияния
Если во время rebase Git найдет конфликты — процесс остановится. В консоли будет написано Merge conflict in имя_файла.
Что нужно делать
- Открой конфликтные файлы в редакторе (например, VS Code).
- Оставь нужный код, удали маркеры конфликтов (
<<<<<<<,=======,>>>>>>>). - Сохрани измененные файлы.
- Добавь их в индекс (сообщи Git, что конфликт решен).
$ git add file.txt
Команду git commit здесь выполнять не нужно.
Продолжи процесс rebase
$ git rebase --continue
Повторяй шаги, пока rebase не завершится.
4. Отменить весь процесс rebase
Если ты запутался в конфликтах и хочешь отменить весь процесс rebase, вернув ветку в исходное состояние, выполни команду
$ git rebase --abort
Работа с удалённым репозиторием
[локальный репозиторий] ←→ [удалённый репозиторий]
твой компьютер GitHub / GitLab
Стандартное имя удалённого репозитория — origin. Это просто псевдоним (алиас) для длинного URL. Вместо того, чтобы каждый раз писать
$ git push https://github.com/username/some-repo.git master
Пишем коротко
$ git push origin master
При создании репозитория с нуля — нужно задать имя (обычно origin) и установить связь (tracking).
git init # Задаем для удаленного репозитория имя origin git remote add origin https://github.com/username/some-repo.git # Локальная ветка master отслеживает удаленную git branch --set-upstream-to=origin/master master
При клонировании репозитория — имя origin и связь master-master настраиваются автоматически.
$ git clone https://github.com/username/some-repo.git
При клонировании локально будет создана только ветка master (или main), остальные ветки будут существовать как удаленные (remotes/origin/...) — Git о них знает, но локальные копии не создает. Однако, при переключении на (не существующую) локальную ветку develop — создаст эту ветку автоматически.
$ git switch develop $ git branch -a * develop master remotes/origin/HEAD -> origin/master remotes/origin/develop remotes/origin/master
Запись remotes/origin/HEAD означает «главная ветка удаленного репозитория». Клонирование всегда работает правильно, Git смотрит на origin/HEAD и понимает — какую ветку создать локально по умолчанию.
Связь (tracking) означает, что Git знает, куда отправлять и откуда забирать изменения. Если связь не настроена — при выполнении push и pull будут ошибки.
# Если tracking для ветки не настроен git push # error: No configured push destination git pull # error: No remote repository specified
Проверить связь текущей локальной ветки с удаленной — можно с помощью команды
$ git remote -v origin https://github.com/username/some-repo.git (fetch) origin https://github.com/username/some-repo.git (push)
Проверить tracking всех веток в локальном репозитории — можно с помощью команды
$ git branch -vv
Схема взаимодействия с удаленным репозиторием
ЛОКАЛЬНЫЙ РЕПОЗИТОРИЙ УДАЛЁННЫЙ РЕПОЗИТОРИЙ (origin)
┌─────────────────────┐ git push -u origin master ┌─────────────────────┐
│ ветка: master │◄─────────────────────────────►│ ветка: master │
│ ветка: develop │ git push -u origin develop │ ветка: develop │
│ ветка: feature/xxx │◄─────────────────────────────►│ ветка: feature/xxx │
│ ..... │◄─────────────────────────────►│ ..... │
└─────────────────────┘ └─────────────────────┘
│ │
└─────────────── git remote add origin ───────────────┘
(короткое имя для URL)
Tracking устанавливается отдельно для каждой ветки — обычно не отдельной командой, а при выполнении push с добавлением опции -u.
$ git push -u origin local_branch
Имя локальной и удаленной ветки могут не совпадать — но на практике так не делают, чтобы не создавать путиницу.
$ git push -u origin local_branch:remote_branch
Синтаксис src:dst встречается и в других командах Git — например в git fetch и git push. Общий смысл всегда одинаковый — откуда:куда.
Выложить проект на GitHub
Первый шаг — создание репозитория на GitHub, задаем имя, не добавляем README.md.
Второй шаг — нужно задать имя для удаленного репозитория, обычно origin
# Cоздаем проект для публикации на GitHub git init git add . git commit -m "Initial commit" # Задаем имя для удалённого репозитория git remote add origin https://github.com/username/some-repo.git
Третий шаг — отправляем код локальной ветки master в удаленную ветку origin/master
# Синтаксис откуда:куда, из локальной master в удаленную master git push -u origin master:master # Обычно имена веток одинаковые, имя удаленной ветки пропускаем git push -u origin master
Опция -u связывает локальную и удаленную ветки (tracking), так что в следующий раз достаточно git push — без указания, куда отправлять.
Клонировать репозиторий c GitHub
# Клонировать в директорию some-repo git clone https://github.com/username/some-repo.git # Клонировать в конкретную директорию git clone https://github.com/username/some-repo.git my-folder
После клонирования origin уже настроен автоматически, связь установлена.
Основные команды синхронизации
[локальный репозиторий] ←→ [удалённый репозиторий] git push →→→→→→→→→ ←←←←←←←← git pull ←←←←←←←← git fetch
| Команда | Что делает |
|---|---|
git push |
Отправляет коммиты на удалённый репозиторий |
git pull |
Скачивает и сразу вливает изменения в текущую ветку |
git fetch |
Только скачивает изменения, не вливает |
Командная разработка
Никто не пушит напрямую в master — каждый работает в своей ветке
master (стабильная ветка) │ ├── feature/login ← разработчик 1 ├── feature/payment ← разработчик 2 └── bugfix/header-crash ← разработчик 3
Чтобы включиться в работу — синхронизируйся с командой
$ git switch master $ git pull origin master
Создай свою ветку для выполнения задачи
$ git switch -c feature/login
Пиши код, добавляй коммиты
# ... пишешь код ... git add . git commit -m "feat: add login form" # ... пишешь код ... git add . git commit -m "feat: add login validation"
Отправь свою ветку на GitHub
$ git push origin feature/login
Создай Pull Request (PR) на GitHub
- Открываешь проект на GitHub
- Нажимаешь «New Pull Request»
- Выбираешь
feature/login→master - Описываешь, что сделал в задаче
- Коллеги проверяют код (code review)
- После одобрения — ветка вливается в
master
После merge — обнови локальный master
git switch master # забираем свежие изменения git pull origin master # удаляем локальную ветку git branch -d feature/login
Если master обновился, пока ты работал
# Ты работаешь в ветке feature/login # Коллега залил изменения в master git switch master git pull origin master git switch feature/login # вливаем свежий master в свою ветку git merge master # или выполняем rebase вместо merge git rebase master
Поиск: CLI • Git • GitHub • Команда • Система контроля версий