Откуда вообще берётся бардак: три категории файлов
Прежде чем что-то удалять, надо понимать, с чем Git вообще имеет дело. У любого файла в рабочем каталоге есть статус, и команды уборки работают строго по этим статусам.
- Отслеживаемые (tracked) - Git их знает, они есть в индексе и/или в истории. Их откатывает restore, удаляет git rm.
- Неотслеживаемые (untracked) - файлы, которые ты создал, но не добавил в индекс. Git про них знает только то, что они валяются рядом. Их трогает git clean.
- Игнорируемые (ignored) - подмножество неотслеживаемых, которые попадают под правила .gitignore (сборка, node_modules, .env, IDE-мусор). По умолчанию Git их вообще не показывает и НЕ удаляет - пока ты явно не попросишь флагом -x.

git clean: как очистить рабочий каталог git и не потерять данные
Главное правило, которое спасёт тебе нервы и проект: ВСЕГДА сначала -n. Флаг -n (он же --dry-run) ничего не удаляет, а только печатает, что будет удалено. Это твой предохранитель.
Код: Выделить всё
$ git clean -n
Would remove test_output.log
Would remove debug.txt
Код: Выделить всё
$ git clean
fatal: clean.requireForce defaults to true and neither -i, -n, nor -f given; refusing to clean
Код: Выделить всё
$ git clean -f
Removing test_output.log
Removing debug.txt
- -d - заходить в неотслеживаемые каталоги. Без -d clean чистит только файлы в корне неотслеживаемых директорий, но сами пустые каталоги и их содержимое может оставить. Хочешь снести целиком папку temp\ - нужен -d.
- -x - вот это динамит. Включает в зачистку ИГНОРИРУЕМЫЕ файлы. То есть всё, что защищено .gitignore (твой .env, локальные конфиги, кэш сборки), полетит в небытие.
- -X (большая) - наоборот, удалить ТОЛЬКО игнорируемое, а руками созданные неотслеживаемые файлы не трогать. Удобно почистить артефакты сборки, не задев заметки.
- -i - интерактивный режим. Git показывает список и спрашивает, что делать. Для новичка - самый безопасный способ.
Код: Выделить всё
$ git clean -di
Would remove the following items:
build/ debug.txt test_output.log
*** Commands ***
1: clean 2: filter by pattern 3: select by numbers
4: ask each 5: quit 6: help
What now>
ОПАСНОСТЬ: почему git clean -fdx может стоить тебе вечера
Запомни эту строчку как заклинание, которое НЕ надо произносить бездумно:
Код: Выделить всё
$ git clean -fdx
- твой .env с паролями и токенами (он же в .gitignore - значит, под -x);
- локальные конфиги вроде config.local.php, settings.json IDE;
- node_modules\, vendor\, кэши - это переставится, не страшно;
- и любые рабочие заметки, которые ты не закоммитил.
Практический совет из реальной жизни: перед любым clean -x сначала прогоняй с -n, глазами читай каждую строчку, и особенно ищи в списке свой .env. Увидел его в Would remove - стоп, не выполняй с -f, вынеси .env в сторонку или используй -X вместо -x.
git mv и git rm: почему не обычные mv и rm
Теперь к отслеживаемым файлам. Ты можешь переименовать файл обычным системным mv, а потом git add старое-удаление и новое-добавление. Это сработает, но это два шага и лишний шанс забыть про индекс. Команда git mv делает то же самое одним движением и сразу обновляет индекс.
Код: Выделить всё
$ git mv src/old_name.py src/new_name.py
$ git status
On branch main
Changes to be staged:
renamed: src/old_name.py -> src/new_name.py
Аналогично git rm удаляет отслеживаемый файл И с диска, И из индекса за один заход:
Код: Выделить всё
$ git rm config/legacy.ini
rm 'config/legacy.ini'
$ git status
Changes to be staged:
deleted: config/legacy.ini
Грабли: если файл уже изменён или застейджен, Git откажется удалять без подтверждения - чтобы ты не потерял правки.
Код: Выделить всё
$ git rm config/legacy.ini
error: the following file has staged content different from both the
file and the HEAD:
config/legacy.ini
hint: (use -f to force removal)
git rm --cached: убрать из индекса, оставить на диске
Это отдельный, очень частый сценарий, ради которого стоит запомнить флаг --cached. Представь: ты случайно закоммитил .env или огромный бинарник, который должен был быть в .gitignore. Тебе надо вынуть его из Git, но оставить файл на диске - он же нужен для работы.
Код: Выделить всё
$ git rm --cached .env
rm '.env'
$ git status
Changes to be staged:
deleted: .env
Untracked files:
.env
Для рекурсивного удаления каталога из индекса добавляй -r:
Код: Выделить всё
$ git rm -r --cached build/
Исторически один git checkout делал слишком много: переключал ветки, восстанавливал файлы, создавал ветки, отвязывал HEAD. Перегруженный комбайн, в котором новички путались - git checkout some_name мог означать и переход на ветку, и затирание файла, в зависимости от того, что за some_name. Поэтому функции разнесли по двум командам: git switch для веток и git restore для файлов. И вот свежий факт на 2026: с Git 2.51 обе команды официально вышли из экспериментального статуса - они СТАБИЛЬНЫ, их интерфейс зафиксирован, можно смело учить и использовать в скриптах.
git restore - это про восстановление содержимого файлов. Базовое: откатить файл в рабочем каталоге к последнему коммиту, выбросив несохранённые правки.
Код: Выделить всё
$ git restore config.yml
restore умеет работать прицельно по слоям трёх деревьев (рабочий каталог и индекс):
- git restore file - вернуть файл в рабочем каталоге (источник по умолчанию - индекс).
- git restore --staged file - убрать файл из индекса, то есть отменить git add (анстейдж), оставив правки в рабочем каталоге. Раньше для этого учили невнятное git reset HEAD file.
- git restore --staged --worktree file - снести правки и в индексе, и на диске разом.
- git restore --source=HEAD~2 file - вытащить версию файла из конкретного коммита (два назад), не трогая остальное.
Код: Выделить всё
# Откатить файл (одно и то же действие)
git checkout -- file.txt # старый способ
git restore file.txt # современный
# Анстейдж файла
git reset HEAD file.txt # старый способ
git restore --staged file.txt # современный
# Переключить ветку
git checkout main # старый
git switch main # современный
Типичные грабли
- clean -fdx по привычке. Видел в чужом гайде - скопировал - снёс .env. Всегда сначала -n, и думай, нужен ли тебе именно -x (игнорируемое) или хватит -X.
- Думать, что clean можно отменить. Нельзя. Нет stash, нет reflog, нет корзины. Только бэкап файловой системы.
- git restore затирает правки молча. Нет подтверждения, нет вывода. Перепутал файл - потерял работу. Если правки могут понадобиться - сначала git stash, а не restore.
- Системный rm вместо git rm. Файл удалён с диска, но индекс об этом не знает, пока не сделаешь add/rm. Лишний шаг и путаница в git status.
- git rm вместо git rm --cached для секрета. Снёс .env с диска целиком, а он был нужен приложению. Для вынимания из индекса с сохранением на диске - всегда --cached.
Повтори руками в тестовом репозитории, тут всё безопасно.
Код: Выделить всё
# 1. Готовим песочницу
mkdir clean-lab && cd clean-lab
git init -b main
echo "main code" > app.py
git add app.py && git commit -m "init"
# 2. Создаём мусор: untracked, ignored и каталог
echo "secret=123" > .env
echo ".env" > .gitignore
echo "log line" > debug.log
mkdir trash && echo "x" > trash/junk.txt
# 3. Сухой прогон БЕЗ игнорируемого
git clean -nd
# -> Would remove debug.log
# -> Would remove trash/
# (.env НЕ показан - он игнорируется)
# 4. Сухой прогон С игнорируемым - тут вылезет .env
git clean -ndx
# -> Would remove .env <-- ОПАСНО, читай глазами!
# 5. Чистим только мусор, .env бережём
git clean -fd
# 6. Тренируем restore: ломаем и чиним файл
echo "BROKEN" >> app.py
git restore app.py
cat app.py # снова "main code", правка исчезла
# 7. Анстейдж через restore
echo "new" >> app.py
git add app.py
git restore --staged app.py
git status # app.py изменён, но не застейджен
# 8. Убрать из индекса, оставив на диске
git add .env 2>/dev/null; git rm --cached .env
ls -la # .env на месте, но deleted в индексе
Контрольные вопросы
- Почему перед git clean -f почти всегда сначала запускают git clean -n, и можно ли потом отменить удаление?
- Чем git clean -x опаснее обычного git clean и какой файл чаще всего страдает?
- В чём разница между git rm file и git rm --cached file? Когда нужен именно второй?
- Как через git restore отменить git add, не теряя правок в файле? А как вернуть файл к версии из коммита HEAD~2?
Четыре команды, две зоны. clean и (системный) rm работают с тем, что Git либо не знает, либо удаляет насовсем, - тут ошибки НЕОБРАТИМЫ, поэтому clean только через -n сначала. mv, rm и restore работают с отслеживаемыми файлами и индексом аккуратно, в один шаг. restore и switch с 2.51 стабильны и заменяют перегруженный checkout: restore - для файлов, switch - для веток. Главное, что унесёшь из главы: git clean удаляет неотслеживаемые файлы без права на восстановление, а git clean -fdx добивает ещё и игнорируемое вроде .env - поэтому палец над Enter держи только после сухого прогона.