git renommer de nombreux fichiers et dossiers

j'essaie de renommer de nombreux fichiers dans mon application et j'ai besoin de pouvoir faire un renommage dans tous les sous-répertoires à partir de l'app root via git (i.e. git mv %filenamematch% %% replacement%) qui ne remplace que le texte correspondant. Je ne suis pas doué pour les scripts de bash.

mise à jour: ce serait bien si les répertoires renommés qui correspondent aussi!

22
demandé sur fasked 2012-04-03 02:29:21

7 réponses

Cela devrait faire l'affaire:

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

pour suivre ce que cela fait, vous aurez besoin de comprendre la tuyauterie avec " | "et la substitution de commande avec" $(...)". Ces puissantes constructions shell nous permettent de combiner plusieurs commandes pour obtenir le résultat dont nous avons besoin. Voir Pipelines et substitution de commande .

voici ce qui se passe dans cette doublure:

  1. git ls-files : cela produit une liste de fichiers dans le dépôt Git. Il est similaire à ce que vous pourriez obtenir de ls , sauf qu'il ne produit que des fichiers de projet Git. À partir de cette liste assure que rien dans votre .git / directory est touché.

  2. | grep %filenamematch% : nous prenons la liste de git ls-files et la pipons à travers grep pour la filtrer vers le bas à seulement les noms de fichier contenant le mot ou le motif que nous cherchons.

  3. | sed -e 's/\(%filenamematch%[^/]*\).*//' : nous pipons ces correspondances à travers sed (l'éditeur de flux), en exécutant la commande (-e) sed pour couper n'importe quel / et les caractères suivants après notre répertoire correspondant (si c'est un).

  4. | uniq : dans les cas où la correspondance est un répertoire, maintenant que nous avons coupé les répertoires et les fichiers contenus, il pourrait y avoir beaucoup de correspondance ligne. Nous utilisons uniq pour les faire tous en une seule ligne.

  5. for file in ... : le shell "pour" commande va itérer tous les éléments (noms de fichiers) dans la liste. Chaque nom de fichier à son tour, il assigne à la variable "$file" puis exécute la commande après le point-virgule (;).

  6. sed -e 's/%filenamematch%/%replacement%/' : nous utilisons echo pour pipe chaque nom de fichier à travers sed, utiliser à nouveau la commande de remplacement--cette fois pour effectuer le remplacement de notre motif sur le nom du fichier.

  7. git mv : nous utilisons cette commande git pour mv le fichier existant ($file) vers le nouveau nom de fichier (celui modifié par sed).

Une façon de comprendre mieux ce serait d'observer chacune de ces étapes dans l'isolement. Pour ce faire, exécutez les commandes ci-dessous dans votre coquille, et observez le résultat. Tout ce sont des listes non destructives, ne produisant que pour votre observation:

  1. git ls-files

  2. git ls-files | grep %filenamematch%

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

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

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

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

24
répondu Jonathan Camenisch 2012-04-12 13:20:25

la Fin de la partie, mais, cela devrait fonctionner dans BASH (pour les fichiers et les répertoires, mais je préfère être prudent au sujet de répertoires):

find . -name '*foo*' -exec bash -c 'file={}; git mv $file ${file/foo/bar}' \;
12
répondu GoZoner 2015-08-15 01:26:44

renommer les fichiers avec une expression régulière en utilisant la commande rename :

rename 's/old/new/' *

puis enregistrez les modifications avec Git en ajoutant les nouveaux fichiers et en supprimant les anciens:

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

dans les versions plus récentes de Git, vous pouvez utiliser le drapeau --all à la place:

git add --all .
9
répondu Flimm 2015-10-07 16:13:12

git mv dans une boucle shell?

Quel est le but de git-mv?

(en Supposant que vous êtes sur une plate-forme, avec une coquille!)

en S'appuyant sur @jonathan-camenish: # (quelqu'un peut-il éditer ce lien?)

# 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

voici un exemple plus long (en bash ou similaire)

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
#

voir: http://en.wikibooks.org/wiki/Ad_Hoc_Data_Analysis_From_The_Unix_Command_Line /

5
répondu Gregg Lind 2017-05-23 11:54:16

j'ai résolu cela pour moi - même en utilisant https://github.com/75lb/renamer - a fonctionné parfaitement :-) Ne fait pas explicitement un git mv mais git semblait traiter les résultats parfaitement de toute façon.

quand j'ai suivi toutes les étapes de la réponse du haut, j'ai été bloqué à l'étape finale, quand ma console a répondu avec

for pipe quote>

si quelqu'un peut expliquer cela, je l'apprécierais!

1
répondu samjewell 2014-10-31 11:33:09

j'utilise habituellement NetBeans pour faire ce genre de choses parce que j'évite la ligne de commande quand il y a un moyen plus facile. NetBeans a un certain support pour git, et vous pouvez l'utiliser sur les répertoires/fichiers arbitraires via l'onglet "Favoris".

0
répondu Vincent 2012-04-02 22:36:45

Cela a bien fonctionné pour mon cas d'utilisation:

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

explication:

  • ls folder*/*.css - utilise ls pour obtenir une liste de tous les répertoires avec des fichiers CSS qui correspondent au motif glob. (Répertoires commençant par folder et contenant des fichiers avec .css extensions)
  • while read line - lecture dans la sortie résultante du ls ligne de commande-par-ligne
  • do git mv -- $line ${line%.css}.css - exécuter git mv sur la sortie ligne par ligne (la variable $line contient chaque ligne) tout en respectant le début de chaque nom de fichier et en excluant l'extension .css (avec ${line% et en ajoutant une nouvelle extension .scss ( -- est utilisé pour éviter l'ambiguïté entre les noms de fichiers et les drapeaux)

le Code ci-dessous peut être utilisé pour un "dry run" (n'exécutera pas réellement git mv ):

ls variant*/*.css | while read line; do echo git mv $line to ${line%.css}.scss; done;
0
répondu Alex W 2018-02-19 16:03:27