Git이 파일을 바이너리 또는 텍스트로 처리하는지 확인하는 방법은 무엇입니까?


78

Git은 파일이 바이너리인지 텍스트인지 자동으로 감지하고 .gitattributes필요한 경우 수동으로 설정하는 데 사용할 수 있다는 것을 알고 있습니다. 그러나 Git이 파일을 어떻게 처리하는지 물어 보는 방법도 있습니까?

그래서 두 개의 파일이있는 Git 저장소가 있다고 가정 해 봅시다 : ascii.dat일반 텍스트를 binary.dat포함 하는 파일 과 임의의 바이너리를 포함 하는 파일. Git은 첫 번째 .dat파일을 텍스트로, 보조 파일을 바이너리로 처리합니다. 이제 텍스트 파일 용 뷰어와 바이너리 파일 용 특수 뷰어 (예 : 16 진수 덤프 표시)가있는 Git 웹 프런트 엔드를 작성하고 싶습니다. 물론 내 자신의 텍스트 / 이진 검사를 구현할 수 있지만 뷰어가 Git이 이러한 파일을 처리하는 방법에 대한 정보에 의존하는 경우 더 유용 할 것입니다.

그렇다면 파일을 텍스트로 처리하는지 바이너리로 처리하는지 Git에게 어떻게 물어볼 수 있습니까?

답변:


40

builtin_diff()1 은 처음 8000 바이트 (또는 더 짧은 경우 전체 길이)에서 0 바이트 (NUL "문자")가 발생하는지 확인 diff_filespec_is_binary()하는 호출 을 호출 buffer_is_binary()합니다.

나는 이것이 "이진법인가?"라는 것을 알지 못한다. 테스트는 모든 명령에서 명시 적으로 노출됩니다.

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이 존재하지 않습니다. 하나는 Seth가 만든 마법 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) expression을 제공 합니다. 정규식을 -e .이 버전 에서 작동 하도록 변경합니다 (빈 줄로만 구성된 텍스트 파일을 잘못 식별하는 대신).
John Marshall

파일을 테스트하는 간단한 방법을 많이 좋아했습니다. 감사!
Eugene Sajine 2015

-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
[…]

아, 그리고 BTW, 4b825d는 ... 빈 트리 (가 나타내는 마법의 SHA는 이다 빈 나무에 대한 SHA하지만 자식이 마법의 특별 알고있다).


2
감사합니다. 내가 사용 git diff-tree --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD이있는 - - filename형식을.
John Gietzen 2011 년

2
저장소에있는 모든 바이너리 파일 목록을 원한다면 할 수 있습니다git diff --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD -- | grep "^-" | cut -f 3
bonh

1
Seth는 마지막 문장에서 오타를 수정하십시오 . 4b82 5 d 여야합니다 . 그래서 한글자 편집을 제출하지 않을 것입니다.
chrisinmtown

0

열악한 코드 품질로 인해 충돌 할 위험이 있으므로 Git 소스의 원래 buffer_is_binary () 루틴을 기반으로 빌드 된 C 유틸리티 is_binary를 나열합니다. 빌드 및 실행 방법은 내부 의견을 참조하십시오. 쉽게 수정 가능 :

/***********************************************************
 * 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
나는 그것을 반대표를 던진 사람이 아니지만 'file'이 git이 파일 유형을 결정하는 방법과 관련이 없기 때문에 의심의 여지가 없습니다. 'file'은 git 코드를 사용하지 않고 git은 'file'명령을 사용하지 않습니다. 예를 들어 'file'은 .gitattributes 파일이 git이 파일 유형을 결정하는 데 어떻게 도움이되는지에 대해 아무것도 모릅니다.
Jim Raden
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.