¿Puedo usar git diff en archivos sin seguimiento?

270

¿Es posible pedirle a git diff que incluya archivos sin seguimiento en su salida diff? ¿O es mi mejor apuesta para agregar los nuevos archivos que he creado y los archivos existentes que he editado y usar

git diff --cached

?

Andrew Grimm
fuente

Respuestas:

267

Con las versiones recientes de git puede git add -Nel archivo (o --intent-to-add), que agrega un blob de longitud cero al índice en esa ubicación. El resultado es que su archivo "sin seguimiento" ahora se convierte en una modificación para agregar todo el contenido a este archivo de longitud cero, y eso se muestra en la salida "git diff".

git diff

echo "this is a new file" > new.txt
git diff

git add -N new.txt
git diff
diff --git a/new.txt b/new.txt
index e69de29..3b2aed8 100644
--- a/new.txt
+++ b/new.txt
@@ -0,0 +1 @@
+this is a new file

Lamentablemente, como se señaló, no puede git stashmientras tenga un --intent-to-addarchivo pendiente como este. Aunque si necesita guardar, simplemente agregue los nuevos archivos y luego los guarde. O puede usar la solución de emulación:

git update-index --add --cacheinfo \
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt

(configurar un alias es tu amigo aquí).

araqnid
fuente
Resulta que mi copia de Git no es lo suficientemente reciente como para agregar -N, pero esto responde a mi pregunta.
Andrew Grimm
1
Puede emular "git add -N new.txt" con "git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt" (¿cómo logré poner esto en la respuesta incorrecta?)
araqnid
Característica agregada en 1.6.1: github.com/git/git/blob/master/Documentation/RelNotes/1.6.1.txt
MarcH
1
¿Qué pasa si tiene muchos archivos nuevos? ¿Hay alguna manera fácil de agregarlos todos y luego diferenciarlos?
Vic
1
@Vicgit add -N .
Nathan
92

Creo que puede diferenciar los archivos en su índice y los archivos no rastreados simplemente proporcionando la ruta a ambos archivos.

git diff --no-index tracked_file untracked_file
Harold
fuente
3
¿Funciona si tiene más de un archivo sin seguimiento que ha creado desde la última confirmación?
Andrew Grimm
12
Sí, respuesta perfecta! Entonces puedo usar git diff --no-index untracked_file_1 untracked_file_2para obtener git diffcolores de sintaxis, etc. en diffs ... hermoso.
Colin D Bennett
40
No entiendo por qué estás comparando un archivo rastreado con un archivo no rastreado no relacionado. Si sólo quería conseguir dif salida para el archivo sin seguimiento, sólo puede utilizar /dev/nullen su lugar: git diff --no-index -- /dev/null <untracked_file>.
44
O simplemente cat untracked_file_1, o tal vez printf '\e[1;32m%s\e[0m\n' "$(cat untracked_file_1)"si realmente necesita una salida verde. :) (Aunque en una nota más seria, tenga en cuenta que la sustitución de comandos eliminará las nuevas líneas finales de su archivo.)
Comodín
8
Esta debería ser la respuesta aceptada: no requiere cambiar el índice de git; que, como dice el autor original, tiene su lado negativo
DIMMSum
38

Para mi git interactivo del día a día (donde difiero el árbol de trabajo contra el HEAD todo el tiempo, y me gustaría tener archivos sin seguimiento incluidos en el diff), add -N/--intent-to-addes inutilizable, porque se rompe git stash .

Así que aquí está mi git diffreemplazo. No es una solución particularmente limpia, pero como realmente solo la uso de forma interactiva, estoy de acuerdo con un truco:

d() {
    if test "$#" = 0; then
        (
            git diff --color
            git ls-files --others --exclude-standard |
                while read -r i; do git diff --color -- /dev/null "$i"; done
        ) | `git config --get core.pager`
    else
        git diff "$@"
    fi
}

Escribir solo dincluirá archivos no rastreados en el diff (que es lo que me importa en mi flujo de trabajo), y d args...se comportará como siempre git diff.

Notas:

  • Aquí estamos usando el hecho de que solo se git difftrata de diferencias individuales concatenadas, por lo que no es posible distinguir el dresultado de un "diferencial real", excepto por el hecho de que todos los archivos no rastreados se ordenan al final.
  • El único problema con esta función es que la salida se colorea incluso cuando se redirige; pero no me molesto en agregar lógica para eso.
  • No pude encontrar ninguna manera de obtener archivos sin seguimiento incluidos simplemente compilando una lista de argumentos ingeniosa para git diff. Si alguien descubre cómo hacer esto, o si tal vez se agrega una función giten algún momento en el futuro, ¡deje una nota aquí!
Jo Liss
fuente
44
Irónicamente, mi git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txtsolución sugerí para GITS de edad avanzada hace el trabajo con git stash, suponiendo que ya tienes e69de29bb en su base de datos, por ejemplo, al tratar de utilizar add -Npreviamente. Entonces, aparentemente no es exactamente equivalente de git add -Nalguna manera: tbh, no estoy seguro de cómo.
araqnid
2
Por testcierto, está realizando una comparación de cadenas en lugar de una verificación de igualdad numérica con su comando. No debería afectar nada, pero test "$#" -eq 0es más precisamente lo que se pretende.
Comodín el
1
Sí, todavía parece que necesita hacerlo por pares ... pero puede simularlo en uno lesspara que no tenga que presionar qpara cada archivo y se siente exactamente así git diff, al eliminar la paginación por archivo ( -P), y luego volver a agregarlo ( | less), preservando el color ( --color=always) e interpretándolo como color ( less -ro less -R). En total, es:do git -P diff --color=always -- /dev/null "$i"; done | less -r
hyperpallium
En caso de que desee ser molestado en el futuro, test -t 1(por ejemplo, if [ -t 1 ]; then color_arg=--color; fio algo así) es una forma para que el shell compruebe si su salida es un terminal, que es una forma útil de decidir el color. Y xargspodría dar una manera de deshacerse del ciclo while. No obstante, deberá -n 1en el que, por lo que va siendo lanzamiento GIT un montón de veces, y todavía tienen que ser parejas de esa manera, pero ... se deshace de whiley read, lo que tal vez es mejor?!? Eso se lo dejo al lector.
Lindes
28

No es 100% al punto, pero si por alguna razón no desea agregar sus archivos al índice como lo sugiere la respuesta aceptada, aquí hay otra opción:

Si los archivos no se rastrean, obviamente, el diff es el archivo completo, por lo que puede verlos con menos:

less $(git ls-files --others --exclude-standard)

Navegue entre ellos con :ny :ppara el siguiente y el anterior.

Actualización de los comentarios: si necesita un formato de parche, también puede combinarlo con git diff:

git ls-files --others --exclude-standard | xargs -n 1 git --no-pager diff /dev/null | less

También puede redirigir la salida a un archivo o usar otro comando diff en este caso.

usuario1587520
fuente
66
también puede ejecutar git diff /dev/null <untracked_tile>y obtener el parche en formato de parche en lugar de "solo" un archivo
SimSimY
2
Esta respuesta combinada con git diff es la solución perfecta.
iwind
22
git add -A
git diff HEAD

Genere un parche si es necesario y luego:

git reset HEAD
Amol Pujari
fuente
Esto tiene el potencial de perder (pre) trabajo previo, al agregar todo. Especialmente el caso si se usa con git add -pmucha frecuencia (lo que generalmente recomiendo, por cierto) ... Esto da una forma de hacer lo básico, solo ... debe tenerse en cuenta que tiene el potencial de un lado no deseado efectos
Lindes
13

esto funciona para mi:

git add my_file.txt
git diff --cached my_file.txt
git reset my_file.txt

El último paso es opcional, dejará el archivo en el estado anterior (sin seguimiento)

útil si también está creando un parche:

  git diff --cached my_file.txt > my_file-patch.patch
Alejandro Moreno
fuente
La especificidad de este par agregar / restablecer es un buen contraste con el enfoque de escopeta de stackoverflow.com/a/50486906/313756 ... gracias por eso.
lindes
9

Los cambios funcionan cuando se realiza y no se realiza con este comando. Los archivos nuevos funcionan cuando se organizan:

$ git diff HEAD

Si no están organizados, solo verá diferencias de archivos.

alairock
fuente
26
HEADes el valor predeterminado , por lo que es el mismo git diffque no resuelve el problema.
Iulian Onofrei
44
Esto requiere git addde cada archivo no rastreado
SilvioQ
Si edita esta respuesta para incluirla git add, es la más simple si su caso de uso es verificar lo que acaba de agregar / desea agregar
KCD
8

Para un archivo:

git diff --no-index /dev/null new_file

Para todos los archivos nuevos:

for next in $( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null $next; done;

Como alias:

alias gdnew="for next in \$( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null \$next; done;"

Para todos los archivos modificados y nuevos combinados como un comando:

{ git --no-pager diff; gdnew }
radzimir
fuente
2

Por lo general, cuando trabajo con equipos de ubicación remota, es importante para mí que tenga conocimiento previo de los cambios realizados por otros equipos en el mismo archivo, antes de seguir las etapas de git desanudar -> por etapas -> comprometerme para eso escribí un script bash que ayúdame a evitar una resolución innecesaria fusionar conflictos con el equipo remoto o hacer una nueva sucursal local y comparar y fusionar en la sucursal principal

#set -x 
branchname=`git branch | grep -F '*' |  awk '{print $2}'`
echo $branchname
git fetch origin ${branchname}
for file in `git status | grep "modified" | awk "{print $2}" `
do
echo "PLEASE CHECK OUT GIT DIFF FOR "$file 
git difftool FETCH_HEAD $file ;
done

en la secuencia de comandos anterior, busco la rama principal remota (no es necesariamente su rama maestra) para FETCH_HEAD hacer una lista de mi archivo modificado solo y comparar archivos modificados con git difftool

Aquí hay muchas herramientas compatibles con git, configuro 'Meld Diff Viewer' para una buena comparación de GUI.

adg
fuente
-9

Asumiendo que no tiene confirmaciones locales,

git diff origin/master
Pradhan
fuente
8
La pregunta solicita un git diffcomando que incluya archivos sin seguimiento. Este comando no los incluye. Además, si existen compromisos locales o no tiene absolutamente nada que ver con la pregunta.
toon81
JFTR, I git merge --squash mybranch, y git diff masterme mostró los cambios en los archivos sin seguimiento.
muammar
2
Eso es imposible. Parece estar confundido acerca de lo que significa "sin seguimiento". Sin seguimiento no significa que un archivo se rastrea en una rama y no en otra, significa que no está "en Git" en ninguna parte de ninguna manera. Si aplastas o no, no hay diferencia. git diffno muestra diferencias en los archivos no rastreados: debido a que no están rastreados, nunca hay diferencias para mostrar, por definición. Así es como funciona Git. :)
toon81