Як визначити, чи обробляє Git файл як двійковий чи як текст?


78

Я знаю, що Git якось автоматично визначає, чи є файл двійковим або текстовим, і за допомогою цього .gitattributesможна вручну встановити це, якщо потрібно. Але чи є спосіб запитати Git, як він поводиться з файлом?

Отже, скажімо, у мене є сховище Git з двома файлами: ascii.datФайл, що містить звичайний текст, і binary.datфайл, що містить випадкові двійкові файли. Git обробляє перший .datфайл як текст, а вторинний - як двійковий. Тепер я хочу написати інтерфейсний інтерфейс Git, в якому є переглядач текстових файлів та спеціальний переглядач двійкових файлів (наприклад, відображення шістнадцяткового дампа). Звичайно, я міг би здійснити власну перевірку тексту / двійкового файлу, але було б корисніше, якщо програма перегляду покладається на інформацію про те, як Git обробляє ці файли.

Отже, як я можу запитати Git, якщо він обробляє файл як текстовий чи двійковий?

Відповіді:


40

builtin_diff()1 дзвінки, diff_filespec_is_binary()що викликає, buffer_is_binary()який перевіряє наявність будь-якого нульового байта ("символ" NUL) у перших 8000 байтах (або на всю довжину, якщо коротша).

Я не бачу, що це "це двійковий файл?" test явно виставляється в будь-якій команді.

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, тому ми просто перевіряємо це.


1 builtin_diff() має такі рядки, Binary files %s and %s differякі повинні бути знайомими.


1
На cygwin (Windows) / dev / null не існує. Потрібно використовувати магію SHA1, яку виховував Сет. git diff --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD -- "$1".
koppor

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

поверне імена файлів, які git інтерпретує як текстові файли.

Ви можете використовувати символи підстановки, наприклад

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

Працює з пізнішими версіями, але з git 1.7.5.4 це просто дає вираз fatal: empty (sub) . Зміна регулярного виразу на -e .роботу з цією версією (можливо, ціною неправильного визначення текстових файлів, що складаються виключно з порожніх рядків!).
Джон Маршалл,

Дуже сподобався цей простий спосіб тестування файлу. Дякую!
Eugene Sajine

Я змінив його на, -e .щоб бути більш сумісним, і додав --untrackedдля роботи з ширшим колом файлів.
eckes

19

Мені не подобається ця відповідь, але ви можете проаналізувати результат 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
[…]

Так, і до речі, 4b825d ... чарівний ША , яка представляє собою порожній дерево (воно є Ша для порожнього дерева, але мерзотник спеціально знає про цю магії).


2
Дякую, добрий сер. Я використовував git diff-tree --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEADякий має - - filenameформат.
Джон Гітцен,

2
Якщо вам потрібен список усіх двійкових файлів у вашому репо, ви можете це зробитиgit diff --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD -- | grep "^-" | cut -f 3
bonh

1
Сет, будь ласка, виправте друкарську помилку в останньому реченні, має бути 4b82 5 д; ТАК не дозволить мені подати односимвольну редакцію.
chrisinmtown

0

Ризикуючи отримати шльопання за низьку якість коду, я перелічую утиліту 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: /programming/14002954/c-programming-how-to-read-the-whole-file-contents-into-a-buffer */

/* From: /programming/1563882/reading-a-file-name-from-piped-command */

/* From: /programming/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 */
}

-10

Ви можете використовувати утиліту "файл" інструменту командного рядка. У Windows він входить до інсталяції git і зазвичай знаходиться в папці C: \ Program Files \ git \ usr \ bin

file --mime-encoding *

Докладніше див. У розділі Отримати кодування файлу в Windows


11
Я не той, хто проголосував за нього, але це, без сумніву, було проти, оскільки 'файл' не має нічого спільного з тим, як git визначає тип файлу. 'file' не використовує git-код, а git не використовує команду 'file'. Наприклад, "файл" не знає нічого про те, як файл .gitattributes допомагає git визначити тип файлу.
Джим Раден,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.