git可以将zip文件作为目录和zip文件中的文件视为blob吗?

时间:2011-11-03 20:48:32

标签: git zip msysgit

方案

想象一下,我被迫使用一些始终存储在.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文件中的文件。但是,我认为这可以通过配置选项来解决。

两个想法如何完成(如果它还没有存在)

  • 在git
  • 中使用minizipIO::Compress::Zip等库
  • 以某种方式添加文件系统层,以便git实际上将zip文件视为以
  • 开头的目录

8 个答案:

答案 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的想象。

有关详细信息和原型设计代码,请阅读以下链接:

Zippey Git file filter

此外,相信这个激发了我这个解决方案的地方: 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)

我认为您需要将zip文件挂载到文件系统。我没有用它,但考虑FUSE:

http://code.google.com/p/fuse-zip/

Windows和Linux也有ZFS:

http://users.telenet.be/tfautre/softdev/zfs/

答案 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
    *~
    
  • 一些配置:

    1. 安装Git LFS
    2. 通过发出一次命令 git lfs install 来准备 LFS。
    3. 通过发出命令 git config core.hooksPath .githooks 安装钩子。
    4. 通过发出命令 .githooks/post-checkout 应用一次结帐挂钩。
    5. 通过发出命令 git add -A 应用一次过滤器。

示例见此处:https://github.com/vivi90/git-zip

2021 年 3 月 14 日和 16 日的重要错误修复

请按如下方式编辑您的提交挂钩(对我来说.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)

RezipZippey 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部分是为了使这些文件实际上显示为差异中的文本文件。