如何使用命令行工具进行DEFLATE提取git对象?


77

我正在寻找DEFLATE算法的命令行包装。

我有一个使用DEFLATE压缩的文件(git blob),我想将其解压缩。gzip命令似乎没有直接使用DEFLATE算法的选项,而不是gzip格式的选项。

理想情况下,我正在寻找可以做到这一点的标准Unix / Linux工具。

编辑:这是我尝试使用gzip解决我的问题时得到的输出:

$ cat .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7 | gunzip

gzip: stdin: not in gzip format

Answers:


17

更新: Mark Adler指出git blob不是原始的DEFLATE流,而是zlib流。这些可以通过pigz工具进行打包,该工具已预先打包在多个Linux发行版中:

$ cat foo.txt 
file foo.txt!

$ git ls-files -s foo.txt
100644 7a79fc625cac65001fb127f468847ab93b5f8b19 0   foo.txt

$ pigz -d < .git/objects/7a/79fc625cac65001fb127f468847ab93b5f8b19 
blob 14file foo.txt!

编辑由kriegaex:混帐猛砸对于Windows用户会发现,pigz默认情况下不可用。您可以在此处找到预编译的32/64位版本。我尝试了64位版本,效果很好。您可以例如直接复制Pigz.exec:\Program Files\Git\usr\bin以便将其放置在路径上。


我的原始答案出于历史原因而保留:

如果我理解Marc van Kempen提到的Wikipedia文章中的提示,则可以直接puff.czlib中使用。

这是一个小例子:

#include <assert.h>
#include <string.h>
#include "puff.h"

int main( int argc, char **argv ) {
    unsigned char dest[ 5 ];
    unsigned long destlen = 4;
    const unsigned char *source = "\x4B\x2C\x4E\x49\x03\x00";
    unsigned long sourcelen = 6;    
    assert( puff( dest, &destlen, source, &sourcelen ) == 0 );
    dest[ 4 ] = '\0';
    assert( strcmp( dest, "asdf" ) == 0 );
}

4
是的,我看着那个。但我绝对希望使用通常打包的工具。
FelixGeisendörfer10年

好的,现在用一个最小的示例进行了很晚的编辑。
mkluwe's

3
这是行不通的。git blob是zlib流,而不是原始放气。此解决方案适用于原始放气。puff不处理zlib标头和尾标。如果需要实用程序,可以使用pigz,它将使用-dz选项解压缩zlib格式,并使用生成zlib格式-z
Mark Adler's

1
@MarkAdler -z, --zlib Compress to zlib (.zz) instead of gzip format。到目前为止,此标志仅与压缩有关,而与解压缩无关。pigz -d < "infile" > "outfile"效果很好。
Murlakatamenka

@mkluwe,希望您不要介意我为Windows Git Bash用户添加了有关Pigz的信息。这个答案仍然是正确的,对我来说非常有用,我只是想进一步改善它。
kriegaex

52

类似于以下内容的内容将打印原始内容,包括“ $ type $ length \ 0”标头:

perl -MCompress::Zlib -e 'undef $/; print uncompress(<>)' \
     < .git/objects/27/de0a1dd5a89a94990618632967a1c86a82d577

[不正确]在没有标记和最终crc的原始放气流上,输出为空,退出代码为零78
ulidtko

C使用zlib直接压缩的任何数据也对我有用,所以很棒的答案。和往常一样:最终,大多数世界问题都可以用PERL
单线

46

您可以使用OpenSSL命令行工具执行此操作:

openssl zlib -d < $IN > $OUT

不幸的是,至少在Ubuntu上,zlib子命令在默认的构建配置(--no-zlib --no-zlib-dynamic)中被禁用,因此您需要openssl从源代码进行编译才能使用它。但是,例如,默认情况下在Arch上启用了此功能。

编辑:似乎该zlib命令也不再受Arch支持。这个答案可能不再有用了:(


12
请注意,如果您的openssl构建使用默认选项(包括和)配置,则该zlib子命令(以及子命令的-z选项enc不可用。因此,仅当您的openssl编译时从其中一个配置选项中删除了前缀时,此答案才有效。您可以通过查找--no-zlib--no-zlib-dynamicno--DZLIBopenssl version -f
Hercynium

@H 特别地,这是为Ubuntu 14.04 :(的情况下
西罗桑蒂利郝海东冠状病六四事件法轮功

在Mac上也可以使用。

1
在上不适用于Mac LibreSSL 2.2.7。我得到了openssl:Error: 'zlib' is an invalid command.

39

pythonic单行代码:

$> python -c "import zlib,sys;print \
           repr(zlib.decompress(sys.stdin.read()))" < $IN

repr(...)似乎将所有内容都括在引号('...')中,因此我不得不将其删除(解压缩zlib压缩的JSON文件)。
亚当·林德伯格

实际上python -c "import zlib,sys;print(zlib.decompress(sys.stdin.buffer.read()).decode('utf8'))" < $IN,如果您期望在python 3中创建一个utf8文件,那么它就是
Cyrille Pontvieux

27

您可以使用zlib-flate,如下所示:

cat .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7 \
    | zlib-flate -uncompress; echo

默认情况下,它在我的计算机上,但是qpdf - tools for and transforming and inspecting PDF files如果需要安装,它是其中的一部分。

echo在命令末尾弹出了一个,因为这样更容易读取输出。


4
不需要猫:zlib-flate -uncompress <.git / objects / c0 / fb67ab3fda7909000da003f4b2ce50a53f43e7
G. Sylvie Davies

20

尝试以下命令:

printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" | cat - .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7 | gunzip

无需外部工具。

来源:如何在UNIX中解压缩zlib数据?在unix SE


1
您最终遇到“意外的文件结尾”错误,但仍然是一种巧妙的方法。
埃里克

3
仅以gzip文件标题为前缀。尼斯:)
Jaap Versteegh

1
那也是我发现它的地方-现在添加zlipd() (printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - $@ |gzip -dc)到我的.bashrc:)
Tobias Kienzler

不错!@Eric add2> /dev/null将stderr发送为null。
poe84it

14

这是一个Ruby单一代码(cd .git /首先并标识任何对象的路径):

ruby -rzlib -e 'print Zlib::Inflate.new.inflate(STDIN.read)' < ./74/c757240ec596063af8cd273ebd9f67073e1208

ruby -rzlib -e 'print Zlib::Inflate.inflate($stdin.read).split("\x00")[1..-1].join' < .git/objects/abc
去除


9

这是在Python中打开提交对象的示例:

$ git show
commit 0972d7651ff85bedf464fba868c2ef434543916a
# all the junk in my commit...
$ python
>>> import zlib
>>> file = open(".git/objects/09/72d7651ff85bedf464fba868c2ef434543916a")
>>> data = file.read()
>>> print data
# binary garbage
>>> unzipped_data = zlib.decompress(data)
>>> print unzipped_data
# all the junk in my commit!

您将看到的内容几乎与'git cat-file -p [hash]'的输出相同,除了该命令不显示标头('commit'后跟内容的大小和空字节)。


4
根据操作系统的不同,您可能需要添加“ rb”开关,open例如:file = open(".git/objects/09/72d7651ff85bedf464fba868c2ef434543916a", "rb")
Igor Popov

我的压缩方法未知。
赛伯纳德

7

看起来Mark Adler牢记了我们的心意,并写了一个有关如何执行此操作的示例:http : //www.zlib.net/zpipe.c

它仅需编译即可gcc -lz安装zlib标头。我/usr/local/bin/zpipe在使用git时将生成的二进制文件复制到我的计算机上。


6

git对象是使用zlib而不是压缩的gzip,因此可以使用zlib解压缩它,也可以使用git命令,即git cat-file -p <SHA1>打印内容。


3
正如杰克上面所指出的,输出git cat-file -p <SHA1>没有的zlib的解压缩的完整内容.git/objects/<SHA1>。如果您要实现一个Git commit哈希计算器,则区别是关键
。–

尽管您想了解对象的内容,但是-p pretty print选项是一个优点。使用Pigz解压缩树对象不会给您带来可读的结果。
Vortexfive

6
// save this as deflate.go

package main

import (
    "compress/zlib"
    "io"
    "os"
    "flag"
)

var infile = flag.String("f", "", "infile")

func main() {
    flag.Parse()
    file, _ := os.Open(*infile)

    r, err := zlib.NewReader(file)
    if err != nil {
        panic(err)
    }
    io.Copy(os.Stdout, r)

    r.Close()
}

$ go build deflate.go
$ ./deflate -f .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7

完美在macOS 10.11上运行,谢谢!我必须从官方网站安装Go(无论如何我都打算这样做),然后它运行完美。你自己写的吗?意外的参数不是很好。:)
通配符

1

请参阅http://en.wikipedia.org/wiki/DEFLATE#Encoder_implementations

它列出了许多软件实现,包括gzip,因此应该可以使用。您是否尝试仅在文件上运行gzip?是否不能自动识别格式?

您怎么知道它是使用DEFLATE压缩的?使用什么工具压缩文件?


请参见此页底部:progit.org/book/ch9-2.html Gzip确实实现了DEFLATE,但似乎您不能直接应用该算法。Gzip希望数据采用gzip格式(这会在DEFLATE的数据周围添加一堆标题和内容)。(我刚刚编辑了我的帖子,包括了gunzip的输出)
FelixGeisendörfer10年

2
好的,因此可以使用zlib库压缩数据,这也可以说也可以使用zlib解压缩!您可以尝试使用ruby,perl或其他绑定来擦除简单的deflate脚本。或者,如果您不害怕尝试编译ac程序,请尝试以下方法: zlib.net/zlib_how.html
Marc van Kempen 2010年

注意我只是试过了,zpipe.c在git对象上工作,用'gcc -o zpipe zpipe.c -I / path / to / zlib.h -L / path / to / zlib -lz'编译,使用:./zpipe -d <.git / objects / 83 / 535d1693580f04824a2ddd22bd241fd00533d8(使用-d进行解压缩)
Marc van Kempen 2010年

1

您为什么不只使用git的工具来访问数据?这应该能够读取任何git对象:

git show --pretty=raw <object SHA-1>

4
我正在准备一个即将开设的git-workshop。示例之一涉及显示手工执行“ git add”。使用git本身对blob进行解压缩是没有意义的,因为我想展示底层功能。我可能最终会使用ruby或perl,但我希望可以坚持使用简单的bash oneliner。
FelixGeisendörfer10年

3
git cat-file -p c0fb67ab3fda7909000da003f4b2ce50a53f43e7
JakubNarębski2010年

@igorw:仅当对象在树中时。关于在“迷失+找到”中找到一些git对象的知识(在fsck.ext4将它们放到那里之后)非常方便……
akira

2
正如其他人指出的那样,这不能为您提供git对象完整内容。如果您尝试以编程方式处理git对象,则很重要。
Hawkeye Parker

1

我发现这个问题-text是在hadoop dfs我刚安装的客户端的新版本中寻找实用程序的错误的解决方法。该-text实用程序的工作方式类似于cat,除非所读取的文件被压缩,否则它将透明地解压缩并输出纯文本(因此而得名)。

已经发布的答案绝对有帮助,但是其中一些在处理Hadoop大小的数据时会遇到一个问题-他们在解压缩之前将所有内容读取到内存中。

因此,这是我在上述PerlPython答案上的变化,但没有这些限制:

蟒蛇:

hadoop fs -cat /path/to/example.deflate |
  python -c 'import zlib,sys;map(lambda b:sys.stdout.write(zlib.decompress(b)),iter(lambda:sys.stdin.read(4096),""))'

Perl:

hadoop fs -cat /path/to/example.deflate |
  perl -MCompress::Zlib -e 'print uncompress($buf) while sysread(STDIN,$buf,4096)'

注意,使用-cat子命令代替-text。这样一来,在他们修复此错误后,我的解决方法不会中断。对python版本的可读性表示歉意。



1

要添加到集合中,这里有用于放气/充气/原始放气/原始充气的perl一线纸。

放气

perl -MIO::Compress::Deflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Compress::Deflate::deflate(\$in, \$out); print $out;'

膨胀

perl -MIO::Uncompress::Inflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Uncompress::Inflate::inflate(\$in, \$out); print $out;'

原始放气

perl -MIO::Compress::RawDeflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Compress::RawDeflate::rawdeflate(\$in, \$out); print $out;'

生气膨胀

perl -MIO::Uncompress::RawInflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Uncompress::RawInflate::rawinflate(\$in, \$out); print $out;'


0
const zlib = require("zlib");
const adler32 = require("adler32");
const data = "hello world~!";
const chksum = adler32.sum(new Buffer(data)).toString(16);
console.log("789c",zlib.deflateRawSync(data).toString("hex"),chksum);
// or
console.log(zlib.deflateSync(data).toString("hex"));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.