73

In order to diff binary files in git, I assume I need to set up a difftool.

What difftools work? How do you put the parameters in?

LightCC
  • 125
  • 7
Nick Retallack
  • 1,906
  • 3
  • 16
  • 21
  • What kind of output are you expecting to get from a diff tool of a binary file? What kind of binary file is this? Is it something that can be rendered to a text format and then compared? – Zoredache Jan 24 '14 at 01:04

6 Answers6

58

If you want to force git to show binary files diff as a plain text diff use --text option like so:

git diff --text
chestozo
  • 681
  • 5
  • 4
  • I love this answer because it's so simple and quick! One thing that I'm noticing is that it seemingly doesn't work for a merge conflict. If anyone knows how to get that to work, I think that would be a great addition. – paulkernfeld Jan 12 '21 at 19:04
  • Note that if you have an external diff (`diff.external`) set up, you may need to add `--no-ext-diff` to bypass it. – ShreevatsaR May 29 '23 at 02:24
41

You can set a textconv config option for a filetype. See "Performing text diffs of binary files" in gitattributes(5). What you should use depends on the filetype.

Example 1:

Say you want to diff the contents of zip files. In that case you should put in one of the following files $XDG_CONFIG_HOME/git/config or $HOME/.gitconfig or $GIT_DIR/config .

[diff "zip"]
    textconv = unzip -v

Next time you ask for a diff on a zip file in a repo, it will call unzip -v on both version and diff the resulting text.

Example 2:

For pdf files you could use e.g. pdfinfo;

[diff "pdf"]
    textconv = pdfinfo

Example 3:

If there is no specific infomation utility for a filetype, you could e.g. use hexdump (comes with FreeBSD and OSX, also available on Linux):

[diff "bin"]
    textconv = hexdump -v -C
toastal
  • 103
  • 4
Roland Smith
  • 1,958
  • 12
  • 14
  • I could diff it in hex. I'd be happy enough just knowing how many bytes are different, or at what positions the bytes differ. I ended up using Hex Fiend by cloning my git repository so I could check out both versions of the file, because I couldn't figure out how to get git to launch the program. – Nick Retallack Jan 25 '14 at 06:09
  • @NickRetallack: see added examples. – Roland Smith Jan 25 '14 at 08:22
  • 2
    I added Example 3 to my git config, but when I do "git diff" it still just gives me the same short message: "Binary files a/file and b/file differ" – Nick Retallack Jan 31 '14 at 18:25
  • @NickRetallack Example 3 only works for files with the `bin` extension. AFAIK, you'll have to set up a textconv for each individual file type. – Roland Smith Feb 01 '14 at 17:34
  • What do I do if there's no extension? Can I get it to work with libmagic instead? – Nick Retallack Feb 03 '14 at 03:58
  • 1
    If you want to use libmagic, you'll have to look into the git source code to see if that works... – Roland Smith Feb 08 '14 at 20:50
  • 11
    I finally got this to work, after adding *.bin diff=bin to my .gitattributes – Justin Rowe Jan 07 '15 at 13:09
  • For pdf, get both the header and text changes: `[diff "pdf"]` `textconv="pdfinfo \"$1\";pdftotext \"$1\" - #"` `cachetextconv = true` – Tom Hale Sep 17 '16 at 07:32
  • I've tried to get this working for MS `.xlsm` files, which are just zip files, and cannot get it to work. Doing `unzip -v` lists the content as expected, so not sure why it's not working. Git just continues to state `Binary files a and b differ`. – nilskp Oct 14 '16 at 15:35
  • 3
    @nilskp You need to *both* define a diff in your `.gitconfig` file and assign that attribute to a path in `.gitattributes`. – Roland Smith Nov 20 '16 at 10:53
  • @RolandSmith, yeah, I did. – nilskp Nov 21 '16 at 19:35
  • @nilskp Maybe you should post what you did as a question. – Roland Smith Nov 21 '16 at 23:46
  • @RolandSmith, I did exactly as described here. But I don't have this need right now, and not enough time to formulate it into a question. – nilskp Nov 22 '16 at 14:19
32

The answer from Roland Smith was helpful but is currently incomplete (see the comments) - there are two parts to this.

You can define a new diff commands in your repository's .git/config file or your personal global $XDG_CONFIG_HOME/git/config/.gitconfig (usually $HOME/.gitconfig) file, for example a hex diff command using hexdump:

[diff "hex"]
    textconv = hexdump -v -C
    binary = true

Next, you need to use the repository's .gitattributes file to tell git which files should be used with this special diff command:

# Binary files (no line-ending conversions), diff using hexdump
*.bin binary diff=hex

Like the .gitignore file, the .gitattributes file should be checked into your repository.

In my case I have several different file extensions which I want to treat as binary (e.g. avoid any line ending conversions if using git on Windows), and also see any differences via hexdump:

https://github.com/peterjc/galaxy_blast/commit/5ec4695e6c3da3926fb100ca006f0f3e88c53c3d

See also https://github.com/resin-io/etcher/pull/1367 for another example defining a hexdump diff command for use with image files.

Peter Cock
  • 421
  • 4
  • 4
  • 5
    You can set the `.gitattributes` globally as well (to go along with the `[diff]` entries in your global `.gitconfig`). If you make the `.gitattributes` local to the repo, then the user will have to modify his local `.gitconfig` repo settings because for security reasons those will not be pushed to the remote. Either way, each user has to update their local files/config somehow to enable this behavior. In `.gitconfig` under `[core]` add `attributesfile = c:/users//.gitattributes` or wherever you want to store it if you make it global (note the forwardslashes, even in windows). – LightCC Nov 01 '19 at 20:40
5

To create a binary patch, a patch that works for binaries instead of just saying "Binary files differ", use

git diff --binary file1 file2

This produces a "GIT binary patch" using only ASCII characters (unlike --text), suitable for emailing.

qwr
  • 657
  • 8
  • 13
1

I liked @qwr's answer above, however I wanted to see it in hexdump mode, rather than deflated(compressed) base85 "Git binary patch" format. If I use @peterjc's answer from above, then I get the diff between two hexdumps which is like concat-ing two hexdumps, so not very useful.

As such, I've decided to patch git(v2.37.3 on Gentoo) to add --hexdump argument to git diff which works only in --binary mode, and now it looks like in this example:

$ git diff --hexdump --binary  HEAD~1  "./dated/sheet0005_older/2006/sheet0620/20000809_1118(3)..JPG"
diff --git a/txt/papersheets/dated/sheet0005_older/2006/sheet0620/20000809_1118(3)..JPG b/txt/papersheets/dated/sheet0005_older/2006/sheet0620/20000809_1118(3)..JPG
index 263d047bf61e2104157d4b1feda5b77a01000847..c78a9a1ddddd0267dc490711eaf1723e38767b09 100644
GIT binary hexdump (non-reusable, for human eyes only) patch
delta 34
CC A0 18 C7 FD 17 02 FF  D8 83 87 11 87 87 11 01   |................|
87 87 11 02 87 87 11 03  87 87 11 04 B7 87 11 05   |................|
C5 FE                                              |..              |

delta 4140
C7 FD 17 CC A0 18 7F FF  D8 FF E1 11 83 45 78 69   |.............Exi|
66 00 00 49 49 2A 00 08  00 00 00 0A 00 0F 01 02   |f..II*..........|
00 0E 00 00 00 86 00 00  00 10 01 02 00 06 00 00   |................|
00 A6 00 00 00 12 01 03  00 01 00 00 00 01 00 00   |................|
00 1A 01 05 00 01 00 00  00 DE 00 00 00 1B 01 05   |................|
00 01 00 00 00 E6 00 00  00 28 01 03 00 01 00 00   |.........(......|
00 02 00 00 00 31 01 02  00 26 00 00 00 B6 00 00   |.....1...&......|
00 32 01 02 00 14 00 00  00 EE 00 00 00 13 02 03   |.2..............|
00 01 00 00 00 02 7F 00  00 00 69 87 04 00 01 00   |..........i.....|
00 00 02 01 00 00 76 02  00 00 53 6F 6E 79 20 45   |......v...Sony E|
72 69 63 73 73 6F 6E 00  00 00 00 00 00 00 00 00   |ricsson.........|
00 00 00 00 00 00 00 00  00 00 57 38 30 30 69 00   |..........W800i.|
00 00 00 00 00 00 00 00  00 00 52 31 42 43 30 30   |..........R1BC00|
32 20 20 20 20 20 70 72  67 43 58 43 31 32 35 30   |2     prgCXC1250|
30 39 32 5F 45 55 5F 31  5F 43 41 20 34 2E 35 00   |092_EU_1_CA 4.5.|
00 00 48 00 00 00 01 00  00 00 48 00 00 00 01 00   |..H.......H.....|
00 00 32 30 30 30 7F 3A  30 38 3A 30 39 20 31 31   |..2000.:08:09 11|
3A 31 38 3A 32 32 00 16  00 9A 82 05 00 01 00 00   |:18:22..........|
00 10 02 00 00 9D 82 05  00 01 00 00 00 18 02 00   |................|
00 27 88 03 00 01 00 00  00 64 00 00 00 00 90 07   |.'.......d......|
00 04 00 00 00 30 32 32  30 03 90 02 00 14 00 00   |.....0220.......|
00 20 02 00 00 04 90 02  00 14 00 00 00 34 02 00   |. ...........4..|
00 01 91 07 00 04 00 00  00 01 02 03 00 04 92 0A   |................|
00 01 00 00 00 48 02 00  00 07 92 03 00 01 00 00   |.....H..........|
00 02 00 00 00 08 7F 92  03 00 01 00 00 00 00 00   |................|
00 00 09 92 03 00 01 00  00 00 00 00 00 00 00 A0   |................|
07 00 04 00 00 00 30 31  30 30 01 A0 03 00 01 00   |......0100......|
00 00 01 00 00 00 02 A0  04 00 01 00 00 00 60 06   |..............`.|
00 00 03 A0 04 00 01 00  00 00 C8 04 00 00 05 A0   |................|
04 00 01 00 00 00 58 02  00 00 01 A4 03 00 01 00   |......X.........|
00 00 00 00 00 00 02 A4  03 00 01 00 00 00 00 00   |................|
00 00 03 A4 03 00 01 00  00 00 00 00 00 00 04 A4   |................|
05 00 01 00 00 00 7F 50  02 00 00 06 A4 03 00 01   |.......P........|
00 00 00 03 00 00 00 0C  A4 03 00 01 00 00 00 03   |................|
00 00 00 00 00 00 00 01  00 00 00 3C 00 00 00 1C   |...........<....|
00 00 00 0A 00 00 00 32  30 30 30 3A 30 38 3A 30   |.......2000:08:0|
39 20 31 31 3A 31 38 3A  32 32 00 32 30 30 30 3A   |9 11:18:22.2000:|
30 38 3A 30 39 20 31 31  3A 31 38 3A 32 32 00 00   |08:09 11:18:22..|
00 00 00 0A 00 00 00 64  00 00 00 64 00 00 00 02   |.......d...d....|
00 01 00 02 00 04 00 00  00 52 39 38 00 02 00 07   |.........R98....|
00 04 00 00 00 30 7F 31  30 30 00 00 00 00 07 00   |.....0.100......|
...

8B 38 FC B5 92 51 F3 79  D6 8E F1 B2 E0 E4 12 08   |.8...Q.y........|
03 F1 3F CC 55 88 A1 86  DA 15 86 DD 22 8A 31 9C   |..?.U.......".1.|
22 49 85 1D F8 02 97 52  AD 64 7F FF D9 FF C4 01   |"I.....R.d......|
A2 00 00 01 05 01 01 01  01 81 0E 85 0E 01 85 0E   |................|
02 85 0E 03 85 0E 04 B5  0E 05 B9 FE               |............    |

lines 219-269/269 (END)

rather than the normal way, which is this:

$ git diff --binary  HEAD~1  "./dated/sheet0005_older/2006/sheet0620/20000809_1118(3)..JPG"
diff --git a/txt/papersheets/dated/sheet0005_older/2006/sheet0620/20000809_1118(3)..JPG b/txt/papersheets/dated/sheet0005_older/2006/sheet0620/20000809_1118(3)..JPG
index 263d047bf61e2104157d4b1feda5b77a01000847..c78a9a1ddddd0267dc490711eaf1723e38767b09 100644
GIT binary patch
delta 34
lcmX@JK;rmcai;$_n%f22+XWecm<foPftY1`yCCb)e*gxY4e<Z~

delta 4140
zcmb7Hc{o&U8$UCHv5cLv3?`I_-kFJ-8K#jU#=fSKWXVzyvQ2Tazh#UydNm>Y5-PGJ
zp@mUdK4eLjB1=RDsc3x1oA>&<zU%wvyRYka-M{mk`@Wy&{+;`e=d}LZ{yJL<+!)w+
zFB+*I?0FUdjEvL(UH}020bv*%5Q10?1QCeyK)wKi7z_cxAioJ2828_P1mdz=d=lcj
zw_@NB$3eNfAYTmu4{-^|&qEN0|EdEAp$E@cuD=Vxp{jvUmbH&}2u9z})5YK4#~XV8
z-*$|E#d`j>Xob@|jK$(Hn|9I9{jmLE99|2HCE`!(+n&aqK70tHxmOE{H-xZx@P9lW
zi^YN@EP;e2VsJPTjzGfWfo(uW#IL?YprhR0;!+S-`SaJAT{pK*L;_rp!{YH+MB=Z$
zFi;HF7T1J0Ea_Ja4C<9Dng7?;&^j`Ct9K}$7u<T-tjYHq2eP*|z+thl?Ei=k&;F&A
z6ZAz8Tbu=*gnNtIZ*H9TD}J*k{5OvHjdSJwY7(@75_q;=AfN=)Z+x@BreHb{&=B|`
zY>M{Zn*FaeDD?06O|>=whbqDU*361XfY?@hAk^PxC=x(yjSbY;{~WU}=%D|M*#N|U
zA2S&Imnvh>I(&=Y+MHj={`uPfcxd2<fGB{MhX={S%?l!tNIpJZew2hDN<aW5Eha83
zAt$3CFDHXWW0d!*U=-Dr(CFO<RMoLKO-)S&6(X5{*V(&I6A$C#<3kCcqyz<}@H@~u
z@c*}MGy$T#LO?K(jescva8VdS6m}n;4+Gx<C<G*yC_)sV01^69a$fLUWW|Y^-P6R9
zInvKhU(1R=ICv=FX7!fkXx6dTt0k&#Y)b`KIv?;^T505}a_jwBvuX1aopBZ#*!Y}u
z-znL!=}xepUB<J}mm(mf5FAjFB2e)VXRA%R<3N+AkgBtS1B!)}as#sUgXKY&`c8T_
zp_RBUJYyGHS7gWt@Mu$SXd-)Nor!`AXB<)<W3>+Tzs)KV%Pl_=qWv{8!H2!u-IARW
zLq?8UXwWq(e>(Ap^GMNQ9Me4~^wlq;UmjK3$)HXBuvnG5MlZV3Bzt2l!ECp(i*gcU
zxwqy>bgspa;e6<QOD+0&zjlz=;fIQC95;x#m*o-Tk(xhfT3VZ`l+=^q8{^_r<sdlr
z<)ilE+Z<EH{+ID^g1*I_!!F^>OFw#NJ$dyVi2Ot88ccMT&<ksKoOAau+@D?0T;<!M
zJ()~!<7f3Brx#E~@K3&%_UNLEN7Zg{W@cAP&J{$t(?v9feX9`l6mY?tlZq=ivPgZk
zBkd!;N$9aqFvmFyb0&{f|IDyf{n)gZd-vT5g~yR0WMgz@9p_R(hwO#@?=f`6u`iTi
...
z(Ts<g0S%htr2K@R8^Gzs+%<O-6^>pt1*Fd!+G!~e93M&((FohUZ$pbEi~~`zJRVmb
zxJaWDN4w-XZ`2A{Z;sd81GeLsHFYiAdp>RJo~W$GIFY@weVC!D>2!xU!urEx%cYP$
z#^Qsq2{B&8BIUL1pLb&3O2!N;UdJ&NjiTkg!PBkET)~aOjpwi&=wFW;23fdJv=A&>
R2p%njh!)~{D8yaI`8U9_qG|vD

lines 32-82/82 (END)

(I used ... above to redact/snip most output lines)

Here's the patch:

Index: /var/tmp/portage/dev-vcs/git-2.37.3/work/git-2.37.3/diff.c
===================================================================
--- git-2.37.3/diff.c
+++ git-2.37.3/diff.c
@@ -743,7 +743,8 @@ enum diff_symbol {
    DIFF_SYMBOL_NO_LF_EOF,
    DIFF_SYMBOL_CONTEXT_FRAGINFO,
    DIFF_SYMBOL_CONTEXT_MARKER,
-   DIFF_SYMBOL_SEPARATOR
+   DIFF_SYMBOL_SEPARATOR,
+  DIFF_SYMBOL_BINARY_HEXDUMP_DIFF_HEADER,
 };
 /*
  * Flags for content lines:
@@ -1472,6 +1473,9 @@ static void emit_diff_symbol_from_struct
    case DIFF_SYMBOL_BINARY_DIFF_HEADER:
        fprintf(o->file, "%sGIT binary patch\n", diff_line_prefix(o));
        break;
+   case DIFF_SYMBOL_BINARY_HEXDUMP_DIFF_HEADER:
+       fprintf(o->file, "%sGIT binary hexdump (non-reusable, for human eyes only) patch\n", diff_line_prefix(o));
+       break;
    case DIFF_SYMBOL_BINARY_DIFF_HEADER_DELTA:
        fprintf(o->file, "%sdelta %s\n", diff_line_prefix(o), line);
        break;
@@ -3237,10 +3241,11 @@ static void emit_binary_diff_body(struct
                  mmfile_t *one, mmfile_t *two)
 {
    void *cp;
-   void *delta;
+   void *delta,*plaindelta;
+  char *hexdump_ptr;
    void *deflated;
    void *data;
-   unsigned long orig_size;
+   unsigned long orig_size,hexdump_size;
    unsigned long delta_size;
    unsigned long deflate_size;
    unsigned long data_size;
@@ -3249,20 +3254,31 @@ static void emit_binary_diff_body(struct
     * whichever is smaller.
     */
    delta = NULL;
+  plaindelta=NULL;
+  hexdump_ptr=NULL;
+  hexdump_size=0;
    deflated = deflate_it(two->ptr, two->size, &deflate_size);
    if (one->size && two->size) {
-       delta = diff_delta(one->ptr, one->size,
+       plaindelta = diff_delta(one->ptr, one->size,
                   two->ptr, two->size,
                   &delta_size, deflate_size);
-       if (delta) {
-           void *to_free = delta;
+       if (plaindelta) {
+           //void *to_free = plaindelta;
            orig_size = delta_size;
-           delta = deflate_it(delta, delta_size, &delta_size);
-           free(to_free);
+           delta = deflate_it(plaindelta, delta_size, &delta_size);
+           //free(to_free);
+      if (!(o->output_format & DIFF_FORMAT_HEXDUMP)) {
+        free(plaindelta);
+        plaindelta=NULL;
+      }
        }
    }
 
    if (delta && delta_size < deflate_size) {
+    //using delta (z packed aka deflated)
+    // show plaindelta & orig_size
+    hexdump_ptr=plaindelta;
+    hexdump_size=orig_size;
        char *s = xstrfmt("%"PRIuMAX , (uintmax_t)orig_size);
        emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_HEADER_DELTA,
                 s, strlen(s), 0);
@@ -3271,6 +3287,10 @@ static void emit_binary_diff_body(struct
        data = delta;
        data_size = delta_size;
    } else {
+    //using deflated two (the second file, z packed ie. gzipped or similar)
+    // show two->ptr & two->size
+    hexdump_ptr=two->ptr;
+    hexdump_size=two->size;
        char *s = xstrfmt("%lu", two->size);
        emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_HEADER_LITERAL,
                 s, strlen(s), 0);
@@ -3280,6 +3300,64 @@ static void emit_binary_diff_body(struct
        data_size = deflate_size;
    }
 
+  if (o->output_format & DIFF_FORMAT_HEXDUMP) {
+#define LINELEN 16
+#define LINELENPLUSZERO (LINELEN+1)
+#define UNPRINTABLECHAR '.'
+    char line[LINELENPLUSZERO];
+    memset(line,'\0',LINELENPLUSZERO);
+    //line[LINELEN]=0;
+    assert(0 == line[LINELEN]);
+    int i=0;
+    const unsigned long origlen=hexdump_size;
+    for (; i<origlen; i++) {
+      const char c=hexdump_ptr[i];
+      const int mod=i%16;
+      if (isprint(c)) {
+        line[mod]=c;
+      } else {
+        line[mod]=UNPRINTABLECHAR;
+      }
+      fprintf(o->file,"%02X ", c & 0xff);
+      if (i>0){
+        if ((i+1) % 8==0) {
+          fprintf(o->file," ");
+        }
+        if ((i+1) % 16==0) {
+          assert(0 == line[16]);
+          fprintf(o->file," |%s|\n",line);
+        }
+      }
+    }
+    int weat=i%16;
+    if (weat != 0) {
+      line[weat]=0;
+      if (weat<8){
+        fprintf(o->file," ");
+      }
+      for (int i=weat;i<16;i++) {
+        fprintf(o->file,"   ");
+      }
+      fprintf(o->file," ");
+      fprintf(o->file," |%s",line);
+      for (int i=weat;i<16;i++) {
+        fprintf(o->file," ");
+      }
+      fprintf(o->file,"|\n");
+    }
+    //for (int i=0; i<origlen; i++) {
+    //  printf("%02X ",fp[i] & 0xff);
+    //}
+    //fprintf(o->file,"\n");//this is FOOTER below
+    //emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_BODY,
+    //      line, len, 0);
+
+    if (plaindelta) {
+      free(plaindelta);
+      plaindelta=NULL;
+    }
+  } else { //not re-indenting the below, for an easier-on-the-eyes patch.
+
    /* emit data encoded in base85 */
    cp = data;
    while (data_size) {
@@ -3301,6 +3379,7 @@ static void emit_binary_diff_body(struct
        emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_BODY,
                 line, len, 0);
    }
+  }
    emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_FOOTER, NULL, 0, 0);
    free(data);
 }
@@ -3308,7 +3387,11 @@ static void emit_binary_diff_body(struct
 static void emit_binary_diff(struct diff_options *o,
                 mmfile_t *one, mmfile_t *two)
 {
-   emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_HEADER, NULL, 0, 0);
+  if (o->output_format & DIFF_FORMAT_HEXDUMP) {
+    emit_diff_symbol(o, DIFF_SYMBOL_BINARY_HEXDUMP_DIFF_HEADER, NULL, 0, 0);
+  } else {
+    emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_HEADER, NULL, 0, 0);
+  }
    emit_binary_diff_body(o, one, two);
    emit_binary_diff_body(o, two, one);
 }
@@ -4710,7 +4793,7 @@ void diff_setup_done(struct diff_options
                      DIFF_FORMAT_NAME_STATUS |
                      DIFF_FORMAT_CHECKDIFF |
                      DIFF_FORMAT_NO_OUTPUT))
-       options->output_format &= ~(DIFF_FORMAT_RAW |
+       options->output_format &= ~(DIFF_FORMAT_RAW | DIFF_FORMAT_HEXDUMP | //this clears these bits
                        DIFF_FORMAT_NUMSTAT |
                        DIFF_FORMAT_DIFFSTAT |
                        DIFF_FORMAT_SHORTSTAT |
@@ -5389,6 +5472,9 @@ static void prep_parse_options(struct di
        OPT_BIT_F(0, "raw", &options->output_format,
              N_("generate the diff in raw format"),
              DIFF_FORMAT_RAW, PARSE_OPT_NONEG),
+       OPT_BIT_F(0, "hexdump", &options->output_format,
+             N_("generate the diff in hexdump format for human eyes only(ie. can't git apply it!)"),
+             DIFF_FORMAT_PATCH | DIFF_FORMAT_HEXDUMP, PARSE_OPT_NONEG),
        OPT_BITOP(0, "patch-with-raw", &options->output_format,
              N_("synonym for '-p --raw'"),
              DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW,
@@ -6755,7 +6841,7 @@ void diffcore_std(struct diff_options *o
 {
    int output_formats_to_prefetch = DIFF_FORMAT_DIFFSTAT |
        DIFF_FORMAT_NUMSTAT |
-       DIFF_FORMAT_PATCH |
+       DIFF_FORMAT_PATCH | //DIFF_FORMAT_HEXDUMP | //we don't use hexdump here because it implies DIFF_FORMAT_PATCH.
        DIFF_FORMAT_SHORTSTAT |
        DIFF_FORMAT_DIRSTAT;
 
Index: /var/tmp/portage/dev-vcs/git-2.37.3/work/git-2.37.3/diff.h
===================================================================
--- git-2.37.3/diff.h
+++ git-2.37.3/diff.h
@@ -103,6 +103,7 @@ typedef struct strbuf *(*diff_prefix_fn_
 #define DIFF_FORMAT_PATCH  0x0010
 #define DIFF_FORMAT_SHORTSTAT  0x0020
 #define DIFF_FORMAT_DIRSTAT    0x0040
+#define DIFF_FORMAT_HEXDUMP    0x0080
 
 /* These override all above */
 #define DIFF_FORMAT_NAME   0x0100
$ git diff -h
usage: git diff --no-index [<options>] <path> <path>

Diff output format options
    -p, --patch           generate patch
    -s, --no-patch        suppress diff output
    -u                    generate patch
    -U, --unified[=<n>]   generate diffs with <n> lines context
    -W, --function-context
                          generate diffs with <n> lines context
    --raw                 generate the diff in raw format
    --hexdump             generate the diff in hexdump format for human eyes only(ie. can't git apply it!)
    --patch-with-raw      synonym for '-p --raw'
    --patch-with-stat     synonym for '-p --stat'

It doesn't seem very helpful to force text files to be seen as binary for git diff purposes:

$ cat .gitattributes                                                                                                                                              
*.log -diff

That is needed, else it will be force seen as text even if --binary is specified. Seen man 5 gitattributes section Marking files as binary.

$ GIT_PAGER=cat

ie. tell git to not use less.

$ git diff
diff --git a/genkernel-boot.log b/genkernel-boot.log
index 85ebc17..3d89503 100644
Binary files a/genkernel-boot.log and b/genkernel-boot.log differ
$ git diff --binary
diff --git a/genkernel-boot.log b/genkernel-boot.log
index 85ebc177502e392a41183f9baa730e01180b647d..3d89503b6824c39d7c70f446aa2fe1d400ab72f0 100644
GIT binary patch
delta 49
zcmV-10M7rgi2;U*0kFdsv-%c+6tlD|!V8m7LJpH20tb`eLI{&8LlFcZb75<f(Gf1Q
HkT)O==e`m1

delta 42
wcmZqcWZVEmhsBtSD|06^3Yly^EY>K(nvt2DpSM{+`y2OU0WPV{Y32&N08T9qbN~PV

This is why I said it doesn't seem useful, because what is this?:

$ git diff --binary --hexdump
diff --git a/genkernel-boot.log b/genkernel-boot.log
index 85ebc177502e392a41183f9baa730e01180b647d..3d89503b6824c39d7c70f446aa2fe1d400ab72f0 100644
GIT binary hexdump (non-reusable, for human eyes only) patch
delta 49
B0 89 01 86 89 01 B0 C3  16 B3 FA 16 81 14 B3 B4   |................|
2B C2 0B 93 50 42 0E 93  1E 02 07 93 E0 42 08 93   |+...PB.......B..|
2A 43 11 04 20 73 61 6B  93 D1 11 2E B3 90 37 20   |*C.. sak......7 |
0D                                                 |.               |

delta 42
86 89 01 B0 89 01 B0 C3  16 03 73 79 6D 93 01 12   |..........sym...|
34 B3 C3 16 81 14 05 68  69 63 6F 6E B3 10 2B F6   |4......hicon..+.|
0B 93 10 0A 1A B3 66 37  20 0D                     |......f7 .      |

$ git diff --text
diff --git a/genkernel-boot.log b/genkernel-boot.log
index 85ebc17..3d89503 100644
--- a/genkernel-boot.log
+++ b/genkernel-boot.log
@@ -95,7 +95,6 @@
 [2020-11-23 14:52:20] Failed (1): 'modprobe u14-34f'
 [2020-11-23 14:52:20] Failed (1): 'modprobe ultrastor'
 [2020-11-23 14:52:20] Failed (1): 'modprobe wd7000'
-[2020-11-23 14:52:20] Failed (1): 'modprobe sym53c8xx'
 [2020-11-23 14:52:20] Failed (1): 'modprobe dmx3191d'
 [2020-11-23 14:52:20] Failed (1): 'modprobe imm'
 [2020-11-23 14:52:20] Failed (1): 'modprobe in2000'
@@ -190,7 +189,6 @@
 [2020-11-23 14:52:20] Failed (1): 'modprobe hid-apple'
 [2020-11-23 14:52:20] Failed (1): 'modprobe hid-belkin'
 [2020-11-23 14:52:20] Failed (1): 'modprobe hid-cherry'
-[2020-11-23 14:52:20] Failed (1): 'modprobe hid-chicony'
 [2020-11-23 14:52:20] Failed (1): 'modprobe hid-cypress'
 [2020-11-23 14:52:20] Failed (1): 'modprobe hid-dummy'
 [2020-11-23 14:52:20] Failed (1): 'modprobe hid-ezkey'
@@ -244,6 +242,7 @@
 [2020-11-23 14:52:20] Failed (1): 'modprobe btrfs'
 [2020-11-23 14:52:20] Failed (1): 'modprobe reiserfs'
 [2020-11-23 14:52:20] Failed (1): 'modprobe jfs'
+[2020-11-23 14:52:21] Executed: 'mount -o move /sys /newroot/sys' sak
 [2020-11-23 14:52:20] Failed (1): 'modprobe nfs'
 [2020-11-23 14:52:20] Failed (1): 'modprobe xfs'
 [2020-11-23 14:52:20] Failed (1): 'modprobe zfs'
-1

The above are comprehensive ways to do so.. however, if you just need to do it for a few files, the following method is what I use:

git checkout HEAD -- /path/to/file > ~/file
vimdiff ~/file /path/to/file

Here I am using vimdiff but you can use any other tool. The above can be also combined into a small script if you need to do this over and over again.

jww
  • 11,918
  • 44
  • 119
  • 208
alpha_989
  • 993
  • 10
  • 14
  • 1
    This appears to have discarded the changes to my file (and created an empty file where I wanted the committed version to be). – Erhannis Dec 06 '18 at 02:49