Git 为什么将同一内容压缩两次会得到两个具有不同SHA1的文件?
我在git和zip文件方面遇到了一个奇怪的问题。我的构建脚本将一堆文档html页面压缩成docs.zip文件,然后将该文件签入git 我遇到的问题是,每次我重新运行构建脚本并获得一个新的zip文件时,新的zip文件的SHA1都与上次运行的不同。我的构建脚本正在调用ant zip任务。然而,如果我将同一个目录压缩两次,从MacOSXshell手动调用MacOSXzip会给我一个不同的sha1 运行1:Git 为什么将同一内容压缩两次会得到两个具有不同SHA1的文件?,git,ant,zip,gzip,sha,Git,Ant,Zip,Gzip,Sha,我在git和zip文件方面遇到了一个奇怪的问题。我的构建脚本将一堆文档html页面压缩成docs.zip文件,然后将该文件签入git 我遇到的问题是,每次我重新运行构建脚本并获得一个新的zip文件时,新的zip文件的SHA1都与上次运行的不同。我的构建脚本正在调用ant zip任务。然而,如果我将同一个目录压缩两次,从MacOSXshell手动调用MacOSXzip会给我一个不同的sha1 运行1: zip foo.zip * openssl sha1 foo.zip rm foo.zip
zip foo.zip *
openssl sha1 foo.zip
rm foo.zip
运行2:
zip foo.zip *
openssl sha1 foo.zip
运行1和运行2给出不同的SHA1,即使在运行之间内容没有更改。在这两种情况下,zip打印出的文件与正在压缩的文件完全相同。这并不表示zip文件中包含任何特定于操作系统的文件,如.DS_Store
zip算法是确定性的吗?如果在相同的内容上运行,它会产生完全相同的位吗?若否,原因为何
对于以确定性方式压缩文件,我有哪些选择?压缩文件中有数千个,我不希望这些文件有太大的变化。我知道git会将你签入的任何文件压缩,但压缩它们的动机只是为了避免它们的大量出现。根据维基百科的说法,压缩文件似乎有标题
文件上次修改时间和文件上次修改日期,因此,如果zip是从相同的内容重新生成的,那么签入git的任何zip文件在git看来都将发生更改。而且似乎没有任何标志告诉它不要设置这些标题
我只是使用tar,如果运行多次,它似乎会为相同的输入生成相同的字节 默认情况下,gzip保存文件名和时间戳
%> gzip -help 2>&1 | grep -e '-n'
-N --name save or restore original file name and time stamp
-n --no-name don't save original file name or time stamp
%> gzip -V
Apple gzip 272
使用-n选项:
%> tar cv foo/ | gzip -n > foo.tgz; shasum foo.tgz # sha256sum on Ubuntu
您将始终得到相同的哈希值
尝试上面不带-n的内容,您每次都会看到不同的散列。我成功地使用
-X
(--无额外的)标志创建了具有相同SHA1的文件
我创建了一个文件夹和几个要压缩的文件来测试它,正如预期的那样,每次都会得到不同的SHA1哈希:
$ mkdir stuff
$ echo "Stuff 1" > stuff/stuff1.txt
$ echo "Stuff 2" > stuff/stuff2.txt
$ zip -r stuff.zip stuff/
adding: stuff/ (stored 0%)
adding: stuff/stuff1.txt (stored 0%)
adding: stuff/stuff2.txt (stored 0%)
$ shasum stuff.zip
1c8be43ac859bb57603be1243da14022710d22bd stuff.zip
$ shasum stuff.zip
1c8be43ac859bb57603be1243da14022710d22bd stuff.zip
$ zip -r stuff.zip stuff/
updating: stuff/ (stored 0%)
updating: stuff/stuff1.txt (stored 0%)
updating: stuff/stuff2.txt (stored 0%)
$ shasum stuff.zip
73920362d0f7de74d87286502e03e7126fdc0a6a stuff.zip
但是,使用-X
在连续压缩后得到相同的哈希值:
$ zip -r -X stuff.zip stuff/
updating: stuff/ (stored 0%)
updating: stuff/stuff1.txt (stored 0%)
updating: stuff/stuff2.txt (stored 0%)
$ shasum stuff.zip
1ed228b16d1ee803f26a8b1419f2eb3bf7fcb9f5 stuff.zip
$ zip -r -X stuff.zip stuff/
updating: stuff/ (stored 0%)
updating: stuff/stuff1.txt (stored 0%)
updating: stuff/stuff2.txt (stored 0%)
$ shasum stuff.zip
1ed228b16d1ee803f26a8b1419f2eb3bf7fcb9f5 stuff.zip
我没有时间深入研究,并找出哪些额外的信息是造成差异弹出在第一种情况下,但这可能会有助于有人试图解决它。也仅在macOS 10.12.6上测试。使用下面的脚本创建确定性zip或jar文件
#/bin/bash
用法(){
echo“用法:./createDeterministicArtifact.sh”
出口1
}
信息(){
回音“$1”
}
条状伪影(){
如果[-z${file}];则
使用
fi
如果[-f${file}-a-s${file}];则
mkdir-p${file}.tmp
解压-oq-d${file}.tmp${file}
查找${file}.tmp-follow-exec touch-a-m-t 201912010000.00{}\+
如果[“$UNAME”==“Linux”];则
查找${file}.tmp-follow-exec chattr-a{}\+
elif[“$UNAME”==CYGWIN*| |“$UNAME”==MINGW*];然后
查找${file}.tmp-follow-exec attrib-A{}\+
fi
cd${file}.tmp
zip-rq-D-X-9-A——压缩方法deflate../${file}.new。
光盘-
rm-rf${file}.tmp
info“重新创建的确定性工件:${file}.new”
其他的
信息“输入文件为空。请验证该文件并重试”
fi
}
文件=$1
条状伪影
两件事。首先,似乎zip文件本身可能包含在zip中,因为它位于同一目录中,这可能会产生不确定的结果。第二,zip可能包含不同于运行的日期和时间。zip文件未包含在新生成的zip中,我在发布问题之前检查了一下。没错,zip存档包含不同的文件信息,包括文件修改时间(对于unix-文件权限、所有者、创建时间和事件访问时间)。这是一个正确的答案,但如果您告诉用户它是做什么的,以及它如何解决问题,则会很有帮助。在gzip帮助中“-n--压缩时没有名称,默认情况下不要保存原始文件名和时间戳…”保存的原始文件名会影响哈希值。-X
标志可能适用于同一文件的连续压缩,但不适用于具有相同名称和内容的两个文件,甚至不适用于具有修改的访问时间的同一文件。