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

91
我正在寻找一个DEFLATE算法的命令行包装器。我有一个使用DEFLATE压缩的文件(git blob),我想解压它。gzip命令似乎没有直接使用DEFLATE算法的选项,而不是gzip格式。理想情况下,我正在寻找一个可以做到这一点的标准Unix / Linux工具。编辑:当我尝试使用gzip解决我的问题时,这是我得到的输出:
$ cat .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7 | gunzip

gzip: stdin: not in gzip format

针对那些通过搜索引擎找到这个问题并想要使用 cURL 解压数据的人的相关问题:https://dev59.com/bWsy5IYBdhLWcg3wtwW9 - baptx
22个回答

9

Git对象使用zlib进行压缩,而不是gzip,因此可以使用zlib解压缩,或者使用git命令,例如git cat-file -p <SHA1>打印内容。


3
正如Jack在上面指出的git cat-file -p <SHA1>的输出并不是.git/objects/<SHA1>的zlib解压缩的完整内容。如果你想要实现一个Git提交哈希计算器,这种差异是关键的... - ntc2
-p 的漂亮打印选项是一个优点,当您想要了解对象的内容时非常有用。使用 pigz 解压树对象不会给您人类可读的结果。 - Vortexfive

7
// 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(我本来就打算这样做),然后它完美地工作了。这是你自己写的吗?对于意外的参数,它并不是很友好。 :) - Wildcard

4

Git对象是zlib流(不是原始deflate)。pigz可以使用-dz选项解压缩这些流。


4

pigz可以完成这项任务:

apt-get install pigz
unpigz -c .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7

2
我曾多次遇到这个问题,似乎互联网上几乎所有的答案都是错误的,要求编译一些不太理想的代码或下载一大堆系统未跟踪的依赖项!但我找到了一个真正的解决方案。它使用 PERL,因为 PERL 在大多数系统上都可以轻松获取。

从 Bash 类似的 shell 中:

perl -mIO::Uncompress::RawInflate=rawinflate -erawinflate'"-","-"'

或者,如果您手动执行/分叉(没有Shell引号,但是分隔行):

  • perl
  • -mIO::Uncompress::RawInflate=rawinflate
  • -erawinflate"-","-"

重要提示:如果流不以有效的DEFLATE流(例如未压缩的数据)开头,则此命令将愉快地传输所有数据。只有当流以有效的DEFLATE流(带有有效的字典,我想?我不太确定...)开始时,然后此命令将以某种方式出错。在某些情况下,这可能是可取的。

希望这能帮助任何时空旅行者。

参考资料:

PERL IO::Uncompress::RawInflate::rawinflate


Git 对象不是原始的 deflate 格式,它们是 zlib 流。 - Mark Adler
你好 Adler!是的,这个答案实际上并没有回答原问题。也许它应该被移动到自己的问题和答案中,或者问题的标题也应该被更改。 - BurninateSE

1

这是我使用 Powershell 的方法。

$fs = New-Object IO.FileStream((Resolve-Path $Path), [IO.FileMode]::Open, [IO.FileAccess]::Read)
$fs.Position = 2
$cs = New-Object IO.Compression.DeflateStream($fs, [IO.Compression.CompressionMode]::Decompress)
$sr = New-Object IO.StreamReader($cs)
$sr.ReadToEnd()

然后,您可以创建一个别名,例如:

function func_deflate{
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline = $true)]
        [ValidateScript({Test-Path $_ -PathType leaf})]
        [string]$Path
    )
    $ErrorActionPreference = 'Stop'    
    $fs = New-Object IO.FileStream((Resolve-Path $Path), [IO.FileMode]::Open, [IO.FileAccess]::Read)
    $fs.Position = 2
    $cs = New-Object IO.Compression.DeflateStream($fs, [IO.Compression.CompressionMode]::Decompress)
    $sr = New-Object IO.StreamReader($cs)
    return $sr.ReadToEnd()
}

Set-Alias -Name deflate -Value func_deflate

enter image description here


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;'

1

我发现这个问题是在寻找一个解决方案,因为我刚刚安装了新版本的 hadoop dfs 客户端中的 -text 实用程序存在一个 bug。 -text 实用程序类似于 cat,但是如果要读取的文件被压缩,它会透明地解压缩并输出纯文本(因此得名)。

已经发布的答案肯定有帮助,但其中一些在处理大量 Hadoop 数据时会有一个问题-在解压缩之前将所有内容读入内存中。

因此,这里是我对上面 PerlPython 答案的变化,没有那种限制:

Python:

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

请查看http://en.wikipedia.org/wiki/DEFLATE#Encoder_implementations

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

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


Gzip确实实现了DEFLATE算法,但似乎不能直接应用该算法。Gzip期望数据以gzip格式提供(这会在DEFLATE压缩的数据周围添加一堆头文件和其他内容)。 (我刚刚编辑了我的帖子,包括gunzip的输出结果) - Felix Geisendörfer
2
啊,好的,数据是使用zlib库进行压缩的,那么很容易理解可以使用zlib来进行解压!你可以尝试使用Ruby、Perl或其他绑定程序来编写一个简单的deflate脚本。或者如果你不怕尝试编译C程序,可以尝试这个链接:http://www.zlib.net/zlib_how.html - Marc van Kempen
注意:我刚试过了,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

1

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

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

4
我正在为不久后要举行的一个小型 Git 工作坊做准备。其中一个示例涉及手动展示“git add”的作用。使用 Git 自身解压 Blob 没有意义,因为我想展示其底层功能。我可能最终会使用 Ruby 或 Perl,但我希望能使用简单的 Bash 单行命令。 - Felix Geisendörfer
4
使用命令 git cat-file -p c0fb67ab3fda7909000da003f4b2ce50a53f43e7 可以查看 Git 存储库中对象 ID 为 c0fb67ab3fda7909000da003f4b2ce50a53f43e7 的对象的内容。 - Jakub Narębski
@igorw: 仅当对象在树中时才有效。了解如何在'lost+found'中找到一些git对象(在fsck.ext4将它们放在那里之后)非常方便... - akira
2
正如其他人所指出的那样,这并不会给你完整的git对象内容。如果你想要在程序上对git对象进行编程处理,这一点非常重要。 - Hawkeye Parker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接