Ajouter récursivement des fichiers par motif

172

Comment ajouter récursivement des fichiers par un modèle (ou glob) situé dans différents répertoires?

Par exemple, je voudrais ajouter A/B/C/foo.javaet D/E/F/bar.java(et plusieurs autres fichiers java) avec une seule commande:

git add '*.java'

Malheureusement, cela ne fonctionne pas comme prévu.

Michel Krämer
la source
2
Cela fonctionne pour moi (Mac OS X, Git 1.7.1+). Quelle version d'OS et de Git utilisez-vous?
Chris Johnsen
3
Si vous avez des .javafichiers (déjà suivis) dans votre répertoire actuel, vous êtes peut-être en train de rencontrer le traitement des caractères génériques, euh , compliqué entre bash et le «helper» de ligne de commande msys . Je ne suis pas sûr d’une solution. Vous pouvez essayer plusieurs couches de guillemets: git add '"*.java"'(les guillemets simples sont pris par bash pour empêcher l'expansion de glob, les guillemets doubles sont pris par la couche msys pour empêcher l'expansion de glob).
Chris Johnsen
1
Merci pour la note. Malheureusement, cela ne fonctionne pas non plus. Ils disent que le a été corrigé, mais j'ai déjà la dernière version.
Michel Krämer
1
git add *.javafonctionne pour moi (sur PowerShell avec le client GitHub)
ThaDafinser

Réponses:

89

La réponse de Sergio Acosta est probablement votre meilleur pari si certains des fichiers à ajouter ne sont peut-être pas déjà suivis. Si vous voulez vous limiter aux fichiers que git connaît déjà, vous pouvez combiner git-ls-filesavec un filtre:

git ls-files [path] | grep '\.java$' | xargs git add

Git ne fournit aucun mécanisme sophistiqué pour le faire lui-même, car il s'agit essentiellement d'un problème de shell: comment obtenir une liste de fichiers à fournir comme arguments à une commande donnée.

Cascabel
la source
8
Merci! J'ai légèrement amélioré votre commande et maintenant il fait ce que je cherchais:git ls-files -co --exclude-standard | grep '\.java$' | xargs git add
Michel Krämer
169

Vous pouvez utiliser git add [path]/\*.javapour ajouter des fichiers java à partir de sous-répertoires,
par exemple git add ./\*.javapour le répertoire courant.

De la git adddocumentation :

Ajoute le contenu de tous les *.txtfichiers sous le Documentationrépertoire et ses sous-répertoires:

$ git add Documentation/\*.txt

Notez que l'astérisque *est cité du shell dans cet exemple; cela permet à la commande d'inclure les fichiers des sous-répertoires du Documentation/répertoire.

Sergey Glotov
la source
2
@ MichelKrämer probablement pas, mais c'est maintenant.
Alberto
7
C'est la meilleure solution, fonctionne également dans Windows.
TheTFo
1
"l'astérisque * est cité du shell". Je pense que vous voulez dire "échappé". Dans tous les cas, la barre oblique inverse empêche la coque de l'étendre.
gwideman
1
@gwideman Je pense que vous avez raison, mais ce n'est pas moi. C'est une citation de la documentation git-scm.com/docs/git-add#_examples
Sergey Glotov
62

Avec zshvous pouvez exécuter:

git add "**/*.java"

et tous vos *.javafichiers seront ajoutés de manière récursive.

Olivier Verdier
la source
Merci pour cela, mais je travaille avec msysgit sur Windows et il n'a qu'une bash.
Michel Krämer
1
Eh bien, je vois qu'il existe un zshshell pour Windows ... vous vous ferez une faveur pour l'utiliser au lieu de bash, à mon humble avis.
Olivier Verdier
1
Le port Windows de zsh est basé sur une version très ancienne et plante tout le temps (par exemple lorsque j'entre ls).
Michel Krämer
Wow, parfait. Je ne connaissais pas cette fonctionnalité!
Tomáš Votruba
1
Cela n'a rien à voir avec zsh. Je pense que cette réponse manque le point que vous voulez passer le chemin avec des caractères génériques intacts à git et laisser git le traiter. Vous voulez donc empêcher le shell que vous utilisez d'étendre le (s) caractère (s) générique (s). Pour ce faire, vous devez le citer d'une manière appropriée pour le shell que vous utilisez. Voir les autres réponses pour plus de détails.
gwideman
55

Un peu hors sujet (pas spécifiquement lié à git) mais si vous êtes sous Linux / Unix, une solution de contournement pourrait être:

find . -name '*.java' | xargs git add

Et si vous attendez des chemins avec des espaces:

find . -name '*.java' -print0 | xargs -0 git add

Mais je sais que ce n'est pas exactement ce que vous avez demandé.

Sergio Acosta
la source
6
Problème mineur avec cette approche - si vous "trouvez" un fichier correspondant à votre .gitignore, alors git se plaint que vous essayez d'ajouter un fichier que vous lui avez dit d'ignorer.
yoyo
2
@yoyo - Je viens d'ajouter -f à la fin, et cela a corrigé ça
Maslow
5
@Maslow, cela ajoutera de force le fichier, même s'il était censé être ignoré (basé sur .gitignore). Je préfère obtenir la plainte et ne pas ajouter le fichier (qui est le comportement par défaut.)
yoyo
En quoi est-ce mieux que de laisser git effectuer l'extension générique?
gwideman
12

La réponse de Sergey (ne me créditez pas) fonctionne:

You can use git add [path]/\*.java

avec un git récent:

$git version
git version 1.7.3.4

Fichiers pour le test:

$find -name .git -prune -o -type f -print | sort
./dirA/dirA-1/dirA-1-1/file1.txt
./dirA/dirA-1/dirA-1-2/file2.html
./dirA/dirA-1/dirA-1-2/file3.txt
./dirA/dirA-1/file4.txt
./dirB/dirB-1/dirB-1-1/file5.html
./dirB/dirB-1/dirB-1-1/file6.txt
./file7.txt

Statut Git:

$git status -s
?? dirA/
?? dirB/
?? file7.txt

Ajout de * .txt:

$git add \*.txt

Statut mis à jour:

$git status -s
A  dirA/dirA-1/dirA-1-1/file1.txt
A  dirA/dirA-1/dirA-1-2/file3.txt
A  dirA/dirA-1/file4.txt
A  dirB/dirB-1/dirB-1-1/file6.txt
A  file7.txt
?? dirA/dirA-1/dirA-1-2/file2.html
?? dirB/dirB-1/dirB-1-1/file5.html
Alberto
la source
8

Si vous suivez déjà vos fichiers et que vous y avez apporté des modifications et que vous souhaitez maintenant les ajouter de manière sélective en fonction d'un modèle, vous pouvez utiliser l' --modifiedindicateur

git ls-files --modified | grep '<pattern>' | xargs git add

Par exemple, si vous souhaitez uniquement ajouter les modifications CSS à ce commit, vous pouvez faire

git ls-files --modified | grep '\.css$' | xargs git add

Voir man git-ls-filespour plus de drapeaux

RAM
la source
5

Utilisez simplement git add *\*.java. Cela ajoutera tous les fichiers .java dans le répertoire racine et tous les sous-répertoires.

Jan Lovstrand
la source
Très bonne réponse. J'ai fait git add * / pom.xml pour ajouter tous les noms de fichiers pom.xml.
Philip Rego
4

Ajout d'une solution de ligne de commande Windows qui n'a pas encore été mentionnée:

for /f "delims=" %G in ('dir /b/s *.java') do @git add %G
selalerer
la source
3

Je voulais uniquement ajouter des fichiers qui avaient une certaine chaîne basée sur git status:

git status | grep string | xargs git add

puis a pu git commit -m 'commit msgvalider tous les fichiers modifiés avec "chaîne" dans le titre du fichier

bdanin
la source
2

Comme mentionné dans " git: Comment puis-je ajouter de manière récursive tous les fichiers dans un sous-arbre de répertoire qui correspondent à un modèle de glob? ", Si vous échappez ou citez correctement votre globbing de pathspec (comme'*.java' ), alors oui, git add'*.java'

Git 2.13 (Q2 2017) améliore cela pour l'ajout interactif:

Voir commit 7288e12 (14 mars 2017) par Jeff King ( peff) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit 153e0d7 , 17 mars 2017)

add --interactive: ne développez pas les pathspecs avec ls-files

Lorsque nous voulons obtenir la liste des fichiers modifiés, nous développons d'abord toutes les indications de chemin fournies par l'utilisateur avec " ls-files", puis nous alimentons la liste de chemins résultante en arguments pour " diff-index" et " diff-files".
Si votre pathspec se développe en un grand nombre de chemins, vous pouvez rencontrer l'un des deux problèmes suivants:

  1. Le système d'exploitation peut se plaindre de la taille de la liste d'arguments et refuser de s'exécuter. Par exemple:

    $ (ulimit -s 128 && git add -p drivers)
    Can't exec "git": Argument list too long at .../git-add--interactive line 177.
    Died at .../git-add--interactive line 177.
    

C'est sur le linux.gitréférentiel, qui contient environ 20K fichiers dans le répertoire "drivers" (aucun d'entre eux n'a été modifié dans ce cas). L' ulimit -sastuce " " est nécessaire pour montrer le problème sous Linux même pour un ensemble de chemins aussi gigantesque.
D'autres systèmes d'exploitation ont des limites beaucoup plus petites (par exemple, un cas réel a été vu avec seulement des fichiers 5K sur OS X).

  1. Même quand ça marche, c'est vraiment lent. Le code pathspec n'est pas optimisé pour un grand nombre de chemins. Voici le même cas sans l'ulimit:

    $ time git add -p drivers
      No changes.
    
    real  0m16.559s
    user    0m53.140s
    sys 0m0.220s
    

Nous pouvons améliorer cela en ignorant ls-filescomplètement " ", et en alimentant simplement les pathspecs d'origine aux commandes diff.

Historiquement, le langage pathspec pris en charge par " diff-index" était plus faible, mais ce n'est plus le cas.

VonC
la source
1

mettre la ligne dans ~ / .gitconfig

[alias] addt = !sh -c 'git ls-files | grep \"\\.$1*\" | xargs git add' -

Si vous souhaitez ajouter tous les fichiers java modifiés, vous pouvez simplement faire: git addt java

Samely, si vous souhaitez ajouter tous les fichiers python modifiés, vous pouvez simplement faire: git addt py

Hong Emrys
la source