Git diff --name-only y copia esa lista

151

Solo quiero obtener una lista de archivos modificados entre dos revisiones, que es simple:

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

Pero, ¿qué debo escribir si quiero copiar todos los archivos enumerados en otro lugar? Y necesito una estructura de directorios completamente idéntica para los archivos copiados.

Por ejemplo, he modificado y agregado archivos:

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

Quiero tener en /home/changes/todos esos archivos modificados y agregados:

/home/changes/protected/texts/file1.txt
/home/changes/protected/scripts/index.php
/home/changes/public/pics/pic1.png
BazZy
fuente
1
no entiendo lo que estás tratando de lograr ... ¿propagando cambios a diferentes clones? creando parches? parchar archivos fuera de un repositorio git?
knittl
No es un parche, sino una estructura de copia exacta de los archivos modificados. Como parche, pero con archivos sólidos
BazZy
Y sí, parchear archivos fuera repositorio git - objetivo más cercano para mí :)
Bazzy
3
lo siento. ¿QUÉ? ¿Desea capturar y reproducir cambios en archivos y cambios en árboles? Eso es un parche. git format-patchpuede hacer esto para los rangos de confirmación.
knittl
1
git diff commit1 commit2 > my.patchy luego cd other/path; patch -p1 < my.patch. ¿Por qué tiene que hacerse con copias completas de los archivos? Si es porque cree que el parche podría no aplicarse, y por lo tanto el otro directorio no está realmente en el commit1estado, que realmente debería copiar todo desde el commit2estado ...
Cascabel

Respuestas:

118

Pruebe el siguiente comando, que he probado:

$ cp -pv --parents $(git diff --name-only) DESTINATION-DIRECTORY
York
fuente
2
Gracias por la cp --parentspista, ¡he querido esa opción durante años y nunca supe que existía! .. obviamente nunca me molesté en buscarlo tampoco = \
Stephan Henningsen
2
Tenga en cuenta que esto no funciona en Mac, ya que la --parentsopción de cpno está disponible.
M. Justin
¿Algún consejo sobre cómo usar esto si los archivos tienen caracteres inusuales? Espacio en blanco, caracteres nórdicos.
Halvor Holsten Strand
@HalvorStrand, no lo he probado, pero la configuración IFS=$'\n'primero puede hacerlo. (Preferiblemente en un subshell para no alterar su valor IFS original)
Comodín
Recibo un error cp: cannot stat 'git diff --name-only': No such file or directoryen git bash en windows. ¿Qué estoy haciendo mal? El directorio de destino existe
Shiva
14

Lo siguiente debería funcionar bien:

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

Para explicar más a fondo:

  • El -za con git diff --name-onlysignifica generar la lista de archivos separados con bytes NUL en lugar de líneas nuevas, en caso de que sus nombres de archivo tengan caracteres inusuales.

  • El -0to xargsdice que interprete la entrada estándar como una lista de parámetros separados por NUL.

  • El -IREPLACEes necesario ya que por defecto xargsagregaría los parámetros al final del rsynccomando. En cambio, eso dice ponerlos donde está el último REPLACE. (Ese es un buen consejo de esta respuesta de Falla del servidor ).

  • El -aparámetro a rsyncsignifica preservar permisos, propiedad, etc. si es posible. Los -Rmedios para utilizar la ruta relativa completa al crear los archivos en el destino.

Actualización: si tiene una versión anterior de xargs, deberá usar la -iopción en lugar de -I. (El primero está en desuso en versiones posteriores de findutils).

Mark Longair
fuente
Eso es extraño: ¿qué sistema operativo estás usando? Si es una distribución de Linux, ¿cuál y qué xargs --versiondice?
Mark Longair
1
Ah, en esa versión de xargs debe usar -ien su lugar, que está en desuso en versiones posteriores: 4.1 es bastante antiguo ahora. Actualizaré mi respuesta.
Mark Longair
@ Mark: Recuerdo haber leído en alguna parte que necesitas un espacio después -Ien algunas versiones, así que tal vez prueba en su -I REPLACElugar.
Mikel
No importa. Eso tampoco funciona. -Isolo se admite desde findutils4.2.10, lanzado en diciembre de 2004.
Mikel
Debe agregar --diff-filter=dpara excluir archivos eliminados de la lista. De lo contrario, obtendrá errores al intentar copiarlos en la carpeta de cambios. De lo contrario, gran respuesta. ¡Gracias!
taymless
11

Aquí hay una frase:

Enumere los archivos modificados y empaquételos como * .zip:

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

Enumere los últimos archivos modificados confirmados y empaquételos como * .zip:

git diff --name-only HEAD~ HEAD | zip patched.zip -@
Kolypto
fuente
Si está utilizando Windows, puede descargar zip de la línea de comandos desde sourceforge.net/projects/gnuwin32/files/zip
Radon8472
@ Radon8472 Que se instala sed.exe? Todavía zipno me encuentro en Windows.
Shiva
no, el enlace apunta a la descarga de zip.exe no para sed. Si no puede usar zip en la línea de comandos, debe agregar la carpeta donde está instalado zip.exe a su PATHvariable env.
Radon8472
6
zip update.zip $(git diff --name-only commit commit)
marca
fuente
2

Funciona perfectamente

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

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

Nadie ha mencionado cpiocuál es fácil de escribir, crea enlaces duros y maneja espacios en los nombres de archivo:

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