Мне было интересно, есть ли хорошее решение "git export", которое создает копию дерева без каталога репозитория .git
. Я знаю как минимум три метода:
git clone
с последующим удалением каталога репозитория .git
.git checkout-index
намекает на эту функциональность, но начинается со слов «Просто прочтите желаемое дерево в индекс ...», что я не совсем уверен, как это сделать.git-export
- это сторонний сценарий, который, по сути, переводит git clone
во временное местоположение, а затем rsync --exclude='.git'
в конечный пункт назначения.Ни одно из этих решений не кажется мне удовлетворительным. Ближайшим к svn export
может быть вариант 1, потому что оба требуют, чтобы целевой каталог был сначала пустым. Но вариант 2 кажется даже лучше, если предположить, что я могу понять, что значит читать дерево в индексе.
@mrTom git archive --format zip --output "output.zip" master -0
предоставит вам несжатый архив (-0 - флаг для несжатого). git-scm.com/docs/git-archive.
Я согласен с @mrTom и не думаю, что сжатый или несжатый архив является главной проблемой. С SVN я могу export
подкаталог 250 КБ прямо из удаленного репозитория (который в противном случае мог бы иметь размер 200 МБ, без учета ревизий) - и я попаду в сеть только для передачи загрузки 250 КБ (или около того). С git
, archive
должен быть включен на сервере (поэтому я не могу его попробовать) - clone --depth 1
с сервера все еще может получить репо размером, скажем, 25 МБ, тогда как подпапка .git
занимает 15 МБ. Поэтому я все равно отвечу «нет».
@mrTom ответ на самом деле ДА См. ответ OP - команда git checkout-index
Вот хороший и простой способ: git archive -o latest.zip HEAD
Использование git-checkout-index для «экспорта всего дерева»
Возможность префикса в основном упрощает использование git-checkout-index в качестве функции «экспорта в виде дерева». Просто прочтите нужное дерево в индексе и выполните:
$ git checkout-index --prefix=git-export-dir/ -a
Думаю, путаница заключается в словосочетании «прочитать желаемое дерево в индексе».
Если вы хотите экспортировать каталог foo в панели веток, тогда это будет git read-tree bar:foo
, а затем git checkout-index --prefix=export_dir/ -a
, после этого, возможно, вам следует сделать git update-index master
@JohnWeldon Требуется ли сначала клонировать репо? Если так, то я бы не принял это, так как весь смысл "svn export" подкаталога состоит в том, чтобы напрямую получить копию этого подкаталога; Если у кого-то есть репозиторий Git размером 1 ГБ, а все, что мне нужно, это подкаталог размером 10 КБ, безумие требовать от меня клонирования всего этого.
Также я бы повторил @ davetron5000 с комментарием «прочтите желаемое дерево в индекс», который я не понимаю, что это значит.
Выяснил, что означает вариант 2. Из репозитория вы можете:
git checkout-index -a -f --prefix=/destination/path/
Косая черта в конце пути важна, иначе это приведет к тому, что файлы будут находиться в / назначении с префиксом «путь».
Поскольку в нормальной ситуации индекс содержит содержимое репозитория, нет ничего особенного, чтобы «прочитать желаемое дерево в индекс». Это уже есть.
Флаг -a
требуется для проверки всех файлов в индексе (я не уверен, что значит опустить этот флаг в этой ситуации, поскольку он не делает того, что я хочу). Флаг -f
принудительно перезаписывает любые существующие файлы в выводе, чего эта команда обычно не делает.
Это похоже на то, что я искал.
... и НЕ ЗАБУДЬТЕ СЛЭШ В КОНЦЕ, иначе у вас не будет желаемого эффекта;)
Разве индекс не является просто названием «промежуточной» области? Как так получилось, что дерево уже там? Я думал, что вы можете добавлять в него только вручную с помощью git add
Команда git add
изменяет содержимое индекса, поэтому все, что git status
показывает как «должно быть зафиксировано», является различия между HEAD и содержимым индекса.
похоже, что это эквивалент git archive HEAD
@conny: прочитайте ваш комментарий, забыл об этом и запустил команду без косой черты. совет: следуйте совету Конни -.-
Я тоже люблю убирать другие [хлам] [1]. Например, я также удаляю файл .gitignore
, поскольку он, вероятно, не будет иметь отношения к каким-либо будущим разработчикам программного обеспечения. [1]: en.wikipedia.org/wiki/Cruft
И, по-видимому, я не правильно понял синтаксис в моем комментарии выше для ссылки на термин "крутой" в Википедии. Извиняюсь!
+1 к совету Конни. Кроме того, не пытайтесь создать '~ / dest /', так как это создаст каталог с именем '~' в вашем рабочем каталоге, а не то, что вы действительно хотели. Угадайте, что происходит, когда вы бездумно набираете rm -rf ~
Причина использования флага '-a' описана на странице руководства для git-checkout-index. Он утверждает, что git-checkout-index часто принимает аргументы, а иногда отсутствие аргументов означает, что ничего не делать. Если вы запустите man git-checkout-index
и выполните поиск по запросу «Интуитивность здесь не цель». вы увидите то, о чем я говорю.
Этот метод не принимает тег или любую другую ссылку на ревизию. По общему признанию, необходимость указывать тег была более важной для CVS, поскольку кто-то другой мог изменить удаленный репозиторий. Еще одно предостережение: вышеуказанный метод будет экспортировать файлы из index. То есть, если что-то планируется зафиксировать, это будет экспортировано.
@KyleHeironimus - ваше предупреждение об использовании '~ / dest / `истинно, если вы используете кавычки вокруг вашего префиксного пути, которые говорят оболочке не выполнять раскрытие тильды. В вашем рабочем каталоге будет создан каталог с именем ~
(не '~'
!). В этом отношении в git checkout-index
нет ничего особенного: то же самое и с mkdir '~/dest'
(не делай этого!). Еще одна веская причина избегать имен файлов, которые нужно цитировать (например, в которых есть пробел) :-)
Я не видел, чтобы другие упоминали, что если каталог / пункт назначения / путь / еще не существует, вам необходимо его создать, поскольку git не сделает этого за вас и ничего не будет делать, если не найдет его.
@MattWallis: использование этого подхода в Windows с «Git Bash», включенным в клиент, доступный на git-scm.com, расширение тильды не работает, хотя bash использует тильду как часть приглашения. Это не связано с использованием кавычек в имени пути. в Rich: В этом же самом сценарии любая выходная папка создавалась по запросу.
@takeshin Это не совсем то же самое, что git archive HEAD
: git checkout-index ...
копирует все файлы из индекса, а archive
архивирует файлы из локального репозитория. Они случайно сделают то же самое, если индекс пуст.
Будет ли git checkout-index
пытаться повторно использовать существующие файлы аналогично тому, как это делает обычный checkout
(например, избегать копирования файлов с ожидаемой меткой времени и размером)?
На самом деле я бы предпочел иметь цель расстояние в вашем Makefile (или другой системе сборки), которая экспортирует распространяемый архив вашего кода (.tar.bz2, .zip, .jar или любой другой подходящий). Если вы используете GNU autotools или системы MakeMaker Perl, я думаю, что это существует для вас автоматически. Если нет, настоятельно рекомендую добавить его.
ETA (06.09.2012): Ого, резкие отрицательные голоса. Я по-прежнему считаю, что лучше создавать свои дистрибутивы с помощью инструментов сборки, а не инструмента управления исходным кодом. Я верю в создание артефактов с помощью инструментов сборки. В моей нынешней работе наш основной продукт построен на мишени-муравьях. Мы находимся в самом разгаре переключения систем управления исходным кодом, и наличие этой цели-муравья означает меньше хлопот при миграции.
Я имел в виду не проект кода; это больше похоже на проект веб-сайта.
Не отвечает на вопрос.
Да, такой ответ может не удовлетворить потребности всех, но отрицательные голоса очень странны. Это является полностью верный ответ и действительно во многих сценариях единственно правильный ответ. Это очень убедительно свидетельствует о том, что думать об этой проблеме как о «проблеме с инструментом vc» часто ведет совершенно неверный путь.
Вероятно, самый простой способ добиться этого - использовать git archive
. Если вам действительно нужно только развернутое дерево, вы можете сделать что-то вроде этого.
git archive master | tar -x -C /somewhere/else
В большинстве случаев, когда мне нужно «экспортировать» что-то из git, мне в любом случае нужен сжатый архив, поэтому я делаю что-то вроде этого.
git archive master | bzip2 >source-tree.tar.bz2
ZIP-архив:
git archive --format zip --output /full/path/to/zipfile.zip master
git help archive
для более подробной информации, он довольно гибкий.
Имейте в виду, что даже если архив не будет содержать каталог .git, он, тем не менее, будет содержать другие скрытые файлы, специфичные для git, такие как .gitignore, .gitattributes и т. д. Если вы не хотите, чтобы они были в архиве, убедитесь, что вы используйте атрибут export-ignore в файле .gitattributes и зафиксируйте его перед созданием архива. Подробнее...
Примечание. Если вас интересует экспорт индекса, используйте следующую команду:
git checkout-index -a -f --prefix=/destination/path/
(Подробнее см. Ответ Грега)
ZIP-архив: git archive --format zip --output /full/path master
Имейте в виду, что архив не будет содержать каталог .git, но будет содержать другие скрытые файлы, специфичные для git, такие как .gitignore, .gitattributes и т. д. Поэтому, если они вам не нужны, убедитесь, что вы используете атрибут export-ignore в файл .gitattributes и зафиксируйте его перед созданием архива. См. Feed.cloud.geek.nz/2010/02/…
Чтобы продолжить примечание Streams: вы можете добавить строку '--prefix = something /' в команду для управления именем каталога, который будет упакован внутри zip. Например, если вы используете git archive --format zip --output /path/to/file.zip --prefix=newdir/ master
, вывод будет называться «file.zip», но когда вы распаковываете его, каталог верхнего уровня будет «newdir». (Если вы опустите атрибут --prefix, каталог верхнего уровня будет 'file'.)
и в продолжение примечания @ anotherAlan: префикс - также работает для архивов tar - и в любом случае обязательно включите завершающий /, если вы ожидаете каталог!
Самый простой способ: git archive -o latest.zip HEAD
. Он создает Zip-архив, содержащий содержимое последней фиксации в текущей ветке. Обратите внимание, что выходной формат определяется расширением выходного файла.
Он не поддерживает подмодули git :(
Вы можете получить tar, выполнив "--format = tar --output = foo.tar", вам не нужно передавать его через tar. Фактически, согласно архиву справки git, формат tar используется по умолчанию, поэтому вам даже не нужно его указывать.
@Liam: Да, формат по умолчанию - tar
, поэтому вы может перенаправляете вывод прямо на tar -x
.
Для отдельных файлов может быть полезно перенаправить на стандартный вывод. например: git archive master some/file/name | tar -xO
(заглавная O
, а не ноль).
@ Чарльз Бейли: Интересно, почему вы выбрали это решение вместо клонирования + удаления git-папок. Есть ли у этого обратная сторона?
@ Яaffael1984: одна из причин сделать это с помощью метода clone & remove git-folder - это если вы хотите экспортировать репозиторий git в / поверх существующего каталога. git clone
не устраивает клонирование в непустой каталог.
Хотя это действительно работает и очень просто, есть большой недостаток, с которым я только что столкнулся. Это экспортирует все файлы из дерева и установит их метку времени на время последней фиксации git, вместо того, чтобы каждый файл сохранял свою собственную метку времени, она будет перезаписана меткой последнего зафиксированного файла. Затем это вызовет проблему для чего-то вроде rsync, если вы отправляете свои файлы на удаленный сервер, все файлы будут перенесены.
@jmoz: Это не лучший вариант использования git archive
. Если вас интересуют временные метки файлов в рабочем дереве, то более подходящим вариантом будет простой tar
, cp -pr
или локальный rsync
.
git archive --format zip --output "output.zip" master -0
предоставит вам несжатый архив (-0 - флаг для несжатого). git-scm.com/docs/git-archive
Хорошо, я добавил опцию zip в качестве псевдонима в ~/.gitconfig
[alias] zip = archive --format zip --output
. Использование: git zip ~/Desktop/app.zip master
Можно ли что-то подобное сделать? git archive -o ../{$GIT_DIR}.zip HEAD
Я хочу динамически сгенерировать имя zip-файла на основе имени репо или имени каталога.
Параметр --remote
позволяет создавать архив без предварительного клонирования.
Есть ли способ заархивировать только одну папку проекта?
Обратите внимание, что .tar = без сжатия (меньше накладных расходов) .tar.gz или bz2 означает файлы меньшего размера, но большую загрузку ЦП.
"хозяин" меня оттолкнул. Вы действительно имели в виду название папки для экспорта, верно? Я заменил это точкой.
Обратите внимание, что git archive
не является решением, если вы используете git-lfs
.
git archive не забирает файлы, которые не зафиксированы. Я пытался использовать его для резервного копирования всех файлов, включая файлы, которые я редактировал, но он не собирал последние (отредактированные) файлы. Я уверен, что это так, как задумано. Теперь мне нужно найти способ получить список всех файлов в HEAD и использовать cpio для копирования файлов, чтобы я взял файлы, которые редактируются. Мне нужна команда git ls-tree -r master --name-only | cpio -pdmv / некоторые / dest
Я написал простую оболочку для git-checkout-index
, которую вы можете использовать следующим образом:
git export ~/the/destination/dir
Если целевой каталог уже существует, вам нужно добавить -f
или --force
.
Установка проста; просто перетащите скрипт где-нибудь в PATH
и убедитесь, что он исполняемый.
Репозиторий github для git-export
Эта оболочка не зависит от платформы; он полагается на / bin / sh. Так что, если вы используете Windows, это решение наверное вам не подойдет.
Ухх, этот скрипт состоит из 57 строк документации, пробелов, настроек, синтаксического анализа аргументов и только одной строки, которая действительно что-то делает ...
git archive
также работает с удаленным репозиторием.
git archive --format=tar \
--remote=ssh://remote_server/remote_repository master | tar -xf -
Чтобы экспортировать конкретный путь внутри репо, добавьте столько путей, сколько хотите, в качестве последнего аргумента в git, например:
git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv
Этот вариант мне нравится больше всего. Дополнительным преимуществом является то, что он также работает с голыми репозиториями.
Улучшенная версия: git archive --format=tar --prefix=PROJECT_NAME/ --remote=USER@SERVER:PROJECT_NAME.git master | tar -xf -
(гарантирует, что ваш архив находится в папке)
По какой-то причине это не работает для меня на github. Итак, я написал небольшую обертку в zsh: gist.github.com/1895274
это сработало для меня +1. Как указать целевую папку на основе этого примера?
Удалось ответить на свой вопрос экспорт в указанный каталог git archive --format=tar --remote=ssh://remote_server/remote_repository master | (cd /path/to/dir/ && tar -xf -)
если вы привыкли к svn export repository.com/etc, это самый близкий вариант.
Я попробовал: git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git master
и получил фатальный результат: операция не поддерживается протоколом. Неожиданный конец потока команд.
@andyf поддерживает только git и протокол smart http. Если простой http на сервере, то он этого не сделает. stackoverflow.com/a/11258694/520567
@andyf GitHub работает по-своему: curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -
на документы
@bishop GitHub также поддерживает (но не рекламирует) протокол git. Просто замените https: // на git: // в URL-адресе.
@NeilMayhew У меня не работает, я получаю fatal: The remote end hung up unexpectedly
. Пробовал на двух разных серверах с репозиторием github jQuery.
Похоже, что это меньшая проблема с Git, чем с SVN. Git помещает только папку .git в корень репозитория, тогда как SVN помещает папку .svn в каждый подкаталог. Таким образом, "svn export" избегает рекурсивной магии командной строки, тогда как с Git в рекурсии нет необходимости.
Начиная с SVN 1.7, есть только одна папка .svn: subversion.apache.org/docs/release-notes/1.7.html#single-db
Это не избавит от каких-либо дополнительных файлов сборки, которые удаляет svn export. Так что это точно не ответ.
Мне это было нужно для сценария развертывания, и я не мог использовать ни один из вышеупомянутых подходов. Вместо этого я нашел другое решение:
#!/bin/sh
[ $# -eq 2 ] || echo "USAGE $0 REPOSITORY DESTINATION" && exit 1
REPOSITORY=$1
DESTINATION=$2
TMPNAME = "/tmp/$(basename $REPOSITORY).$$"
git clone $REPOSITORY $TMPNAME
rm -rf $TMPNAME/.git
mkdir -p $DESTINATION
cp -r $TMPNAME/* $DESTINATION
rm -rf $TMPNAME
В чем заключалась проблема с решением для дерева чтения / проверки-индекса или архивирования? Насколько я могу судить, вы сделали эквивалент чего-то вроде mkdir -p "" && git --git-dir = "" archive HEAD | tar -x -C ""
, но несколько длиннее.
Мне не удалось заставить работать дерево чтения из удаленного репозитория, а решение для архивирования не работает с github.
Да, с архивом получить недопустимую команду: 'git-upload-archive' ... ошибка, и у меня нет параметра конфигурации core.gitProxy и установленной переменной среды GIT_PROXY_COMMAND
Делая это простым способом, это функция для .bash_profile, она напрямую распаковывает архив в текущее место, сначала настройте свой обычный [url: path]. ПРИМЕЧАНИЕ: с помощью этой функции вы избегаете операции клонирования, она получает напрямую из удаленного репо.
gitss() {
URL=[url:path]
TMPFILE = "`/bin/tempfile`"
if [ "" = "" ]; then
echo -e "Use: gitss repo [tree/commit]\n"
return
fi
if [ "" = "" ]; then
TREEISH = "HEAD"
else
TREEISH = ""
fi
echo "Getting /$TREEISH..."
git archive --format=zip --remote=$URL/ $TREEISH > $TMPFILE && unzip $TMPFILE && echo -e "\nDone\n"
rm $TMPFILE
}
Псевдоним для .gitconfig, требуется такая же конфигурация (ОБЯЗАТЕЛЬНО выполняя команду внутри проектов .git, она ВСЕГДА переходит в базовый каталог ранее как сказано здесь, пока это не будет исправлено, я лично предпочитаю функцию
ss = !env GIT_TMPFILE = "`/bin/tempfile`" sh -c 'git archive --format=zip --remote=[url:path]/ \ > $GIT_TMPFILE && unzip $GIT_TMPFILE && rm $GIT_TMPFILE' -
Я просто хочу отметить, что в случае, если вы
Тогда вы можете просто использовать cp foo [destination]
вместо упомянутого git-archive master foo | -x -C [destination]
.
Это скопирует все содержимое, за исключением файлов .dot. Я использую это для экспорта клонированных проектов git в репозиторий git моего веб-приложения без материала .git.
cp -R ./path-to-git-repo /path/to/destination/
Обычный старый bash отлично работает :)
Почему бы просто не нажать на пульт? Даже проще, чем bash.
как насчет файлов, которые являются частью веб-приложений и их имя начинается с точки? :) подумайте о .htaccess
Иногда вы также хотите игнорировать то, что находится в .gitignore
, этого не будет.
Я широко использую git-submodules. Это работает для меня:
rsync -a ./FROM/ ./TO --exclude='.*'
Не будут ли пропущены файлы, имена которых начинаются с точки, например .htaccess
?
Хорошее решение, я бы заменил --exclude = '. *' На --exclude = '. Git *'
--exclude-vcs, если вы собираетесь поступить так
Может ли ./FROM/ быть удаленным репо?
Я бы заменил --exclude = '. *' На --exclude = '. Git *'
К вашему сведению, моя копия rsync
перечисляет аргумент как --cvs-exclude
. Кроме того, он по-прежнему копирует .gitattributes
и .gitignore
.
Bash-реализация git-export.
Я сегментировал процессы создания и удаления файлов .empty по их собственной функции с целью их повторного использования в реализации «git-archive» (будет опубликовано позже).
Я также добавил в процесс файл .gitattributes, чтобы удалить ненужные файлы из целевой папки экспорта. Включено подробное описание процесса, что сделало функцию «git-export» более эффективной.
EMPTY_FILE = ". Пустой";
function create_empty () {
## Processing path (target-dir):
TRG_PATH = "";
## Component(s):
EXCLUDE_DIR = ".git";
echo -en "\nAdding '${EMPTY_FILE}' files to empty folder(s): ...";
find ${TRG_PATH} -not -path "*/${EXCLUDE_DIR}/*" -type d -empty -exec touch {}/${EMPTY_FILE} \;
#echo "done.";
## Purging SRC/TRG_DIRs variable(s):
unset TRG_PATH EMPTY_FILE EXCLUDE_DIR;
return 0;
}
declare -a GIT_EXCLUDE;
function load_exclude () {
SRC_PATH = "";
ITEMS=0; while read LINE; do
# echo -e "Line [${ITEMS}]: '${LINE%%\ *}'";
GIT_EXCLUDE[((ITEMS++))]=${LINE%%\ *};
done < ${SRC_PATH}/.gitattributes;
GIT_EXCLUDE[${ITEMS}] = "${EMPTY_FILE}";
## Purging variable(s):
unset SRC_PATH ITEMS;
return 0;
}
function purge_empty () {
## Processing path (Source/Target-dir):
SRC_PATH = "";
TRG_PATH = "";
echo -e "\nPurging Git-Specific component(s): ... ";
find ${SRC_PATH} -type f -name ${EMPTY_FILE} -exec /bin/rm '{}' \;
for xRULE in ${GIT_EXCLUDE[@]}; do
echo -en " '${TRG_PATH}/{${xRULE}}' files ... ";
find ${TRG_PATH} -type f -name "${xRULE}" -exec /bin/rm -rf '{}' \;
echo "done.'";
done;
echo -e "done.\n"
## Purging SRC/TRG_PATHs variable(s):
unset SRC_PATH; unset TRG_PATH;
return 0;
}
function git-export () {
TRG_DIR = ""; SRC_DIR = "";
if [ -z "${SRC_DIR}" ]; then SRC_DIR = "${PWD}"; fi
load_exclude "${SRC_DIR}";
## Dynamically added '.empty' files to the Git-Structure:
create_empty "${SRC_DIR}";
GIT_COMMIT = "Including '${EMPTY_FILE}' files into Git-Index container."; #echo -e "\n${GIT_COMMIT}";
git add .; git commit --quiet --all --verbose --message "${GIT_COMMIT}";
if [ "${?}" -eq 0 ]; then echo " done."; fi
/bin/rm -rf ${TRG_DIR} && mkdir -p "${TRG_DIR}";
echo -en "\nChecking-Out Index component(s): ... ";
git checkout-index --prefix=${TRG_DIR}/ -q -f -a
## Reset: --mixed = reset HEAD and index:
if [ "${?}" -eq 0 ]; then
echo "done."; echo -en "Resetting HEAD and Index: ... ";
git reset --soft HEAD^;
if [ "${?}" -eq 0 ]; then
echo "done.";
## Purging Git-specific components and '.empty' files from Target-Dir:
purge_empty "${SRC_DIR}" "${TRG_DIR}"
else echo "failed.";
fi
## Archiving exported-content:
echo -en "Archiving Checked-Out component(s): ... ";
if [ -f "${TRG_DIR}.tgz" ]; then /bin/rm ${TRG_DIR}.tgz; fi
cd ${TRG_DIR} && tar -czf ${TRG_DIR}.tgz ./; cd ${SRC_DIR}
echo "done.";
## Listing *.tgz file attributes:
## Warning: Un-TAR this file to a specific directory:
ls -al ${TRG_DIR}.tgz
else echo "failed.";
fi
## Purgin all references to Un-Staged File(s):
git reset HEAD;
## Purging SRC/TRG_DIRs variable(s):
unset SRC_DIR; unset TRG_DIR;
echo "";
return 0;
}
Output:
$ git-export /tmp/rel-1.0.0
Adding '.empty' files to empty folder(s): ... done.
Checking-Out Index component(s): ... done.
Resetting HEAD and Index: ... done.
Purging Git-Specific component(s): ...
'/tmp/rel-1.0.0/{.buildpath}' files ... done.'
'/tmp/rel-1.0.0/{.project}' files ... done.'
'/tmp/rel-1.0.0/{.gitignore}' files ... done.'
'/tmp/rel-1.0.0/{.git}' files ... done.'
'/tmp/rel-1.0.0/{.gitattributes}' files ... done.'
'/tmp/rel-1.0.0/{*.mno}' files ... done.'
'/tmp/rel-1.0.0/{*~}' files ... done.'
'/tmp/rel-1.0.0/{.*~}' files ... done.'
'/tmp/rel-1.0.0/{*.swp}' files ... done.'
'/tmp/rel-1.0.0/{*.swo}' files ... done.'
'/tmp/rel-1.0.0/{.DS_Store}' files ... done.'
'/tmp/rel-1.0.0/{.settings}' files ... done.'
'/tmp/rel-1.0.0/{.empty}' files ... done.'
done.
Archiving Checked-Out component(s): ... done.
-rw-r--r-- 1 admin wheel 25445901 3 Nov 12:57 /tmp/rel-1.0.0.tgz
I have now incorporated the 'git archive' functionality into a single process that makes use of 'create_empty' function and other features.
function git-archive () {
PREFIX = ""; ## sudo mkdir -p ${PREFIX}
REPO_PATH = "`echo ""|awk -F: '{print }'`";
RELEASE = "`echo ""|awk -F: '{print }'`";
USER_PATH = "${PWD}";
echo "$PREFIX $REPO_PATH $RELEASE $USER_PATH";
## Dynamically added '.empty' files to the Git-Structure:
cd "${REPO_PATH}"; populate_empty .; echo -en "\n";
# git archive --prefix=git-1.4.0/ -o git-1.4.0.tar.gz v1.4.0
# e.g.: git-archive /var/www/htdocs /repos/domain.name/website:rel-1.0.0 --explode
OUTPUT_FILE = "${USER_PATH}/${RELEASE}.tar.gz";
git archive --verbose --prefix=${PREFIX}/ -o ${OUTPUT_FILE} ${RELEASE}
cd "${USER_PATH}";
if [[ "" =~ [--explode] ]]; then
if [ -d "./${RELEASE}" ]; then /bin/rm -rf "./${RELEASE}"; fi
mkdir -p ./${RELEASE}; tar -xzf "${OUTPUT_FILE}" -C ./${RELEASE}
fi
## Purging SRC/TRG_DIRs variable(s):
unset PREFIX REPO_PATH RELEASE USER_PATH OUTPUT_FILE;
return 0;
}
Использование: git-archive [/ var / www / htdocs] /repos/web.domain/website:rel-1.0.0
Я часто заходил на эту страницу, когда искал способ экспортировать репозиторий git. В моем ответе на этот вопрос рассматриваются три свойства, которые svn export изначально имеет по сравнению с git, поскольку svn следует подходу централизованного репозитория:
Экспорт определенной ветки с помощью svn осуществляется путем указания соответствующего пути
git clone --depth 1 --branch master git://git.somewhere destination_path
rm -rf destination_path/.git
При сборке определенного выпуска полезно клонировать стабильную ветку, например, --branch stable
или --branch release/0.9
.
Это не работает, если место назначения существует и не является пустым.
git archive | tar
approach is inapplicable to POSIX-incompatible shell environments (e.g., AppVeyor's CMD- or PowerShell-based CI), which is non-ideal. The git checkout
approach modifies the index of the main working tree, which is awful. The git checkout-index
approach requires the index of the main working tree to be modified beforehand, which is even awful-er. The traditional git clone
approach clones the entirety of the repository's history before deleting that history, which is wasteful. This is the only sane solution left.
Для локального экспорта обратите внимание, что абсолютный путь к рабочему дереву Git, из которого нужно клонировать, должен иметь префикс протокола file://
(например, git clone --depth 1 --branch v3.14.15 file:///home/me/src_repo trg_repo
). В противном случае будет выдан "warning: --depth is ignored in local clones; use file:// instead."
и будет выполнен стандартный, а не неглубокий клон, что приведет к поражению всей цели этого ответа. Салуд!
Эквивалент
svn export . otherpath
внутри существующего репо
git archive branchname | (cd otherpath; tar x)
Эквивалент
svn export url otherpath
является
git archive --remote=url branchname | (cd otherpath; tar x)
спасибо, это было то, чего мне не хватало ... также, чтобы проверить временные метки экспорта (они не будут сохранены, как в файлах), используйте git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)
... Однако архивирование с временными метками не совсем тривиально, поэтому я опубликовал пример ниже.
Вы можете использовать опцию C для tar вместо подоболочки, например: git archive branchname | tar xC otherpath
Обратите внимание, что опция C
для tar - это только GNU Tar.
Если вам нужно что-то, что работает с подмодулями, возможно, стоит попробовать.
Примечание:
Предположения:
cd MASTER_DIR && tar -zcvf ../DEST_DIR/export.tar.gz --exclude='.git*' . && cd ../DEST_DIR/ && tar xvfz export.tar.gz && rm export.tar.gz
Если вам также нужны подмодули, это должно помочь: https://github.com/meitar/git-archive-all.sh/wiki
На самом деле, похоже, что у него есть несколько небольших проблем, поэтому он, возможно, еще не готов к прайм-тайму.
Вы можете заархивировать удаленное репо в любой фиксации в виде zip-файла.
git archive --format=zip --output=archive.zip --remote=USERNAME@HOSTNAME:PROJECTNAME.git HASHOFGITCOMMIT
Так же просто, как клонирование, затем удалите папку .git:
git clone url_of_your_repo path_to_export && rm -rf path_to_export/.git
Честно говоря, этот ответ, который также является №1 в вопросе, - это то, чем вы собираетесь заниматься в 99% случаев. Большинство этих ответов безумно сложны.
−1. Во-первых, этот способ уже упоминается в вопросе как не удовлетворяющий автора вопроса. Во-вторых, таким образом будет загружена вся история, которая может быть намного больше полезной части. Пожалуйста, включите хотя бы --depth 1
. В-третьих, даже если этот ответ улучшен, он ничего не добавляет к ответ Ларса Шиллингмана.
Просто используйте svn export
.
Насколько я знаю, Github не поддерживает archive --remote
. Хотя GitHub - это svn совместимый, и у них есть все доступные репозитории git svn
, поэтому вы можете просто использовать svn export
, как обычно, с небольшими изменениями URL-адреса GitHub.
Например, чтобы экспортировать весь репозиторий, обратите внимание, как trunk
в URL-адресе заменяет master
(или любой другой ветка HEAD проекта установлена на):
svn export https://github.com/username/repo-name/trunk/
И вы можете экспортировать отдельный файл или даже определенный путь или папку:
svn export https://github.com/username/repo-name/trunk/src/lib/folder
Ветвь HEAD
или ветвь мастер будет доступна при использовании trunk
:
svn ls https://github.com/jquery/jquery/trunk
Не-HEAD
ветви будет доступен под /branches/
:
svn ls https://github.com/jquery/jquery/branches/2.1-stable
Все теги под /tags/
одинаково:
svn ls https://github.com/jquery/jquery/tags/2.1.3
git archive
отлично работает с GitHub, если вы используете протокол git. Просто замените https://
на git://
в URL-адресе. Я не знаю, почему GitHub не рекламирует эту скрытую функцию.
@NeilMayhew У меня не работает, я получаю fatal: The remote end hung up unexpectedly
. Пробовал на двух разных серверах с репозиторием github jQuery.
Ты прав. Я забыл, что использовал git config url.<base>.insteadOf
для кеширования удаленного репозитория. Поэтому на самом деле я использовал URL-адрес file://
. Я сомневаюсь, что git archive
когда-либо сможет работать с URL-адресами git://
, поскольку он должен иметь возможность запускать git-upload-archive
на удаленном конце. Это должно быть возможно с использованием протокола ssh
, за исключением того, что github не позволяет это (Invalid command: 'git-upload-archive'
).
Любой способ использовать локальный серверный инструмент, который ведет себя как github, если я хочу сделать это во внутренних репозиториях git?
проголосовали за - совершенно странно, что в Git нет этой функции, и нам приходится прибегать к svn
Интересно, как использовать svn export
с 2FA или с токеном API на github.
Другой вариант загрузки с GitHub - использовать REST API, см. Этот скрипт Python: gist.github.com/LewisGaul/65aa7d4ff5a20abb1c8ea02cd0948486
Если вы не исключаете файлы с .gitattributes
export-ignore
, попробуйте git checkout
mkdir /path/to/checkout/
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout -f -q
-f
When checking out paths from the index, do not fail upon unmerged entries; instead, unmerged entries are ignored.
и
-q
Avoid verbose
Кроме того, вы можете получить любую ветку или тег или из определенной версии фиксации, как в SVN, просто добавив SHA1 (SHA1 в Git эквивалентен номеру версии в SVN)
mkdir /path/to/checkout/
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout 2ef2e1f2de5f3d4f5e87df7d8 -f -q -- ./
/path/to/checkout/
должен быть пустым, Git не удалит файлы, но перезапишет файлы с тем же именем без предупреждения.
ОБНОВИТЬ:
Чтобы избежать проблемы с обезглавливанием или оставить нетронутым рабочий репозиторий при использовании checkout для экспорта с тегами, ветвями или SHA1, вам нужно добавить -- ./
в конце
Двойное тире --
сообщает git, что все после тире - это пути или файлы, а также в этом случае указывает git checkout
не изменять HEAD
.
Примеры:
Эта команда получит только каталог libs, а также файл readme.txt
именно из этого коммита.
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout fef2e1f2de5f3d4f5e87df7d8 -f -q -- ./libs ./docs/readme.txt
Это создаст (перезапишет) my_file_2_behind_HEAD.txt
с двумя коммитами за головой HEAD^2
.
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout HEAD^2 -f -q -- ./my_file_2_behind_HEAD.txt
Получить экспорт другой ветки
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout myotherbranch -f -q -- ./
Обратите внимание, что ./
относится к корню репозитория.
На самом деле, среди множества других и положительных отзывов, это сработало для меня лучше всего, без каких-либо сжатий, отлично работало с голыми репозиториями (gitolite).
Обратите внимание, что проверка SHA1 создаст проблему «обезглавливания» в репозитории.
на самом деле @ITGabs, это не загружает папку ".git". Таким образом, загруженная папка не является репозиторием git, поэтому технически она не «обезглавлена»
@FabioMarreco Проблема с обезглавливанием находится в репозитории, а не в экспортированных / загруженных файлах, я обновляю ответ для получения более подробной информации
Это отлично сработало для меня. Но сначала я получал сообщения об ошибке «Не репозиторий git». Затем я обнаружил, что «/ path / to / repo /» должен указывать на папку .git. Итак, это сработало: --git-dir = / path / to / repo / .git
Что, если я хочу экспортировать более раннюю фиксацию? Во-первых, сделайте заказ на более раннюю фиксацию с помощью git checkout <sha1>
, затем свою команду git --git-dir=/path/to/repo/ --work-tree=/path/to/checkout/ checkout -f -q
?
Это скопирует файлы из диапазона коммитов (от C до G) в файл tar. Примечание: при этом будут зафиксированы только файлы. Не весь репозиторий. Немного изменено от Здесь
Пример истории фиксации
А -> В -> C -> D -> E -> F -> G -> H -> I
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT C~..G | xargs tar -rf myTarFile.tar
Страница руководства git-diff-tree
-r -> рекурсировать в поддеревья
--no-commit-id -> git diff-tree выводит строку с идентификатором фиксации, если применимо. Этот флаг подавляет вывод идентификатора фиксации.
--name-only -> Показывать только имена измененных файлов.
--diff-filter = ACMRT -> Выбрать только эти файлы. Смотрите здесь полный список файлов
C..G -> Файлы в этом диапазоне коммитов
C ~ -> Включить файлы из коммита C. Не только файлы после коммита C.
| xargs tar -rf myTarFile -> выводит в tar
В моем файле .bashrc есть следующая служебная функция: она создает архив текущей ветки в репозитории git.
function garchive()
{
if [[ "x" == "x-h" || "x" == "x" ]]; then
cat <<EOF
Usage: garchive <archive-name>
create zip archive of the current branch into <archive-name>
EOF
else
local oname=
set -x
local bname=$(git branch | grep -F "*" | sed -e 's#^*##')
git archive --format zip --output ${oname} ${bname}
set +x
fi
}
Я думаю, что сообщение @Aredridel было самым близким, но есть кое-что еще - поэтому я добавлю это здесь; дело в том, что в svn
, если вы находитесь в подпапке репо, и вы делаете:
/media/disk/repo_svn/subdir$ svn export . /media/disk2/repo_svn_B/subdir
тогда svn
экспортирует все файлы, которые находятся под контролем версий (они также могли быть недавно добавлены; или измененный статус) - и если у вас есть другой «мусор» в этом каталоге (и я не считаю здесь вложенные папки .svn
, но видим такие вещи, как Файлы .o
) будет экспортирован нет; будут экспортированы только те файлы, которые зарегистрированы репозиторием SVN. Для меня приятно то, что этот экспорт также включает файлы с локальными изменениями, для которых нет еще был зафиксирован; и еще одна приятная вещь заключается в том, что временные метки экспортируемых файлов такие же, как и у исходных. Или, как говорит svn help export
:
- Exports a clean directory tree from the working copy specified by PATH1, at revision REV if it is given, otherwise at WORKING, into PATH2. ... If REV is not specified, all local changes will be preserved. Files not under version control will not be copied.
Чтобы понять, что git
не сохранит отметки времени, сравните вывод этих команд (в подпапке репозитория git
по вашему выбору):
/media/disk/git_svn/subdir$ ls -la .
... и:
/media/disk/git_svn/subdir$ git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)
... и я, в любом случае, замечаю, что git archive
приводит к тому, что все временные метки заархивированного файла совпадают! git help archive
говорит:
git archive behaves differently when given a tree ID versus when given a commit ID or tag ID. In the first case the current time is used as the modification time of each file in the archive. In the latter case the commit time as recorded in the referenced commit object is used instead.
... но, видимо, оба случая устанавливают "время модификации файла каждый"; тем самым нет сохраняет фактические временные метки этих файлов!
Итак, чтобы также сохранить временные метки, вот сценарий bash
, который на самом деле является однострочным, хотя и несколько сложным, поэтому ниже он размещен в нескольких строках:
/media/disk/git_svn/subdir$ git archive --format=tar master | (tar tf -) | (\
DEST = "/media/diskC/tmp/subdirB"; \
CWD = "$PWD"; \
while read line; do \
DN=$(dirname "$line"); BN=$(basename "$line"); \
SRD = "$CWD"; TGD = "$DEST"; \
if [ "$DN" != "." ]; then \
SRD = "$SRD/$DN" ; TGD = "$TGD/$DN" ; \
if [ ! -d "$TGD" ] ; then \
CMD = "mkdir \"$TGD\"; touch -r \"$SRD\" \"$TGD\""; \
echo "$CMD"; \
eval "$CMD"; \
fi; \
fi; \
CMD = "cp -a \"$SRD/$BN\" \"$TGD/\""; \
echo "$CMD"; \
eval "$CMD"; \
done \
)
Обратите внимание, что предполагается, что вы экспортируете содержимое в «текущий» каталог (выше, /media/disk/git_svn/subdir
) - и место назначения, в которое вы экспортируете, размещено несколько неудобно, но оно находится в переменной среды DEST
. Обратите внимание, что с этим скриптом; вы должны вручную создать каталог DEST
перед запуском вышеуказанного сценария.
После запуска скрипта вы сможете сравнить:
ls -la /media/disk/git_svn/subdir
ls -la /media/diskC/tmp/subdirB # DEST
... и, надеюсь, увидите те же отметки времени (для тех файлов, которые находились под контролем версий).
Надеюсь, это кому-то поможет,
Ваше здоровье!
Для пользователей GitHub метод git archive --remote
не будет работать напрямую, как URL экспорта недолговечен. Вы должны попросить GitHub указать URL-адрес, а затем загрузить этот URL-адрес. curl
упрощает это:
curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -
Это даст вам экспортированный код в локальном каталоге. Пример:
$ curl -L https://api.github.com/repos/jpic/bashworks/tarball | tar xzf -
$ ls jpic-bashworks-34f4441/
break conf docs hack LICENSE mlog module mpd mtests os README.rst remote todo vcs vps wepcrack
Редактировать
Если вы хотите, чтобы код помещался в конкретный каталог существующий (а не в случайный каталог из github):
curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | \
tar xzC /path/you/want --strip 1
Да, это - это чистая и аккуратная команда для архивирования вашего кода без включения git в архив, и ее можно передавать, не беспокоясь о истории коммитов git.
git archive --format zip --output /full/path/to/zipfile.zip master
Это здорово, просто нужно удалить gitignore после, и он готов и готов к публикации.
Удаление .gitgnore и т. д. Упоминается в принятых комментариях к ответу: используйте файл .gitattributes, см. Feed.cloud.geek.nz/posts/excluding-files-from-git-archive
Безусловно, самый простой способ, который я видел (и также работает с Windows), - это git bundle
:
git bundle create /some/bundle/path.bundle --all
Подробнее см. В этом ответе: Как я могу скопировать репозиторий git с моей машины Windows на машину Linux через USB-накопитель?
git bundle
включает папку .git
, чего OP не хочет; git archive
кажется более подходящим способом
Где документация на коммутатор --all
?
@GarretWilson, это странно. --all здесь не вариант для создания пакета git, даже если он действительно выглядит так. --all - допустимое значение для передачи как git-rev-list, см. git-scm.com/docs/git-rev-list.
Вариант 1 звучит не слишком эффективно. Что делать, если в клиенте нет места для клонирования и потом удаляет папку .git
?
Сегодня я обнаружил, что пытаюсь сделать это, где клиентом является Raspberry Pi, на котором почти не осталось места. Кроме того, я также хочу исключить из репозитория какую-то тяжелую папку.
Вариант 2 и другие ответы здесь не помогают в этом сценарии. Ни git archive
(потому что требуется зафиксировать файл .gitattributes
, и я не хочу сохранять это исключение в репозитории).
Здесь я делюсь своим решением, аналогичным варианту 3, но без использования git clone
:
tmp=`mktemp`
git ls-tree --name-only -r HEAD > $tmp
rsync -avz --files-from=$tmp --exclude='fonts/*' . raspberry:
Замена строки rsync
на эквивалентную строку для сжатия также будет работать как git archive
, но с своего рода опцией исключения (как задается здесь).
У меня есть другое решение, которое отлично работает, если у вас есть локальная копия репозитория на машине, на которой вы хотите создать экспорт. В этом случае перейдите в этот каталог репозитория и введите эту команду:
GIT_WORK_TREE=outputdirectory git checkout -f
Это особенно полезно, если вы управляете веб-сайтом с помощью репозитория git и хотите проверить чистую версию в /var/www/
. В этом случае добавьте эту команду в сценарий .git/hooks/post-receive
(hooks/post-receive
в голом репозитории, что больше подходит в этой ситуации)
Насколько я понимаю вопрос, это больше касается загрузки только определенного состояния с сервера, без истории и без данных других ветвей, а не извлечения состояния из локального репозитория (как это делают многие другие пользователи).
Это можно сделать так:
git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
--single-branch
доступен с Git 1.7.10 (апрель 2012 г.).--depth
является (был?) Неисправным по сообщениям, но в случае экспорта упомянутые проблемы не должны иметь значения.Примечание: я только что заметил, что есть 2 страницы анонсеров, я просмотрел только одну перед публикацией. Есть один аналогичный ответ только с --depth
, который подразумевает --single-branch
, если не указан --no-single-branch
, что означает, что это, вероятно, имеет тот же эффект. Хотя не уверены, может подтвердить какой-нибудь эксперт?
экспорт git в zip-архив с добавлением префикса (например, имени каталога):
git archive master --prefix=directoryWithinZip/ --format=zip -o out.zip
@rnrTom: См. ответ Сомова. (в tar-архиве ничего "сжатого" нет).