Git переименовать много файлов и папок
Я пытаюсь переименовать много файлов в моем приложении и должен иметь возможность выполнять переименование во всех подкаталогах из корня приложения через git (т.е. git mv% filenamematch%% replacement%), который заменяет только соответствующий текст. Я не умею работать с bash скриптами.
update: было бы хорошо, если бы они также переименовали каталоги, которые также совпадают!
Ответы
Ответ 1
Это должно сделать трюк:
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); git mv $file $(echo $file | sed -e 's/%filenamematch%/%replacement%/')
Чтобы следить за тем, что это делает, вам нужно понять, что трубопровод с "|" и подстановку команд с помощью "$ (...)". Эти мощные конструкции оболочки позволяют нам комбинировать несколько команд, чтобы получить нужный нам результат. См. Pipelines и Замена команд.
Вот что происходит в этом однострочном слое:
-
git ls-files
: создает список файлов в репозитории Git. Это похоже на то, что вы можете получить из ls
, за исключением того, что он выводит только файлы проекта Git. Исход из этого списка гарантирует, что ничего в вашем каталоге .git/не коснется.
-
| grep %filenamematch%
: Мы берем список из git ls-files
и обрабатываем его через grep, чтобы отфильтровать его только на имена файлов, содержащие искомое слово или шаблон.
-
| sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
: Мы прокладываем эти соответствия через sed (редактор потока), выполняем (-e) sed s (substitute), чтобы вырезать любые/и последующие символы после нашего соответствующего каталога (если это будет один).
-
| uniq
: В тех случаях, когда совпадение является каталогом, теперь, когда мы отрубили каталоги и файлы, может быть много совпадающих строк. Мы используем uniq, чтобы сделать их всех в одну строку.
-
for file in ...
: Оболочка "для" команды будет перебирать все элементы (имена файлов) в списке. Каждое имя файла, в свою очередь, присваивает переменной "$ file", а затем выполняет команду после точки с запятой (;).
-
sed -e 's/%filenamematch%/%replacement%/'
: Мы используем echo, чтобы передать каждое имя файла через sed, снова используя команду substitute - на этот раз для выполнения нашей замены шаблона в имени файла.
-
git mv
: Мы используем эту команду Git для mv существующего файла ($ file) для нового имени файла (тот, который был изменен sed).
Одним из способов понять это лучше было бы наблюдать каждый из этих шагов изолированно. Для этого запустите команды ниже в своей оболочке и посмотрите результат. Все они являются неразрушающими, только производя списки для вашего наблюдения:
-
git ls-files
-
git ls-files | grep %filenamematch%
-
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
-
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq
-
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file
-
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file | sed -e 's/%filenamematch%/%replacement%/'
Ответ 2
Переименуйте файлы с помощью регулярного выражения с помощью команды rename
:
rename 's/old/new/' *
Затем зарегистрируйте изменения с помощью Git, добавив новые файлы и удалив старые:
git add .
git ls-files -z --deleted | xargs -0 git rm
В новых версиях Git вместо этого можно использовать флаг --all
:
git add --all .
Ответ 3
Поздно к участнику, но это должно работать в BASH (для файлов и каталогов, но я буду осторожен относительно каталогов):
find . -name '*foo*' -exec bash -c 'file={}; git mv $file ${file/foo/bar}' \;
Ответ 4
git mv
внутри оболочки оболочки?
Какова цель git-mv?
(Предполагая, что вы находитесь на платформе с разумной оболочкой!)
Опираясь на ответ @Джонатан-Камениш:
# things between backticks are 'subshell' commands. I like the $() spelling over ''
# git ls-files -> lists the files tracked by git, one per line
# | grep somestring -> pipes (i.e., "|") that list through a filter
# '|' connects the output of one command to the input of the next
# leading to: for file in some_filtered_list
# git mv f1 f2 -> renames the file, and informs git of the move.
# here 'f2' is constructed as the result of a subshell command
# based on the sed command you listed earlier.
for file in 'git ls-files | grep filenamematch'; do git mv $file 'echo $file | sed -e 's/%filenamematch%/%replacement%/''; done
Вот более длинный пример (в bash или аналогичный)
mkdir blah; cd blah;
touch old_{f1,f2,f3,f4} same_{f1,f2,f3}
git init && git add old_* same_* && git commit -m "first commit"
for file in $(git ls-files | grep old); do git mv $file $(echo $file | sed -e 's/old/new/'); done
git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# renamed: old_f1 -> new_f1
# renamed: old_f2 -> new_f2
# renamed: old_f3 -> new_f3
# renamed: old_f4 -> new_f4
#
см. также: Специальный анализ данных из командной строки Unix
Ответ 5
Это хорошо сработало для моего варианта использования:
ls folder*/*.css | while read line; do git mv -- $line ${line%.css}.scss; done;
Объяснение:
-
ls folder*/*.css
- использует ls
для получения списка всех каталогов с файлами CSS, которые соответствуют шаблону glob. (Каталоги, начинающиеся с folder
и содержащие файлы с расширениями .css
) -
while read line
- while read line
чтение в результирующем выводе команды ls
-
do git mv -- $line ${line%.css}.css
- Выполнить git mv
для построчного вывода (переменная $line
содержит каждую строку), сопоставляя начало каждого имени файла и исключая расширение .css
( с ${line%
и добавлением нового расширения .scss
(--
используется для предотвращения неоднозначности между именами файлов и флагами)
Код ниже может быть использован для "пробного запуска" (на самом деле git mv
не будет выполняться):
ls variant*/*.css | while read line; do echo git mv $line to ${line%.css}.scss; done;
Ответ 6
Я решил это для себя, используя
https://github.com/75lb/renamer - отлично работал:-)
Явно не делаю git mv
, но git, похоже, все равно имеет дело с результатами.
Когда я выполнил все шаги в верхнем ответе, я застрял на последнем шаге, когда моя консоль ответила
for pipe quote>
Если кто-нибудь сможет это объяснить, я буду признателен!
Ответ 7
Обычно я использую NetBeans для создания такого типа вещей, потому что я избегаю командной строки, когда есть более простой способ. NetBeans поддерживает некоторую поддержку git, и вы можете использовать его в произвольном каталоге/файле через вкладку "Избранное".