Git переименовать много файлов и папок - PullRequest
28 голосов
/ 03 апреля 2012

Я пытаюсь переименовать многие файлы в моем приложении, и мне нужно иметь возможность сделать переименование во всех подкаталогах из корня приложения через git (т.е. git mv% filenamematch%% replace%), который заменяет только соответствующий текст. Я не очень хорошо разбираюсь в bash-скриптах.

обновление: было бы хорошо, если бы также были переименованы каталоги, которые также совпадают!

Ответы [ 7 ]

29 голосов
/ 03 апреля 2012

Это должно сработать:

for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); git mv $file $(echo $file | sed -e 's/%filenamematch%/%replacement%/')

Чтобы понять, что это делает, вам нужно понять, что такое "|" и замена команды на "$ (...)". Эти мощные конструкции оболочки позволяют нам комбинировать несколько команд, чтобы получить нужный нам результат. См. Конвейеры и Подстановка команд .

Вот что происходит в этой однострочной:

  1. git ls-files: создает список файлов в репозитории Git. Это похоже на то, что вы можете получить из ls, за исключением того, что выводятся только файлы проекта Git. Начиная с этого списка, вы ничего не трогаете в каталоге .git /.

  2. | grep %filenamematch%: Мы берем список из git ls-files и направляем его через grep, чтобы отфильтровать его до имен файлов, содержащих слово или шаблон, который мы ищем.

  3. | sed -e 's/\(%filenamematch%[^/]*\).*/\1/': Мы передаем эти соответствия через sed (редактор потоков), выполняя (-e) команду sed (substitute) sed, чтобы отрубить любые / и последующие символы после нашего соответствия каталог (если он один).

  4. | uniq: В случаях, когда совпадение является каталогом, теперь, когда мы отрубили содержащиеся каталоги и файлы, может быть много совпадающих строк. Мы используем uniq, чтобы объединить их в одну строку.

  5. for file in ...: команда «для» оболочки будет перебирать все элементы (имена файлов) в списке. Каждое имя файла по очереди присваивается переменной «$ file», а затем выполняется после точки с запятой (;).

  6. sed -e 's/%filenamematch%/%replacement%/': Мы используем echo , чтобы передать каждое имя файла через sed, снова используя его команду замещения - на этот раз для замены шаблона в имени файла.

  7. git mv: Мы используем эту команду git, чтобы перевести существующий файл ($ file) в новое имя файла (измененное с помощью sed).

Один из способов лучше понять это - наблюдать за каждым из этих шагов по отдельности. Для этого запустите приведенные ниже команды в вашей оболочке и просмотрите результат. Все они неразрушающие, только производят списки для вашего наблюдения:

  1. git ls-files

  2. git ls-files | grep %filenamematch%

  3. git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/'

  4. git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq

  5. for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file

  6. for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file | sed -e 's/%filenamematch%/%replacement%/'

14 голосов
/ 11 февраля 2014

Переименуйте файлы с помощью регулярного выражения, используя команду rename:

rename 's/old/new/' *

Затем зарегистрируйте изменения в Git, добавив новые файлы и удалив старые:

git add .
git ls-files -z --deleted | xargs -0 git rm

В более новых версиях Git вы можете использовать флаг --all вместо:

git add --all .
13 голосов
/ 03 апреля 2012

Поздно до вечеринки, но это должно работать в BASH (для файлов и каталогов, но я буду осторожен с каталогами):

find . -name '*foo*' -exec bash -c 'file={}; git mv $file ${file/foo/bar}' \;
5 голосов
/ 03 апреля 2012

git mv внутри оболочки?

Какова цель git-mv?

(Предполагается, что вы находитесь на платформе с разумной оболочкой!)

Опираясь на ответ @ jonathan-camenish :

# 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

3 голосов
/ 19 февраля 2018

Это хорошо сработало для моего варианта использования:

ls folder*/*.css | while read line; do git mv -- $line ${line%.css}.scss; done;

Объяснение:

  • ls folder*/*.css - использует ls, чтобы получить список всех каталогов с файлами CSS, которыесоответствовать шаблону шара.(Каталоги, начинающиеся с folder и содержащие файлы с расширениями .css)
  • 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;
1 голос
/ 31 октября 2014

Я решил это для себя, используя https://github.com/75lb/renamer - отлично сработало :-) Явно не делает git mv, но git, похоже, все равно отлично справился с результатами.

Когда явыполнив все шаги в верхнем ответе, я застрял на последнем шаге, когда моя консоль ответила

for pipe quote>

Если кто-нибудь сможет это объяснить, я буду признателен!

0 голосов
/ 03 апреля 2012

Я обычно использую NetBeans для такого рода вещей, потому что я избегаю командной строки, когда есть более простой способ. NetBeans имеет некоторую поддержку git, и вы можете использовать его в произвольном каталоге / файле через вкладку «Избранное».

...