Как заменить текст во многих файлах сразу — и не сломать папку .git

В интернете полно такого рецепта: grep -rl oldName . | xargs sed -i 's/oldName/newName/g'. Выглядит невинно. Я запустил его в маленьком репозитории, где один файл называется oldName.js:
$ grep -rl oldName . | xargs sed -i 's/oldName/newName/g'
$ git status --short
D src/newName.js
?? src/oldName.js
Файл никто не переименовывал. Но git теперь уверен, что newName.js удалён, а oldName.js появился из ниоткуда. Команда залезла в служебный файл .git/index и переписала имя внутри него.
Ниже — порядок, в котором такое не случается.
Сначала проще: замена в редакторе
Если заменить надо один раз, тебе, скорее всего, хватит редактора. В VS Code это Ctrl+Shift+H (на Mac — Cmd+Shift+H). Он сам пропускает .git и node_modules, а все правки показывает до применения.
Терминал нужен, когда замену надо повторить, вставить в скрипт или отдать агенту. Тогда идём по шагам.
Пошаговая замена в терминале
-
Зафиксируй текущее состояние. Git станет твоей кнопкой отмены. Посмотри
git status: незакоммиченных правок быть не должно.$ git status --short $ git add src/app.js && git commit -m "before rename" -
Посмотри, что зацепит замена. Команда
git grepищет только по файлам под контролем git, поэтому.gitиnode_modulesдля неё не существуют. Флаг-wозначает «целое слово».$ git grep -nw oldNameПрочитай список. Это дешевле, чем потом разбираться. Если задача пока только найти нужное место, вот подробнее про поиск кода в большом проекте.
-
Замени. Этот вариант работает и на Linux, и на macOS, и не боится пробелов в именах файлов:
$ git grep -lzw oldName | xargs -0 perl -pi -e 's/\boldName\b/newName/g'Тут
git grep -lвыдаёт только имена файлов,-zразделяет их нулевым байтом, аxargs -0этот разделитель понимает.\b— граница слова:oldNameListостанется целым. -
Проверь результат. Это самый важный шаг. Смотри на сводку и на сам дифф:
$ git diff --stat src/a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git diff $ git grep -c oldNameСравни число файлов с тем, что видел на шаге 2. Последняя команда должна показать только то, что ты оставил намеренно.
-
Прогони тесты и закоммить. Не понравилось? Отмена одной командой, и ничего не потеряно:
$ git restore src/a.js
Что получится
Замена затронет только файлы проекта и только целые слова. Папка .git останется нетронутой. Перед коммитом ты увидишь каждую правку, а откат занимает секунду.
Получится повторяемая команда, которую можно сохранить в заметках или вставить в скрипт.
Почему не sed
На Linux сработает и короткая форма: git grep -lw oldName | xargs sed -i 's/\boldName\b/newName/g'. Но на macOS тебя ждут два сюрприза.
- В macOS стоит другой
sed. Ему после-iнужен отдельный аргумент:sed -i ''. Без него он примет твоё выражение за расширение бэкапа и выдастinvalid command code. \bэтотsedне понимает, так что слово не будет считаться словом.
Поэтому perl проще: одна команда на обеих системах.
Ещё две ловушки шаблона, общие для обоих:
- Слэши в тексте. Для замены URL смени разделитель:
s#http://old#https://new#g. Иначе придётся экранировать каждый/. - Точка — любой символ.
v1.2найдёт иv1x2. Пишиv1\.2.
Когда замена текстом — плохая идея
Текстовая замена не понимает код. Она поменяет слово в строках, комментариях и в чужом классе с таким же именем.
Для переименования функции или переменной лучше подходит команда редактора Rename Symbol (F2). Она знает, где этот символ на самом деле используется. А perl оставь для текста: ссылок, конфигов, старого названия продукта.
То же самое при работе с агентом. Не пиши «замени везде». Лучше так:
Найди все вхождения слова oldName через git grep и покажи список. Замени только целые слова, только в src/. Не трогай node_modules и .git. После замены покажи git diff --stat и запусти тесты.
Агент сделает те же шаги, а ты увидишь результат каждого.
Как заменить кириллицу?
Добавь флаги для UTF-8: perl -CSD -Mutf8 -pi -e 's/\bстарый\b/новый/g'. Без них \b не считает русские буквы словом, и команда ничего не найдёт.
А если нужно поменять имена файлов, а не текст?
Это другая задача и другой риск: два файла могут получить одно имя. Смотри как переименовать много файлов сразу.
Что делать в Windows?
Проще всего — замена в VS Code. Для командной строки поставь Git Bash, и команды выше заработают почти без изменений.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





