Git. Управление версиями проекта

14.06.2026

Теги: CLIGitGitHubКомандаСистемаКонтроляВерсий

Git — система контроля версий, которая помогает следить за изменениями в файлах проекта. Она работает как «фотограф» исходного кода: каждый раз при выполнении коммита (commit), Git сохраняет моментальный снимок всех файлов. Эти снимки хранятся в репозитории (локальном хранилище), и можно вернуться к любой сохраненной версии.

Установка

  1. Windows — скачать и запустить установщик с git-scm.com
  2. 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 area
  • git commit -m "Сообщение" — создать коммит с описанием изменений
  • git status — показать текущий статус файлов (изменённые, добавленные)
  • git log — просмотр история коммитов

Работа с ветками (branch)

  • git branch — список веток
  • git switch имя_ветки — переключиться на ветку (новый способ)
  • git checkout имя_ветки — переключиться на ветку (старый способ)
  • git switch -c имя_новой_ветки — создать новую ветку и переключиться на нее
  • git checkout -b имя_новой_ветки — создать новую ветку и переключиться на нее
  • git merge ветка — влить в текущую ветку изменения из другой ветки

Синхронизация с удалённым репозиторием

  • git push — отправка изменений на GitHub/GitLab
  • git pull — получение изменений из GitHub/GitLab

Полезные советы по работе с Git

  • Файл .gitignore позволяет исключить ненужные файлы
  • Коммиты лучше делать небольшими, с понятным комментарием
  • Чаще использовать git status чтобы не потерять изменения

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

Git отслеживает изменения в файлах проекта через три основных области

  1. Git-директория — это директория .git
  2. Рабочая директория — директория проекта
  3. Stage Area — область подготовленных файлов

1. Git-директория или Repository

Это основное хранилище Git, расположенное в директории .git в корне проекта. Здесь хранится вся история проекта, включая коммиты, ветки, теги и метаданные. Git-директория — это «база данных» Git, которая сохраняет состояние проекта в разные моменты времени. Она не изменяется напрямую пользователем, а управляется командами Git (например, commit, merge).

2. Рабочая директория (Working Directory)

Это директория проекта, где идет работа, то есть создание и редактирование файлов. Она содержит все файлы и директории, включая те, которые не отслеживаются Git. Рабочая директория — это «живая» область, где идет работа над проектом. При изменении файлов здесь — Git сравнивает их с последним сохранённым состоянием в Git-директории.

3. Stage Area или Index

Это промежуточная область между рабочей директорией и Git-директорией. Здесь временно хранятся изменения, которые нужно включить в следующий коммит. Область подготовки позволяет точно контролировать, что попадет в историю Git, например, выбрать только часть изменённых файлов для коммита.

Связь между областями

  1. Рабочая директория → Stage Area
    Разработчик изменяет файлы в рабочей директории, затем добавляет их в stage area командой git add. Это «подготовка» изменений к коммиту.
  2. Stage Area → Git-директория
    Команда git commit переносит изменения из stage area в Git-директорию, создавая новый коммит в истории проекта.
  3. 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 не может автоматически определить, какие изменения принимать), нужно

  1. Отредактировать файлы с конфликтами
  2. Выполнить git add для исправленных файлов
  3. Завершить слияние командой 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 — это коммит D
  • HEAD~1 — это коммит C
  • HEAD~2 — это коммит B
  • HEAD~3 — это коммит A

Это удобно тем, что не нужно копировать длинный хеш коммита (например, a1b2c3d4...). Если ты знаешь, что ошибку допустил «пару коммитов назад», ты просто пишешь HEAD~2 и не тратишь время на поиск идентификаторов.

Иногда ты увидишь символ ^ — он означает «родитель». Разница между ~ и ^ становится заметна, только если у тебя есть merge-коммиты (узлы, где соединяются две ветки) — у них два родителя

  • HEAD^1 — родитель из основной ветки
  • HEAD^2 — родитель из ветки, которую ты «вливал»

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

Команда git commit

При выполнении команды git commit, файлы из stage area попадают в историю в том состоянии, в котором они были на момент последнего выполнения git add.

  1. Момент git add. При выполнении команды git add, «снимок» текущего состояния файла фиксируется и помещается в stage area. Это состояние не меняется автоматически, даже если файл редактировался в рабочей директории после выполнения git add.
  2. Между git add и git commit. При редактировании файла после выполнения git add — в рабочей директории будет новое состояние, но stage area сохранит старое состояние (до изменений). Чтобы включить новые изменения в коммит, нужно повторно выполнить git add.
  3. Момент 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 area
  • git diff --staged — сравнить stage area с последним коммитом

Как отредактировать комментарий последнего коммита?

Если ты просто хочешь исправить опечатку или сделать сообщение более понятным, используй команду amend (с англ. «исправить»).

$ git commit --amend -m "Новое правильное сообщение"

Git возьмет последний коммит, изменит его сообщение на новое и сохранит под тем же (или новым) идентификатором. Это самый простой способ сделать историю «чистой».

Как «удалить» последний коммит и выполнить его снова?

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

$ git reset --soft HEAD~1

Опция --soft — означает «мягкий сброс». Git удаляет коммит из истории, но оставляет все твои файлы в индексе (stage area). Аргумент HEAD~1 предписывает «откатиться на один шаг назад».

После этой команды

  1. Твои файлы остались в «зеленом» состоянии (в индексе)
  2. Ты можешь добавить нужные файлы с помощью git add
  3. Снова выполнить коммит — git commit -m "Исправленный коммит"

Команда git status

Самая важная команда, которую стоит вводить перед любым действием (перед коммитом, перед пушем, перед переключением веток). Она показывает текущее состояние рабочей директории и индекса (stage area).

Обычно вывод команды содержит

  1. On branch master — показывает, в какой ветке ты сейчас находишься. Это первое, на что надо смотреть, чтобы не закоммитить код в master по ошибке.
  2. Changes to be committed (зеленый цвет) — это файлы в индексе (stage area). Они готовы к коммиту. Если ты введешь git commit, в него попадут именно эти изменения.
  3. Changes not staged for commit (красный цвет) — это файлы, которые ты изменил, но не добавил в индекс (не сделал git add). Они не попадут в коммит, если сделаеть его прямо сейчас.
  4. 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 файлах, выполнил коммит, но хочешь разбить их на два разных коммита.

  1. Команда git reset --soft HEAD~1 — вернулся к состоянию перед коммитом.
  2. Команда git reset — теперь все файлы пропали из индекса (stage area).
  3. Команда git add file1.txt file2.txt, потом команда git commit -m "Часть первая".
  4. Команда 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?

  1. Если изменения не конфликтуют — Git просто «перенесет» твои правки из feature в master. Теперь в ветке master лежат недоделанные куски кода — это плохо.
  2. Если изменения конфликтуют — Git просто запретит тебе переключение и выдаст ошибку «Your local changes to the following files would be overwritten by checkout».

Как команда stash помогает решить эту проблему

  1. Ты в ветке feature — работаешь над новой фичей, на руках «недострой».
  2. Прилетает срочная задача — нужно переключиться на master, создать ветку fix-bug.
  3. Команда git stash -u — ты прячешь «недострой» в «карман». Твоя рабочая директория теперь идеально чистая (соответствует последнему коммиту в feature).
  4. Команда git switch master — теперь ты можешь спокойно переключиться, Git не ругается.
  5. Команда git switch -c fix-bug — создаешь ветку для исправления бага.
  6. Делаешь фикс, коммитишь, мерджишь в ветку master — готово.
  7. Команда git switch feature — возвращаешься в свою ветку.
  8. Команда 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 имя_файла.

Что нужно делать

  1. Открой конфликтные файлы в редакторе (например, VS Code).
  2. Оставь нужный код, удали маркеры конфликтов (<<<<<<<, =======, >>>>>>>).
  3. Сохрани измененные файлы.
  4. Добавь их в индекс (сообщи 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/loginmaster
  • Описываешь, что сделал в задаче
  • Коллеги проверяют код (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 • Команда • Система контроля версий

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.