Adicionar recursivamente arquivos por padrão

172

Como adiciono recursivamente arquivos por um padrão (ou glob) localizado em diretórios diferentes?

Por exemplo, eu gostaria de adicionar A/B/C/foo.javae D/E/F/bar.java(e vários outros arquivos java) com um comando:

git add '*.java'

Infelizmente, isso não funciona como o esperado.

Michel Krämer
fonte
2
Funciona para mim (Mac OS X, Git 1.7.1+). Qual versão do SO e Git você está usando?
Chris Johnsen
3
Se você possui alguns .javaarquivos (já rastreados) em seu diretório atual, pode estar enfrentando uma manipulação complicada , er, de curinga entre o bash e o "auxiliar" da linha de comando do msys . Não tenho certeza sobre uma solução. Você pode tentar várias camadas de aspas: git add '"*.java"'(as aspas simples são usadas pelo bash para impedir a expansão da glob, as aspas duplas são tomadas pela camada msys para impedir a expansão da glob).
Chris Johnsen
1
Obrigado pela observação. Infelizmente, isso também não funciona. Eles dizem que o foi corrigido, mas eu já tenho a versão mais recente.
Michel Krämer
1
git add *.javafunciona para mim (em powershell com o cliente GitHub)
ThaDafinser

Respostas:

89

A resposta de Sergio Acosta é provavelmente a sua melhor aposta, se alguns dos arquivos a serem adicionados ainda não estiverem rastreados. Se você deseja limitar-se aos arquivos que o git já conhece, você pode combinar git-ls-filescom um filtro:

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

O Git não fornece mecanismos sofisticados para fazer isso sozinho, pois é basicamente um problema de shell: como você obtém uma lista de arquivos para fornecer como argumentos para um determinado comando.

Cascabel
fonte
8
Obrigado! Eu melhorei um pouco o seu comando e agora está fazendo o que estava procurando:git ls-files -co --exclude-standard | grep '\.java$' | xargs git add
Michel Krämer
169

Você pode usar git add [path]/\*.javapara adicionar arquivos java de subdiretórios,
por exemplo , git add ./\*.javapara o diretório atual.

Da git adddocumentação :

Adiciona conteúdo de todos os *.txtarquivos no Documentationdiretório e seus subdiretórios:

$ git add Documentation/\*.txt

Observe que o asterisco *é citado no shell neste exemplo; isso permite que o comando inclua os arquivos dos subdiretórios do Documentation/diretório

Sergey Glotov
fonte
2
@ MichelKrämer provavelmente não era, mas é agora.
Alberto
7
Esta é a melhor solução, funciona no Windows também.
TheTFo
1
msgstr "asterisco * é citado do shell". Eu acho que você quer dizer "escapou". Em qualquer caso, a barra invertida impede que o shell a expanda.
gwideman
1
@gwideman Acho que você está certo, mas não sou eu. É citação dos documentos git-scm.com/docs/git-add#_examples
Sergey Glotov
62

Com zshvocê pode executar:

git add "**/*.java"

e todos os seus *.javaarquivos serão adicionados recursivamente.

Olivier Verdier
fonte
Obrigado por isso, mas estou trabalhando com o msysgit no Windows e ele tem apenas um bash.
Michel Krämer
1
Bem, vejo que existe um zshshell para o Windows ... você fará um favor a si mesmo em usá-lo em vez de bash, imho.
Olivier Verdier
1
A porta do zsh para Windows é baseada em uma versão muito antiga e trava o tempo todo (por exemplo, quando eu entro ls).
Michel Krämer
Uau, perfeito. Eu não sabia sobre esse recurso!
Tomáš Votruba
1
Isso não tem nada a ver com zsh. Eu acho que essa resposta perde o ponto que você deseja percorrer o caminho com curingas intactos para git e deixar o git processá-lo. Portanto, você deseja impedir que o shell que você está usando expanda os caracteres curinga. Para fazer isso, é necessário citá-lo de alguma maneira apropriada para o shell que você está usando. Veja outras respostas para obter detalhes.
gwideman
55

Um tópico pouco interessante (não especificamente relacionado ao git), mas se você estiver no linux / unix, uma solução alternativa pode ser:

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

E se você espera caminhos com espaços:

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

Mas eu sei que não é exatamente o que você pediu.

Sergio Acosta
fonte
6
Problema menor com essa abordagem - se você "encontrar" um arquivo correspondente ao seu .gitignore, o git reclamará que você está tentando adicionar um arquivo que você pediu para ignorar.
yoyo
2
@yoyo - Acabei de adicionar -f na extremidade, e que fixa que
Maslow
5
@ Maslow, que adicionará à força o arquivo, mesmo que ele devesse ser ignorado (com base em .gitignore). Eu prefiro para obter a queixa e não adicionar o arquivo (que é o comportamento padrão.)
yoyo
Como isso é melhor do que deixar o git executar a expansão de curinga?
gwideman
12

A resposta de Sergey (não me credite) está funcionando:

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

com um git recente:

$git version
git version 1.7.3.4

Arquivos para o teste:

$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

Status do Git:

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

Adicionando * .txt:

$git add \*.txt

Status atualizado:

$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
fonte
8

Se você já está acompanhando seus arquivos e fez alterações neles, e agora deseja adicioná-los seletivamente com base em um padrão, pode usar o --modifiedsinalizador

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

Por exemplo, se você deseja adicionar apenas as alterações de CSS a esse commit, você pode fazer

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

Veja man git-ls-filespara mais sinalizadores

RAM
fonte
5

Apenas use git add *\*.java. Isso adicionará todos os arquivos .java no diretório raiz e todos os subdiretórios.

Jan Lovstrand
fonte
Ótima resposta. Git add * / pom.xml para adicionar todos os nomes de arquivos pom.xml.
Philip Rego
4

Adicionando uma solução de linha de comando do Windows que ainda não foi mencionada:

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

Eu queria adicionar apenas arquivos que tivessem uma determinada string com base em git status:

git status | grep string | xargs git add

e, em seguida, conseguiu git commit -m 'commit msgconfirmar todos os arquivos alterados com "string" no título do arquivo

bdanin
fonte
2

Como mencionado em " git: como adiciono recursivamente todos os arquivos em uma subárvore de diretório que correspondem a um padrão glob? ", Se você escapar ou citar corretamente o pathspec globbing (como'*.java' ), sim, git add'*.java'

O Git 2.13 (Q2 2017) melhora isso para adicionar interativo:

Veja commit 7288e12 (14 de março de 2017) por Jeff King ( peff) .
(Mesclado por Junio ​​C Hamano - gitster- na confirmação 153e0d7 , 17 de março de 2017)

add --interactive: não expanda pathspecs com ls-files

Quando queremos obter a lista de arquivos modificados, primeiro expandimos os códigos de caminho fornecidos pelo usuário com " ls-files" e, em seguida, alimentamos a lista resultante de caminhos como argumentos para " diff-index" e " diff-files".
Se o seu pathspec se expandir para um grande número de caminhos, você poderá encontrar um dos dois problemas:

  1. O sistema operacional pode reclamar do tamanho da lista de argumentos e se recusar a executar. Por exemplo:

    $ (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.
    

Está no linux.gitrepositório, que possui cerca de 20K arquivos no diretório "drivers" (nenhum deles modificado neste caso). O ulimit -struque " " é necessário para mostrar o problema no Linux, mesmo para um conjunto tão grande de caminhos.
Outros sistemas operacionais têm limites muito menores (por exemplo, um caso do mundo real foi visto com apenas 5K arquivos no OS X).

  1. Mesmo quando funciona, é muito lento. O código do pathspec não é otimizado para um grande número de caminhos. Aqui está o mesmo caso sem o ulimit:

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

Nós podemos melhorar isso pulando " ls-files" completamente, e apenas alimentando o pathspecs original aos comandos diff.

Historicamente, a linguagem pathspec suportada por " diff-index" era mais fraca, mas esse não é mais o caso.

VonC
fonte
1

colocar linha em ~ / .gitconfig

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

Se você deseja adicionar todos os arquivos java modificados, basta: git addt java

Da mesma forma, se você deseja adicionar todos os arquivos python modificados, basta: git addt py

Hong Emrys
fonte