2011-05-25 20 views
55

Sé que GIT de alguna manera detecta automáticamente si un archivo es binario o de texto y que se pueden usar gitattributes para configurarlo manualmente si es necesario. ¿Pero también hay una manera de preguntarle a GIT cómo trata un archivo?¿Cómo se determina si Git maneja un archivo como binario o como texto?

Así que vamos a decir que tengo un repositorio GIT con dos archivos en ella: Un archivo ascii.dat que contiene texto plano y un archivo que contiene binary.dat cosas binaria aleatoria. Git maneja el primer archivo dat como texto y el archivo secundario como binario. Ahora quiero escribir un GIT webfrontend que tenga un visor para archivos de texto y un visor especial para archivos binarios (mostrando un volcado hexadecimal, por ejemplo). Claro, podría implementar mi propia verificación de texto/binario, pero sería más útil si el espectador confía en la información sobre cómo maneja GIT estos archivos.

Entonces, ¿cómo puedo preguntarle a GIT si trata un archivo como texto o binario?

Respuesta

27

builtin_diff() llama diff_filespec_is_binary() que llama buffer_is_binary() que comprueba para cualquier ocurrencia de un byte cero (“carácter” NUL) en los primeros 8000 bytes (o toda la longitud si más corto).

No veo que esta prueba "¿es binaria?" Está explícitamente expuesta en cualquier comando.

git merge-file utiliza directamente buffer_is_binary(), por lo que puede ser capaz de hacer uso de ella:

git merge-file /dev/null /dev/null file-to-test 

Se parece producir el mensaje de error como error: Cannot merge binary files: file-to-test y produce un estado de salida 255 cuando se le da un archivo binario. Sin embargo, no estoy seguro de que quiera confiar en este comportamiento.

Tal git diff --numstat sería más fiable:

isBinary() { 
    p=$(printf '%s\t-\t' -) 
    t=$(git diff --no-index --numstat /dev/null "$1") 
    case "$t" in "$p"*) return 0 ;; esac 
    return 1 
} 
isBinary file-to-test && echo binary || echo not binary 

Para los archivos binarios, la salida --numstat debe comenzar con - TAB TAB -, por lo que sólo la prueba de eso.


builtin_diff() tiene cadenas como Binary files %s and %s differ que deben estar familiarizados.

+1

En cygwin (Windows),/dev/null no existe. Uno tiene que usar la magia SHA1 criada por Seth. 'git diff --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD -" $ 1 "'. – koppor

17

No me agrada esta respuesta, pero puede analizar la salida de git-diff-tree para ver si es binaria. Por ejemplo:

git diff-tree -p 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD -- MegaCli 
diff --git a/megaraid/MegaCli b/megaraid/MegaCli 
new file mode 100755 
index 0000000..7f0e997 
Binary files /dev/null and b/megaraid/MegaCli differ 

en contraposición a:

git diff-tree -p 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD -- megamgr 
diff --git a/megaraid/megamgr b/megaraid/megamgr 
new file mode 100755 
index 0000000..50fd8a1 
--- /dev/null 
+++ b/megaraid/megamgr 
@@ -0,0 +1,78 @@ 
+#!/bin/sh 
[…] 

Ah, y por cierto, 4b825d ... es un SHA mágico que representa el árbol vacío (es el SHA de un árbol vacío, pero git es especialmente consciente de esta magia).

+2

Gracias, buen señor. Usé 'git diff-tree --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD' que tiene el formato' - - filename '. –

+2

Si quiere una lista de todos los archivos binarios en su repositorio, puede hacer 'git diff --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD - | grep "^ -" | corte -f 3' – bonh

+1

Seth por favor corrija el error tipográfico en la última oración, debe ser 4b82 ** 5 ** d; SO no me permite enviar una edición de 1 carácter. – chrisinmtown

23
git grep -I --name-only --untracked -e . -- ascii.dat binary.dat ... 

devolverá los nombres de los archivos que git interpreta como archivos de texto.

Puede usar comodines, p.

git grep -I --name-only --untracked -e . -- *.ps1 
+0

Funciona con versiones posteriores, pero con git 1.7.5.4 esto simplemente da _fatal: empty (sub) expression_. Cambiar la expresión regular a '-e .' funciona con esta versión (¡quizás a costa de identificar erróneamente archivos de texto que consisten únicamente en líneas vacías!). –

+0

Me gustó esa manera simple de probar el archivo mucho. ¡Gracias! –

+0

Lo cambié al '-e .' para ser más compatible y agregué' --untracked' para trabajar con una gama más amplia de archivos. – eckes

-3

Puede utilizar la herramienta de línea de comandos 'archivo' utilidad. En Windows se incluye en la instalación Git y normalmente se encuentra en en la carpeta C: \ Archivos de programa \ git \ usr \ bin

file --mime-encoding * 

Ver más en Get encoding of a file in Windows

+1

¿Por qué downvote sin explicación qué pasa? –

+2

No soy el que lo votó negativamente, pero fue downvoted sin duda porque 'archivo' no tiene nada que ver con cómo git determina el tipo de archivo. 'archivo' no usa código git, y git no usa el comando 'archivo'. 'archivo', por ejemplo, no sabe nada sobre cómo el archivo .gitattributes ayuda a determinar el tipo de archivo. –

0

En el riesgo de ser golpeado por la pobre calidad del código, Estoy enumerando una utilidad C, is_binary, construida en torno a la rutina buffer_is_binary() original en la fuente de Git. Por favor, vea los comentarios internos sobre cómo construir y ejecutar. Fácilmente modificable:

/*********************************************************** 
* is_binary.c 
* 
* Usage: is_binary <pathname> 
* Returns a 1 if a binary; return a 0 if non-binary 
* 
* Thanks to Git and Stackoverflow developers for helping with these routines: 
* - the buffer_is_binary() routine from the xdiff-interface.c module 
* in git source code. 
* - the read-a-filename-from-stdin route 
* - the read-a-file-into-memory (fill_buffer()) routine 
* 
* To build: 
* % gcc is_binary.c -o is_binary 
* 
* To build debuggable (to push a few messages to stdout): 
* % gcc -DDEBUG=1 ./is_binary.c -o is_binary 
* 
* BUGS: 
* Doesn't work with piped input, like 
* % cat foo.tar | is_binary 
* Claims that zero input is binary. Actually, 
* what should it be? 
* 
* Revision 1.4 
* 
* Tue Sep 12 09:01:33 EDT 2017 
***********************************************************/ 
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 

#define MAX_PATH_LENGTH 200 
#define FIRST_FEW_BYTES 8000 

/* global, unfortunately */ 
char *source_blob_buffer; 

/* From: https://stackoverflow.com/questions/14002954/c-programming-how-to-read-the-whole-file-contents-into-a-buffer */ 

/* From: https://stackoverflow.com/questions/1563882/reading-a-file-name-from-piped-command */ 

/* From: https://stackoverflow.com/questions/6119956/how-to-determine-if-git-handles-a-file-as-binary-or-as-text 
*/ 

/* The key routine in this function is from libc: void *memchr(const void *s, int c, size_t n); */ 
/* Checks for any occurrence of a zero byte (NUL character) in the first 8000 bytes (or the entire length if shorter). */ 

int buffer_is_binary(const char *ptr, unsigned long size) 
{ 
    if (FIRST_FEW_BYTES < size) 
    size = FIRST_FEW_BYTES; 
    /* printf("buff = %s.\n", ptr); */ 
    return !!memchr(ptr, 0, size); 
} 
int fill_buffer(FILE * file_object_pointer) { 
    fseek(file_object_pointer, 0, SEEK_END); 
    long fsize = ftell(file_object_pointer); 
    fseek(file_object_pointer, 0, SEEK_SET); //same as rewind(f); 
    source_blob_buffer = malloc(fsize + 1); 
    fread(source_blob_buffer, fsize, 1, file_object_pointer); 
    fclose(file_object_pointer); 
    source_blob_buffer[fsize] = 0; 
    return (fsize + 1); 
} 
int main(int argc, char *argv[]) { 

    char pathname[MAX_PATH_LENGTH]; 
    FILE *file_object_pointer; 

    if (argc == 1) { 
    file_object_pointer = stdin; 
    } else { 
    strcpy(pathname,argv[1]); 
#ifdef DEBUG 
    printf("pathname=%s.\n", pathname); 
#endif 
    file_object_pointer = fopen (pathname, "rb"); 
    if (file_object_pointer == NULL) { 
     printf ("I'm sorry, Dave, I can't do that--"); 
     printf ("open the file '%s', that is.\n", pathname); 
     exit(3); 
    } 
    } 
    if (!file_object_pointer) { 
    printf("Not a file nor a pipe--sorry.\n"); 
    exit (4); 
    } 
    int fsize = fill_buffer(file_object_pointer); 
    int result = buffer_is_binary(source_blob_buffer, fsize - 2); 

#ifdef DEBUG 
    if (result == 1) { 
    printf ("%s %d\n", pathname, fsize - 1); 
    } 
    else { 
    printf ("File '%s' is NON-BINARY; size is %d bytes.\n", pathname, fsize - 1); 
    } 
#endif 
    exit(result); 
    /* easy check -- 'echo $?' after running */ 
} 
Cuestiones relacionadas