2011-05-25 66 views
55

我知道GIT以某種方式自動檢測文件是二進制還是文本,並且如果需要,可以使用gitattributes來手動設置。但是,還有一種方法可以問GIT如何處理文件?如何確定Git是否將文件處理爲二進制文件或文本?

所以我們可以說我有在這兩個文件一個Git倉庫:一個ascii.dat文件,其中包含純文本和binary.dat含隨機二進制的東西文件。 Git將第一個dat文件處理爲文本,將第二個文件處理爲二進制文件。現在我想寫一個GIT webfrontend,它有一個文本文件查看器和一個二進制文件的特殊查看器(例如顯示一個十六進制轉儲文件)。當然,我可以實現自己的文本/二進制檢查,但如果觀衆依賴GIT處理這些文件的信息,那麼它會更有用。

那麼我怎麼能問GIT如果它把文件當作文本或二進制文件呢?

回答

27

builtin_diff() 調用diff_filespec_is_binary()它調用buffer_is_binary(),其檢查在第一8000個字節一個零字節(NUL「字符」)的任何發生(或者,如果較短的整個長度)。

我沒有看到這個「它是二進制的嗎?」測試是顯式暴露在任何命令,但。

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開始,所以我們只測試了這一點。


builtin_diff()有像Binary files %s and %s differ字符串應該是熟悉的。

+1

在cygwin(Windows)上,/ dev/null不存在。人們必須使用Seth帶來的神奇SHA1。 'git diff --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD - 「$ 1」'。 – koppor 2012-07-19 06:11:21

17

我不喜歡這個答案,但你可以解析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 ...是一個神奇的SHA它代表了空樹(這的SHA一個空的樹,但git特意意識到這個魔術)。

+2

謝謝你,好的先生。我使用'git diff-tree --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD',它有' - - filename'格式。 – 2011-09-17 01:21:25

+2

如果你想要在你的回購中的所有二進制文件的列表,你可以做'git diff --numstat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD - | grep「^ - 」| cut -f 3' – bonh 2015-02-06 16:32:06

+1

Seth請修正拼寫錯誤,應該是4b82 ** 5 ** d;所以SO不會讓我提交1個字符的編輯。 – chrisinmtown 2017-04-17 13:33:05

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

將返回git解釋爲文本文件的文件的名稱。

您可以使用通配符,例如

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

適用於更高版本,但使用git 1.7.5.4,只需提供_fatal:empty(sub)expression_。將正則表達式更改爲「-e。」可與此版本一起使用(可能會以錯誤識別僅包含空行的文本文件爲代價!)。 – 2013-10-10 16:03:26

+0

很喜歡測試這個文件的簡單方法。謝謝! – 2015-02-06 18:11:55

+0

我將其更改爲'-e .'以更加兼容並添加'--untracked'以處理更廣泛的文件。 – eckes 2016-03-07 00:58:35

-3

您可以使用命令行工具'file'工具。在Windows上它包含在git的安裝通常位於C:\ Program Files文件\的git的\ usr \ bin文件夾

file --mime-encoding * 

見多Get encoding of a file in Windows

+1

爲什麼downvote沒有解釋什麼是錯的? – 2016-09-26 20:39:04

+2

我並不是那個低估了它的人,但是它確實被低估了,因爲'文件'與git如何確定文件類型沒有任何關係。 'file'不使用git代碼,git不使用'file'命令。例如,'文件'不知道.gitattributes文件如何幫助git確定文件類型。 – 2016-10-12 01:39:11

0

截至得到耳光代碼質量差的風險,我列出了一個C實用程序is_binary,它圍繞Git源代碼中的原始buffer_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: 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 */ 
} 
相關問題