Вспомогательные команды: clean, mv, rm, restore

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

Вспомогательные команды: clean, mv, rm, restore

Сообщение Pavel_Git »

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

Откуда вообще берётся бардак: три категории файлов

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

Изображение

git clean: как очистить рабочий каталог git и не потерять данные

Главное правило, которое спасёт тебе нервы и проект: ВСЕГДА сначала -n. Флаг -n (он же --dry-run) ничего не удаляет, а только печатает, что будет удалено. Это твой предохранитель.

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

$ git clean -n
Would remove test_output.log
Would remove debug.txt
Видишь Would remove - значит, это сухой прогон, файлы на месте. Прочитал список, согласен - выполняешь по-настоящему. Git намеренно вредный: голый git clean без -f или -n он выполнять откажется, чтобы ты случайно не снёс лишнего.

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

$ git clean
fatal: clean.requireForce defaults to true and neither -i, -n, nor -f given; refusing to clean
Чтобы удаление реально произошло, нужен -f (--force):

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

$ 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>
Жмёшь 4 (ask each) - и Git по каждому файлу отдельно спрашивает Remove build/ [y/N]. Медленно, зато ничего лишнего не улетит.

ОПАСНОСТЬ: почему git clean -fdx может стоить тебе вечера

Запомни эту строчку как заклинание, которое НЕ надо произносить бездумно:

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

$ git clean -fdx
Она означает: удалить принудительно (-f), вместе с каталогами (-d), включая всё игнорируемое (-x). На практике это сносит:
  • твой .env с паролями и токенами (он же в .gitignore - значит, под -x);
  • локальные конфиги вроде config.local.php, settings.json IDE;
  • node_modules\, vendor\, кэши - это переставится, не страшно;
  • и любые рабочие заметки, которые ты не закоммитил.
И вот тут главная засада, ради которой написана половина этой главы. git clean НЕ кладёт удалённое в stash. Удалённое не уходит в корзину. Его НЕТ в истории Git - оно никогда туда не попадало. Это значит, что обычные спасательные круги Git (reflog, reset, восстановление коммита) тут не работают вообще. Файл физически стёрт с диска. Восстановить можно разве что специальной утилитой восстановления данных файловой системы, и то не факт. По сравнению с git stash, который аккуратно прячет изменения в заначку, clean - это бензопила без тормоза.

Практический совет из реальной жизни: перед любым 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 показывает renamed одной строкой - он понял, что это переименование, а не удаление-плюс-создание. Технически git mv - это просто шорткат для трёх операций: переместить файл на диске, убрать старый путь из индекса, добавить новый. Содержимое (blob) не меняется, меняется только запись в дереве.

Аналогично git rm удаляет отслеживаемый файл И с диска, И из индекса за один заход:

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

$ git rm config/legacy.ini
rm 'config/legacy.ini'
$ git status
Changes to be staged:
  deleted:    config/legacy.ini
Если бы ты просто стёр файл системным rm, Git показал бы его как deleted, но НЕ в индексе - тебе пришлось бы ещё руками сделать git add (или git rm), чтобы зафиксировать удаление. git rm экономит этот шаг.

Грабли: если файл уже изменён или застейджен, 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)
Тут либо -f (форсировать, если правки не нужны), либо разберись с правками сначала.

git rm --cached: убрать из индекса, оставить на диске

Это отдельный, очень частый сценарий, ради которого стоит запомнить флаг --cached. Представь: ты случайно закоммитил .env или огромный бинарник, который должен был быть в .gitignore. Тебе надо вынуть его из Git, но оставить файл на диске - он же нужен для работы.

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

$ git rm --cached .env
rm '.env'
$ git status
Changes to be staged:
  deleted:    .env
Untracked files:
  .env
Смотри, что произошло: Git считает .env удалённым из репозитория (deleted), но при этом файл всплыл в Untracked files - значит, на диске он остался целёхонький. Дальше добавляешь .env в .gitignore, коммитишь - и файл больше не отслеживается, но лежит на месте. Классика для секретов, которые случайно попали под версионный контроль. (Важная оговорка: из ИСТОРИИ файл при этом не исчезает - если в нём были боевые секреты, после такого надо ещё переписать историю через сторонний git filter-repo и ОБЯЗАТЕЛЬНО ротировать утёкшие ключи, потому что в старых коммитах они остаются.)

Для рекурсивного удаления каталога из индекса добавляй -r:

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

$ git rm -r --cached build/
git restore против git checkout: современное разделение

Исторически один git checkout делал слишком много: переключал ветки, восстанавливал файлы, создавал ветки, отвязывал HEAD. Перегруженный комбайн, в котором новички путались - git checkout some_name мог означать и переход на ветку, и затирание файла, в зависимости от того, что за some_name. Поэтому функции разнесли по двум командам: git switch для веток и git restore для файлов. И вот свежий факт на 2026: с Git 2.51 обе команды официально вышли из экспериментального статуса - они СТАБИЛЬНЫ, их интерфейс зафиксирован, можно смело учить и использовать в скриптах.

git restore - это про восстановление содержимого файлов. Базовое: откатить файл в рабочем каталоге к последнему коммиту, выбросив несохранённые правки.

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

$ git restore config.yml
Никакого вывода - молча вернул файл к версии из HEAD. Внимание: твои правки в config.yml при этом ПОТЕРЯНЫ безвозвратно (они же не были в коммите). Это второй после clean источник случайной потери данных, будь аккуратен.

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               # современный
checkout никуда не делся и не устарел формально - в интернете и старых проектах его полно, читать ты его должен уметь. Но для новой работы бери restore и switch: меньше шанс случайно сделать не то, потому что у каждой команды теперь одна понятная зона ответственности.

Типичные грабли
  • 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 отличается от restore.

Контрольные вопросы
  • Почему перед 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 держи только после сухого прогона.
👍2 ❤️3 🔥 😄 🤔
Аватара пользователя
caffeinelurker
Сообщения: 1
Зарегистрирован: 15 май 2026, 18:47

Re: Вспомогательные команды: clean, mv, rm, restore

Сообщение caffeinelurker »

Спасибо за -n, реально вчера чуть не снес .env через clean -fdx из чужого гайда. Теперь сначала сухой прогон всегда.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
nickulus
Сообщения: 1
Зарегистрирован: 20 май 2026, 13:35

Re: Вспомогательные команды: clean, mv, rm, restore

Сообщение nickulus »

А git restore --staged это получается замена git reset HEAD file? Всю жизнь reset набирал, не знал что есть нормальный вариант
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Git LFS и большие файлы
Следующая глава →
Псевдонимы и кастомизация .gitconfig

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

Поделиться темой: ✈ Telegram VK

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

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

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