Как определить, обрабатывает ли файл Git файл как двоичный или текстовый?
Я знаю, что Git каким-то образом автоматически определяет, является ли файл двоичным или текстовым, и что .gitattributes
можно использовать для установки этого вручную, если это необходимо. Но есть ли способ спросить Git, как он обрабатывает файл?
Допустим, у меня есть репозиторий Git с двумя файлами: файл ascii.dat
, содержащий простой текст, и файл binary.dat
, содержащий случайные двоичные файлы. Git обрабатывает первый файл .dat
как текст, а вторичный файл - как двоичный. Теперь я хочу написать веб-интерфейс Git, в котором есть средство просмотра текстовых файлов и специальное средство просмотра двоичных файлов (например, отображение шестнадцатеричного дампа). Конечно, я мог бы реализовать свою собственную проверку текста/двоичного кода, но было бы более полезно, если бы зритель полагался на информацию о том, как Git обрабатывает эти файлы.
Итак, как я могу спросить Git, обрабатывает ли он файл как текстовый или двоичный?
Ответы
Ответ 1
builtin_diff()
1 вызывает diff_filespec_is_binary()
, который вызывает buffer_is_binary()
, который проверяет любое вхождение нулевого байта (символ NUL ") в первые 8000 байт (или всю длину, если короче).
Я не вижу, что это "он бинарный?" тест явно отображается в любой команде.
git merge-file
использует buffer_is_binary()
, поэтому вы можете использовать его:
git merge-file /dev/null /dev/null file-to-test
Кажется, что появляется сообщение об ошибке, подобное error: Cannot merge binary files: file-to-test
, и дает статус выхода 255 при двоичном файле. Я не уверен, что хотел бы полагаться на это поведение.
Может быть, git diff --numstat
будет более надежным:
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
Для двоичных файлов вывод --numstat
должен начинаться с -
TAB -
TAB, поэтому мы просто проверяем это.
1builtin_diff()
имеет строки типа Binary files %s and %s differ
, которые должны быть знакомы.
Ответ 2
git grep -I --name-only --untracked -e . -- ascii.dat binary.dat ...
вернет имена файлов, которые git интерпретирует как текстовые файлы.
Вы можете использовать подстановочные знаки, например.
git grep -I --name-only --untracked -e . -- *.ps1
Ответ 3
Мне не нравится этот ответ, но вы можете разобрать вывод git -diff-tree, чтобы узнать, является ли он двоичным. Например:
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
в отличие от:
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
[…]
О, и BTW, 4b825d... - это волшебная SHA, которая представляет пустое дерево (это SHA для пустого дерева, но git специально знает об этой магии).
Ответ 4
Из-за риска получить пощечину за плохое качество кода, я перечисляю утилиту C, is_binary, построенную вокруг исходной функции buffer_is_binary() в источнике Git. Пожалуйста, ознакомьтесь с внутренними комментариями о том, как создавать и запускать. Легко изменяемый:
/***********************************************************
* 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 */
}
Ответ 5
Вы можете использовать утилиту командной строки командной строки. В Windows он включен в установку git и обычно находится в папке C:\Program Files\git\usr\bin
file --mime-encoding *
Подробнее в Получить кодировку файла в Windows