Может ли git обрабатывать zip-файлы как каталоги, а файлы внутри zip-архива - как капли?

Сценарий

Представьте, что я вынужден работать с некоторыми из моих файлов, которые всегда хранятся внутри .zip файлов. Некоторые из файлов внутри zip-архива представляют собой небольшие текстовые файлы и часто меняются, в то время как другие больше, но, к счастью, довольно статичны (например, изображения).

Если я хочу поместить эти zip-файлы в git репозиторий, каждый zip будет рассматриваться как blob, поэтому всякий раз, когда я фиксирую, репозиторий увеличивается на размер zip-файла ... даже если внутри был изменен только один небольшой текстовый файл!

Почему это реально

Файлы MS Word 2007/2010 .docx и Excel .xlsx представляют собой файлы ZIP ...

Чего я хочу

Есть ли случайно способ указать git не обрабатывать zip-архивы как файлы, а скорее как каталоги и рассматривать их содержимое как файлы?

Преимущества

Но вы говорите, что это не сработает?

Я понимаю, что без дополнительных метаданных это привело бы к некоторой двусмысленности: на git checkout git пришлось бы решать, создавать ли foo.zip/bar.txt как файл в обычном каталоге или как zip-файл. Однако я думаю, это можно решить с помощью параметров конфигурации.

Две идеи, как это можно сделать (если такового еще нет)

  • используя библиотеку, такую ​​как minizip или IO::Compress::Zip внутри git
  • каким-то образом добавляя слой файловой системы, чтобы git фактически видел zip-файлы как каталоги, чтобы начать с

person Jonas Heidelberg    schedule 03.11.2011    source источник
comment
Сценарий с .docx файлами имеет смысл, но во многих других случаях вы можете рассмотреть возможность отслеживания отдельных файлов, как правило, с помощью git и только построения результирующего .zip с помощью соответствующего инструмента сборки, такого как make.   -  person pixelistik    schedule 28.11.2013
comment
Учитывая, что два zip-файла, которые выглядят по-разному, могут содержать одни и те же данные (например, текстовый файл, заархивированный два раза с двумя разными уровнями сжатия), это становится намного сложнее. Хотя легко представить разницу между двумя версиями распакованных файлов с небольшим количеством информации, я предполагаю, что представление разницы между двумя версиями архива (что, по сути, то, что должен делать git), с минимальным количеством информации было бы не -тривиально.   -  person HelloGoodbye    schedule 23.12.2013
comment
Вы когда-нибудь получали реализованное решение ответа Джеффа или что-то еще? Мне интересно, в основном то же самое, за исключением для архивов tar, что должно дать совместимый ответ ...   -  person Tobias Kienzler    schedule 03.05.2016
comment
Инструмент дизайна информации (IDT) SAP создает аналогичную файловую структуру для своего формата UNX. Он также рекурсивен: он содержит BLX файл и DFX файл, которые являются архивами, которые соответствуют «бизнес-уровню» и «основанию данных» соответственно. Я тоже хотел бы найти решение.   -  person craig    schedule 03.03.2017
comment
Встроенная VCS Jetbrains позволяет вам просматривать файлы zip-типа. Очень полезно, но требует от вас обзора, например, PR внутри IDE. Теперь, когда Microsoft взяла на себя управление, мы можем увидеть это и в github pr diff.   -  person vincent    schedule 21.09.2018


Ответы (8)


Этого не существует, но он мог бы легко существовать в текущей структуре. Так же, как git по-разному работает с отображением двоичных файлов или файлов ascii при выполнении сравнения, ему можно было бы предложить особую обработку определенных типов файлов через интерфейс конфигурации.

Если вы не хотите менять кодовую базу (хотя это неплохая идея), вы также можете написать сценарий для себя, используя хуки перед фиксацией и после оформления заказа, чтобы распаковать и сохранить файлы, а затем вернуть их в состояние .zip при оформлении заказа. Вам придется ограничить действия только теми файлами blobs / indexes, которые указаны в git add.

В любом случае придется немного поработать - вопрос лишь в том, знают ли другие команды git о том, что происходит, и хорошо ли играют.

person Jeff Ferland    schedule 03.11.2011
comment
Кажется, что крючки - хорошее направление, в которое можно заглянуть; Я кратко подумал об этом, но не был уверен, сработает ли это. Хук предварительной фиксации может изменять как файловую систему, так и промежуточную область? - person Jonas Heidelberg; 04.11.2011
comment
@Jonas Вы когда-нибудь этим занимались, и есть ли шанс, что вы опубликуете работающее решение? Я хотел бы с пользой отслеживать изменения в таблицах в git, а CSV просто не подходит для наших целей. - person Ruben; 13.11.2013
comment
Обратите внимание, что при использовании сценариев, которые будут распаковывать заархивированные файлы перед их фиксацией в репозиторий и снова сжимать файлы при извлечении, фиксация, сразу за которой следует извлечение, вероятно, изменит архивы, даже если файлы, хранящиеся внутри архива, останутся неизменными. . - person HelloGoodbye; 23.12.2013
comment
Я просто написал несколько хуков для этого. Все еще работаю над грубыми краями, но может быть полезно: github.com/ckrf/xlsx-git - person katriel; 24.04.2015

Zippey - решение, использующее фильтр файлов git

Мое решение - использовать фильтр, чтобы превратить zip-файл в монолитный расширенный (возможно, огромный) текстовый файл. В течение _1 _ / _ 2_ zip-файл будет автоматически расширен до этого текстового формата для обычного сравнения текста, а во время оформления заказа он снова автоматически архивируется.

Текстовый файл состоит из записей, каждая из которых представляет собой файл в zip-архиве. Таким образом, вы можете думать, что этот текстовый файл представляет собой текстовое изображение для исходного zip-архива. Если файл в zip-архиве действительно текстовый, он копируется в текстовый файл; в противном случае он кодируется в base64 перед копированием в файл текстового формата. При этом текстовый файл всегда остается текстовым файлом.

Хотя этот фильтр не превращает каждый файл в zip-архиве в большой двоичный объект, текстовые файлы сопоставляются построчно, что является единицей сравнения, в то время как изменения двоичных файлов могут быть представлены обновлениями соответствующих им base64. Я думаю, что это эквивалентно тому, что представляет себе ОП.

Для получения подробной информации и кода прототипа вы можете прочитать следующую ссылку:

Фильтр файлов Zippey Git

Также благодарю место, которое вдохновило меня на это решение: Описание того, как файловый фильтр работает

person Sippey    schedule 18.04.2014
comment
Этот фильтр все еще находится в разработке, если у вас есть вопросы или предложения, дайте мне знать. - person Sippey; 18.04.2014
comment
Я попробовал это и считаю, что мне это должно хорошо сработать. Я бы просто добавил кое-что в документацию, что список текстовых файлов zippey.py должен быть изменен, чтобы включить любые типы файлов, которые вы хотите, чтобы zippey.py распознавал как текстовые файлы. - person mteng; 22.11.2014
comment
Такие огромные файлы несовместимы со многими инструментами. Я особенно думаю о лимите github 50 МБ - person PPC; 19.04.2018
comment
Я не поклонник монолитного файла, потому что он создает слишком большой файл, чтобы его можно было отправить в github (100 МБ), и не позволяет точное отслеживание - person PPC; 26.06.2018
comment
Стоит отметить, что в вашем репозитории нет LICENSE файла или чего-либо подобного. Нет лицензии = все права защищены. - person user5532169; 16.11.2018
comment
небольшие улучшения в zippey в моем репо - person hoijui; 28.02.2019

Используйте bup (подробно описано в GitMinutes # 24)

Это единственная git-подобная система, предназначенная для работы с большими (даже очень очень большими) файлами, что означает, что каждая версия zip-файла будет увеличивать репо только от его дельты (вместо полной дополнительной копия)

Результатом является фактическое репозиторий git, который может прочитать обычная команда Git.

Я подробно описываю, чем bup отличается от Git, в «git с большими файлами».


Любой другой обходной путь (например, git-annex) не совсем удовлетворителен, поскольку подробно описано в «git-annex с большими файлами».

person VonC    schedule 21.11.2013
comment
Это похоже на очень большие файлы, сценарий был больше ориентирован на XML, такой как docx и xlsx (которые часто довольно малы) заархивированы. Вы получите меньший размер репо с помощью bup, но сможете ли вы различать фактические изменения в XML? - person Ruben; 21.11.2013
comment
@Ruben предназначен для файлов большого размера или количества. Но с точки зрения diff он не сильно отличается от git. - person VonC; 21.11.2013
comment
Выглядит интересно, но можете ли вы использовать его с вашим настоящим репозиторием git? - person kutschkem; 20.03.2015
comment
@kutschkem Я так не думаю: репозиторий bup - это репозиторий git (raw.githubusercontent .com / bup / bup / master / DESIGN), но обратное, похоже, неверно. - person VonC; 20.03.2015

http://tante.cc/2010/06/23/managing-zip-based-file-formats-in-git/

(Примечание: согласно комментарию Рубена, речь идет только о получении правильного различия, а не о фиксации разархивированных файлов.)

Откройте ваш файл ~ / .gitconfig (создайте, если он еще не существует) и добавьте следующую строфу:

[diff "zip"] textconv = unzip -c -a

Он использует «unzip -c -a FILENAME» для преобразования вашего zip-файла в текст ASCII (unzip -c распаковывает в STDOUT). Далее необходимо создать / изменить файл REPOSITORY / .gitattributes и добавить следующие

* .pptx diff = zip

который сообщает git использовать описание zip-diff из конфигурации для файлов, соответствующих данной маске (в данном случае все, что заканчивается на .pptx). Теперь git diff автоматически распаковывает файлы и сравнивает вывод ASCII, что немного лучше, чем просто «двоичные файлы отличаются». С другой стороны, по сравнению с запутанным беспорядком, который представляет собой соответствующий XML-файл pptx, он не очень помогает, но для ZIP-файлов, включая текст (например, архивы исходного кода), это действительно очень удобно.

person Community    schedule 28.11.2013
comment
Речь идет только о правильном различии, а не о фиксации разархивированных файлов .. - person Ruben; 28.11.2013
comment
Спасибо. Это отвечает на вопрос, который я хотел решить, об отображении изменений текстовых файлов внутри моих файлов gzip при git diffing. Я использовал [diff "gzip"] = zcat и *.gz diff=gzip. - person spazm; 31.01.2017

Повторно заархивировать ReZipDoc, аналогично Zippey by sippey, позволяет обрабатывать ZIP файлы лучше с помощью git.

Как это работает

При добавлении / фиксации файла на основе ZIP Rezip распаковывает его и переупаковывает без сжатия перед добавлением в индекс / фиксацию. В несжатом ZIP-файле заархивированные файлы отображаются как есть по своему содержанию (вместе с некоторой двоичной метаинформацией перед каждым файлом). Если эти заархивированные файлы представляют собой текстовые файлы, этот метод будет хорошо работать с git.

Преимущества

Основное преимущество Rezip по сравнению с Zippey заключается в том, что фактический файл, хранящийся в репозитории, по-прежнему является файлом ZIP. Таким образом, во многих случаях он по-прежнему будет работать как есть с соответствующим приложением (например, Open Office), даже если он получен без прохождения фильтра повторной упаковки со сжатием.

Как пользоваться

Установите фильтр (ы) в вашу систему:

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 предназначена для того, чтобы эти файлы фактически отображались как текстовые файлы в различиях.

person hoijui    schedule 28.02.2019
comment
Звучит действительно круто! У меня не было необходимости в этом какое-то время, поэтому я так и не дошел до реализации чего-то, но это определенно было бы тем, что я бы попробовал. - person Jonas Heidelberg; 06.01.2020

Вот мой подход:

  • Использование фильтров 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 <[email protected]>
    # 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 <[email protected]>
    # 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. Install Git LFS
    2. Подготовьте LFS, выполнив команду git lfs install один раз.
    3. Установите перехватчики, введя команду git config core.hooksPath .githooks.
    4. Примените обработчик оформления заказа один раз, введя команду .githooks/post-checkout.
    5. Примените фильтр один раз, введя команду git add -A.

Пример см. Здесь: https://github.com/vivi90/git-zip

Важные ИСПРАВЛЕНИЯ ОШИБОК с 14 по 16 марта 2021 г.

Пожалуйста, отредактируйте хук фиксации (для меня .githooks/pre-commit) следующим образом:

#!/bin/sh
#
# Git archive extraction pre commit hook
#
# Created: 2021 by Vivien Richter <[email protected]>
# 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

Известные проблемы

person Sukombu    schedule 08.03.2021
comment
довольно баллистический ответ, спасибо, что поделились этим. - person ipatch; 21.04.2021

Я думаю, вам нужно будет смонтировать zip-файл в файловую систему. Я не использовал его, но подумайте о FUSE:

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

Также существует ZFS для Windows и Linux:

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

person Brad    schedule 03.11.2011
comment
Если я правильно понимаю, fuse-zip может располагаться между файловой системой и git, но zfs нужно будет встроить в git, верно? Жаль, что я не всегда использую Linux с этим репо, иначе fuse-zip был бы действительно хорошей идеей. - person Jonas Heidelberg; 04.11.2011

Часто возникают проблемы с предварительно заархивированными файлами для приложений, поскольку они ожидают, что метод сжатия zip и порядок файлов будут теми, которые они выбрали. Я считаю, что эта проблема есть в файлах Open Office .odf.

Тем не менее, если вы просто используете any-old-zip как метод для хранения вещей, вы должны иметь возможность создать несколько простых псевдонимов, которые будут распаковываться и повторно заархивироваться при необходимости. Самый последний Msysgit (он же Git для Windows) теперь имеет как zip, так и unzip на стороне кода оболочки, поэтому вы можете использовать их в псевдонимах.

Проект, над которым я сейчас работаю, использует zip-архивы в качестве основного локального управления версиями / архива, поэтому я также пытаюсь получить работоспособный набор псевдонимов для втягивания этих сотен zip-архивов в git (и их повторного извлечения ;-), поэтому что коллеги счастливы.

person Philip Oakley    schedule 03.11.2011
comment
Я только что провел несколько тестов для Word 2010 - он кажется вполне терпимым (deflate с разными размерами слов, deflate64 и изменение порядка файлов в zip-файле, созданном 7zip, - все это не сбрасывает Word). Что касается использования псевдонимов, я надеялся избежать каких-либо дополнительных действий вручную ... в настоящее время большинство моих коммитов проходят через TortoiseGit. - person Jonas Heidelberg; 04.11.2011