Git diff --name-only e copie essa lista

151

Eu só quero obter uma lista de arquivos alterados entre duas revisões, o que é simples:

git diff -–name-only commit1 commit2 > /path/to/my/file

Mas, o que devo escrever se quiser copiar todos os arquivos listados para outro local? E eu preciso de uma estrutura de diretório completamente idêntica para arquivos copiados.

Por exemplo, eu modifiquei e adicionei arquivos:

/protected/texts/file1.txt
/protected/scripts/index.php
/public/pics/pic1.png

Eu quero ter em /home/changes/todos os arquivos alterados e adicionados:

/home/changes/protected/texts/file1.txt
/home/changes/protected/scripts/index.php
/home/changes/public/pics/pic1.png
BazZy
fonte
1
não entendo bem o que você está tentando alcançar ... propagando alterações em diferentes clones? criando patches? patching de arquivos fora de um repositório git?
knittl
Não é patch, mas a estrutura exata da cópia dos arquivos alterados. Como patch, mas com arquivos sólidos
Bazzy
E sim, remendar arquivos fora do repositório git - alvo mais próximo para mim :)
Bazzy
3
Desculpe. QUE? Deseja capturar e reproduzir alterações em arquivos e alterações em árvores? isso é um patch. git format-patchpode fazer isso para intervalos de confirmação.
knittl
1
git diff commit1 commit2 > my.patche depois cd other/path; patch -p1 < my.patch. Por que isso precisa ser feito com cópias completas dos arquivos? Se é porque você acha que o patch pode não se aplicar, e, portanto, o outro diretório não está realmente no commit1estado, você realmente deveria copiar tudo do commit2estado ...
Cascabel

Respostas:

118

Tente o seguinte comando, que eu testei:

$ cp -pv --parents $(git diff --name-only) DESTINATION-DIRECTORY
Iorque
fonte
2
Obrigado pela cp --parentsdica, eu queria essa opção há anos e nunca soube que ela existia! ..obviamente, eu nunca me preocupei em procurá-lo também = \
Stephan Henningsen
2
Observe que isso não funciona no Mac, pois a --parentsopção de cpnão está disponível.
237 Justin
Alguma dica sobre como usar isso se os arquivos tiverem caracteres incomuns? Espaço em branco, caracteres nórdicos.
Halvor Holsten Strand
@ HalvorStrand, eu não testei, mas a configuração IFS=$'\n'primeiro pode fazê-lo. (De preferência em um subnível de modo a não atrapalhar o seu valor IFS original).
Wildcard
Estou recebendo um erro cp: cannot stat 'git diff --name-only': No such file or directoryno git bash no Windows. O que estou fazendo de errado? Diretório de destino existe
Shiva
14

O seguinte deve funcionar bem:

git diff -z --name-only commit1 commit2 | xargs -0 -IREPLACE rsync -aR REPLACE /home/changes/protected/

Para explicar mais:

  • O -zto com git diff --name-onlysignifica produzir a lista de arquivos separados por bytes NUL em vez de novas linhas, apenas no caso de seus nomes de arquivos terem caracteres incomuns.

  • O -0to xargsdiz para interpretar a entrada padrão como uma lista de parâmetros separados por NUL.

  • A -IREPLACEé necessária uma vez por padrão xargsiria acrescentar os parâmetros para o final do rsynccomando. Em vez disso, diz para colocá-los onde mais tarde REPLACEestiver. (Essa é uma boa dica desta resposta de falha no servidor .)

  • O -aparâmetro para rsyncsignifica preservar permissões, propriedade etc., se possível. Os -Rmeios para usar o caminho relativo completo ao criar os arquivos no destino.

Atualização: se você possui uma versão antiga xargs, precisará usar a -iopção em vez de -I. (O primeiro foi descontinuado em versões posteriores do findutils.)

Mark Longair
fonte
Isso é estranho - qual sistema operacional você está usando? Se é uma distribuição Linux, qual e o que xargs --versiondiz?
precisa saber é o seguinte
1
Ah, nessa versão do xargs você precisa usar -i, o que é preterido nas versões posteriores - o 4.1 é bastante antigo agora. Vou atualizar minha resposta.
precisa saber é o seguinte
@ Mark: Lembro-me de ler em algum lugar que você precisa de um espaço depois -Iem algumas versões, então talvez tente -I REPLACE.
Mikel
Deixa pra lá. Isso também não funciona. -Ié suportado apenas desde findutils4.2.10, lançado em dezembro de 2004.
Mikel
Você deve adicionar --diff-filter=dpara excluir arquivos excluídos da lista. Caso contrário, você receberá erros ao tentar copiá-los para a pasta de alterações. Caso contrário, ótima resposta. Obrigado!
taymless
11

Aqui está uma frase:

Listar arquivos alterados e compactá-los como * .zip:

git diff --name-only | zip patched.zip -@

Listar os últimos arquivos alterados confirmados e compactá-los como * .zip:

git diff --name-only HEAD~ HEAD | zip patched.zip -@
Kolypto
fonte
Se você estiver usando o Windows você pode baixar zip comando de sourceforge.net/projects/gnuwin32/files/zip
Radon8472
@ Radon8472 Isso instala sed.exe? Ainda zipnão estou sendo encontrado no Windows.
Shiva
não, o link está apontando para o download do zip.exe e não do sed. Se você não pode usar o zip na linha de comando, adicione a pasta em que o zip.exe está instalado na sua PATHvariável env.
Radon8472
6
zip update.zip $(git diff --name-only commit commit)
Marca
fonte
2

Funciona perfeitamente.

git diff 1526043 82a4f7d --name-only | xargs zip update.zip

git diff 1526043 82a4f7d --name-only |xargs -n 10 zip update.zip
knight2016
fonte
1

Ninguém mencionou o cpioque é fácil de digitar, cria links físicos e manipula espaços nos nomes de arquivos:

git diff --name-only $from..$to  | cpio -pld outdir
hexten
fonte