方案
想象一下,我被迫使用一些始终存储在.zip
文件中的文件。 zip中的一些文件是小文本文件并且经常更改,而其他文件更大但幸运的是相当静态(例如图像)。
如果我想将这些zip文件放在git
存储库中,每个zip都被视为一个blob,所以每当我提交存储库时,就会增加zip文件的大小...即使只有一个小的里面的文字文件改了!
为什么这是现实的
MS Word 2007/2010 .docx
和Excel .xlsx
文件是ZIP文件...
我想要什么
是否有任何机会告诉git
不将zips视为文件,而是将其作为目录处理并将其内容视为文件?
优点
但它说不行吗?
我意识到如果没有额外的元数据,这将导致一些歧义:在git checkout
git上必须决定是否将foo.zip/bar.txt
创建为常规目录或zip文件中的文件。但是,我认为这可以通过配置选项来解决。
两个想法如何完成(如果它还没有存在)
minizip
或IO::Compress::Zip
等库
答案 0 :(得分:21)
这不存在,但它可以很容易地存在于当前框架中。正如git在执行diff时显示二进制或ascii文件的行为不同,可以通过配置界面告诉它对某些文件类型提供特殊处理。
如果您不想更改代码库(虽然这是一个很酷的想法),您也可以使用pre-commit and post-checkout hooks解压缩并自行编写脚本。存储文件,然后在结帐时将它们返回到.zip状态。您必须将操作限制为仅由git add
指定的那些文件blob / index。
无论哪种方式都有点工作 - 这只是一个问题,即其他git表示是否知道发生了什么,并且发挥得很好。
答案 1 :(得分:12)
不确定是否有人仍然对这个问题感兴趣。我面临同样的问题,这是我使用git文件过滤器的解决方案。
编辑: 首先,我可能不会说清楚,但这 IS 是OP问题的答案!在评论之前阅读整个句子。此外,感谢@Toon Krijthe提供的建议,以澄清解决方案。
我的解决方案是使用过滤器来平放"将zip文件转换为单片扩展(可能是巨大的)文本文件。在git add / commit期间,zip文件将自动扩展为此文本格式以进行正常的文本区分,并且在结帐时,它会自动再次压缩。
文本文件由记录组成,每个记录代表zip中的文件。所以你可以认为这个文本文件是原始zip的基于文本的图像。如果zip中的文件是契约中的文本,则将其复制到文本文件中;否则,在复制到文本格式文件之前,它是base64编码的。这使文本文件始终保持为文本文件。
虽然这个过滤器不会使zip中的每个文件成为blob,但是文本文件是逐行映射的,这是diff的单位,而二进制文件的更改可以通过更新它们对应的base64来表示,我想这个相当于OP的想象。
有关详细信息和原型设计代码,请阅读以下链接:
此外,相信这个激发了我这个解决方案的地方: Description of how file filter works
答案 2 :(得分:11)
使用 bup (在GitMinutes #24中详细介绍)
它是唯一一个用于处理大型(甚至非常非常大)文件的类似git的系统,这意味着每个版本的zip文件只会增加其delta的repo(而不是完整的附加副本)
结果是一个实际的git repo,一个普通的Git命令可以读取。
我详细说明了 bup
与“git with large files”中Git的区别。
任何其他解决方法(例如 git-annex
)并不完全令人满意,详见“git-annex
with large files”。
答案 3 :(得分:5)
http://tante.cc/2010/06/23/managing-zip-based-file-formats-in-git/
(注意:来自Ruben的评论,这只是关于获得正确的差异,而不是关于提交解压缩的文件。)
打开你的〜/ .gitconfig文件(如果已经存在则创建)并添加 以下节:
[diff“zip”] textconv = unzip -c -a
它的作用是使用“unzip -c -a FILENAME”来转换你的zip文件 到ASCII文本(解压缩-c解压缩到STDOUT)。接下来是 创建/修改文件REPOSITORY / .gitattributes并添加以下内容
* .pptx diff = zip
告诉git使用配置中的zip-diffing描述 计算给定掩码的文件(在这种情况下,所有内容都以 .PPTX)。现在git diff自动解压缩文件并对其进行差异化 ASCII输出比“二进制文件不同”好一点。 另一方面,给相应的XML弄乱了 pptx文件是,它没有帮助很多,但对ZIP文件包括 文本(例如源代码档案)这实际上是相当的 方便。
答案 4 :(得分:2)
答案 5 :(得分:2)
通常,应用程序的预压缩文件存在问题,因为他们希望zip压缩方法和文件顺序是他们选择的。我相信开放式办公.odf文件存在这个问题。
也就是说,如果你只是使用any-old-zip作为保持一起的方法,你应该能够创建一些简单的别名,这些别名将在需要时解压缩并重新压缩。最新的Msysgit(又名Git for Windows)现在在shell代码端都有zip和unzip,所以你可以在别名中使用它们。
我目前正在开发的项目使用zip作为主要的本地版本控制/存档,所以我也试图获得一组可行的别名,用于将这些数百个zips吸入git(并再次将它们取出; - )让同事们感到高兴。
答案 6 :(得分:2)
这是我的方法:
使用 git diff 过滤器将存档文件替换为内容摘要
git config filter.zip.clean "unzip -v %f | tail -n +4 | head -n -2 | awk '{ print \$7,\$8 }' | grep -vE /$ | sort -k 2"
git config filter.zip.smudge "unzip -v %f | tail -n +4 | head -n -2 | awk '{ print \$7,\$8 }' | grep -vE /$ | sort -k 2"
使用 pre-commit
钩子提取和添加存档内容:
#!/bin/sh
#
# Git archive extraction pre commit hook
#
# Created: 2021 by Vivien Richter <vivien-richter@outlook.de>
# License: CC-BY-4.0
# Version: 1.0.0
# Configuration
ARCHIVE_EXTENSIONS=$(cat .gitattributes | grep "zip" | tr -d [][:upper:] | cut -d " " -f1 | cut -d. -f2 | head -c -1 | tr "\n" "|")
# Processing
for STAGED_FILE in $(git diff --name-only --cached | grep -iE "\.($ARCHIVE_EXTENSIONS)$")
do
if [ ! -f "$STAGED_FILE" ]; then
# Deletes the archive content, if the archive itself is removed
rm -r ".$(basename $STAGED_FILE).content"
else
# Extracts archives
unzip -o $STAGED_FILE -d ".$(basename $STAGED_FILE).content"
fi
# Adds extracted or deleted archive content to the stage
git add ".$(basename $STAGED_FILE).content"
done
使用 post-checkout
钩子再次打包存档以供使用:
#!/bin/sh
#
# Git archive packing post checkout hook
#
# Created: 2021 by Vivien Richter <vivien-richter@outlook.de>
# License: CC-BY-4.0
# Version: 1.0.0
# Configuration
ARCHIVE_EXTENSIONS=$(cat .gitattributes | grep "zip" | tr -d [][:upper:] | cut -d " " -f1 | cut -d. -f2 | head -c -1 | tr "\n" "|")
# Processing
for EXTRACTED_ARCHIVE in $(git ls-tree -dr --full-tree --name-only HEAD | grep -iE "\.($ARCHIVE_EXTENSIONS)\.content$")
do
# Gets filename
FILENAME=$(dirname $EXTRACTED_ARCHIVE)/$(basename $EXTRACTED_ARCHIVE | cut -d. -f2- | awk -F '.content' '{ print $1 }')
# Removes the dummy archive file
rm $FILENAME
# Jumps into the extracted archive
cd $EXTRACTED_ARCHIVE
# Creates the real archive file
zip -r9 ../"$FILENAME" $(find . -type f)
# Jumps back
cd ..
done
在 .gitattributes
文件中应用过滤器:
# Macro for all file types that should be treated as ZIP archives.
[attr]zip filter=zip
# OpenDocument
*.[oO][dD][tT] zip
*.[oO][dD][sS] zip
*.[oO][dD][gG] zip
*.[oO][dD][pP] zip
*.[oO][dD][mM] zip
# Krita
*.[kK][rR][aA] zip
# VRoid Studio
*.[vV][rR][oO][iI][dD] zip
*.[fF][vV][pP] zip
向 .gitattributes
文件添加一些二进制处理:
# Macro for all binary files that should use Git LFS.
[attr]bin -text filter=lfs diff=lfs merge=lfs lockable
# Images
*.[jJ][pP][gG] bin
*.[jJ][pP][eE][gG] bin
*.[pP][nN][gG] bin
*.[aA][pP][nN][gG] bin
*.[gG][iI][fF] bin
*.[bB][mM][pP] bin
*.[tT][gG][aA] bin
*.[tT][iI][fF] bin
*.[tT][iI][fF][fF] bin
*.[sS][vV][gG][zZ] bin
向 .gitignore
文件添加一些内容:
# Auto generated LFS hooks
.githooks/pre-push
# Temporary files
*~
一些配置:
git lfs install
来准备 LFS。git config core.hooksPath .githooks
安装钩子。.githooks/post-checkout
应用一次结帐挂钩。git add -A
应用一次过滤器。示例见此处:https://github.com/vivi90/git-zip
请按如下方式编辑您的提交挂钩(对我来说.githooks/pre-commit
):
#!/bin/sh
#
# Git archive extraction pre commit hook
#
# Created: 2021 by Vivien Richter <vivien-richter@outlook.de>
# License: CC-BY-4.0
# Version: 1.0.2
# Configuration
ARCHIVE_EXTENSIONS=$(cat .gitattributes | grep "zip" | tr -d [][:upper:] | cut -d " " -f1 | cut -d. -f2 | head -c -1 | tr "\n" "|")
# Processing
for STAGED_FILE in $(git diff --name-only --cached | grep -iE "\.($ARCHIVE_EXTENSIONS)$")
do
# Deletes the old archive content
rm -rf ".$(basename $STAGED_FILE).content"
# Extracts the archive content, if the archive itself is not removed
if [ -f "$STAGED_FILE" ]; then
unzip -o $STAGED_FILE -d "$(dirname $STAGED_FILE)/.$(basename $STAGED_FILE).content"
fi
# Adds extracted or deleted archive content to the stage
git add "$(dirname $STAGED_FILE)/.$(basename $STAGED_FILE).content"
done
答案 7 :(得分:1)
Rezip与Zippey by sippey类似,允许使用git以更好的方式处理ZIP文件。
添加/提交基于ZIP的文件时,在将其添加到索引/提交之前,Rezip将其解压缩并重新打包而不进行压缩。在未压缩的ZIP文件中, 归档文件的内容会按原样显示( )(以及每个文件之前的一些二进制元信息)。如果这些归档文件是纯文本文件,则此方法在git上可以很好地播放。
与Zippey相比,Rezip的主要优点在于,存储在存储库中的实际文件仍然是ZIP文件。因此,在很多情况下,即使未经过压缩后重新打包过滤器就获得了它,也可以在相应的应用程序(例如Open Office)上按原样工作。 / p>
在系统上安装过滤器:
mkdir -p ~/bin
cd ~/bin
# Download the filer executable
wget https://github.com/costerwi/rezip/blob/master/Rezip.class
# Install the add/commit filter
git config --global --replace-all filter.rezip.clean "java -cp ~/bin Rezip --store"
# (optionally) Install the checkout filter
git config --global --add filter.rezip.smudge "java -cp ~/bin Rezip"
在您的<repo-root>/.gitattributes
文件中添加以下行,从而使用存储库中的过滤器:
[attr]textual diff merge text
[attr]rezip filter=rezip textual
# MS Office
*.docx rezip
*.xlsx rezip
*.pptx rezip
# OpenOffice
*.odt rezip
*.ods rezip
*.odp rezip
# Misc
*.mcdx rezip
*.slx rezip
textual
部分是为了使这些文件实际上显示为差异中的文本文件。