Есть ли "git export" (как "svn export")?

Мне было интересно, есть ли хорошее решение "git export", которое создает копию дерева без .git каталог репозитория. Есть как минимум три метода, о которых я знаю:

  1. git clone с последующим удалением .git каталог репозитория.
  2. git checkout-index ссылается на эту функциональность, но начинается с "Просто прочитайте нужное дерево в индекс...", что я не совсем уверен, как это сделать.
  3. git-export это сторонний скрипт, который по сути делает git clone во временное место с последующим rsync --exclude='.git' в конечный пункт назначения.

Ни одно из этих решений не кажется мне удовлетворительным. Ближайший к svn export может быть вариант 1, потому что оба требуют, чтобы целевой каталог был пустым сначала. Но вариант 2 кажется еще лучше, если предположить, что я могу понять, что значит читать дерево в индексе.

31 ответ

Решение

Вероятно, самый простой способ добиться этого с 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/

(См . Ответ Грега для более подробной информации)

Я узнал, что означает вариант 2. Из репозитория вы можете сделать:

git checkout-index -a -f --prefix=/destination/path/

Косая черта в конце пути важна, иначе это приведет к тому, что файлы будут в / destination с префиксом "путь".

Поскольку в обычной ситуации индекс содержит содержимое репозитория, ничего особенного для "чтения нужного дерева в индекс" делать нечего. Это уже там.

-a Флаг необходим для проверки всех файлов в индексе (я не уверен, что означает опускать этот флаг в этой ситуации, так как он не делает то, что я хочу). -f flag заставляет перезаписывать любые существующие файлы в выводе, чего обычно не делает эта команда.

Похоже, это был тот "экспорт мерзавцев", который я искал.

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

Ответ в особом случае, если хранилище размещено на GitHub.

Просто используйте 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

Пример с библиотекой jQuery JavaScript

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:

Использование git-checkout-index для "экспорта всего дерева"

Возможность префикса в основном упрощает использование git-checkout-index в качестве функции "экспортировать как дерево". Просто прочитайте нужное дерево в индекс и выполните:

$ git checkout-index --prefix=git-export-dir/ -a

Я написал простую обертку вокруг git-checkout-index что вы можете использовать так:

git export ~/the/destination/dir

Если каталог назначения уже существует, вам нужно добавить -f или же --force,

Установка проста; просто бросьте скрипт где-нибудь в вашем PATHи убедитесь, что он исполняемый.

Github хранилище дляgit-export

Похоже, что это меньше проблема с Git, чем SVN. Git помещает только папку.git в корень хранилища, тогда как SVN помещает папку.svn в каждый подкаталог. Таким образом, "svn export" избегает рекурсивной магии командной строки, тогда как в Git рекурсия не нужна.

Эквивалент

svn export . otherpath

внутри существующего репо

git archive branchname | (cd otherpath; tar x)

Эквивалент

svn export url otherpath

является

git archive --remote=url branchname | (cd otherpath; tar x)

Если вы не исключаете файлы с .gitattributesexport-ignore тогда попробуй git checkout

mkdir /path/to/checkout/
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout -f -q

-f
При проверке путей из индекса не допускайте сбоев при незаполненных записях; вместо этого необработанные записи игнорируются.

а также

-q
Избегайте многословия

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

ОБНОВЛЕНИЕ: чтобы избежать обезглавленной проблемы или оставить нетронутым рабочий репозиторий при использовании извлечения для экспорта с тегами, ветвями или 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 -- ./

Заметить, что ./ относительно корня хранилища

Я широко использую git-подмодули. Этот работает для меня:

rsync -a ./FROM/ ./TO --exclude='.*'

Я часто заходил на эту страницу, когда искал способ экспортировать репозиторий 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,

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

cp -R./path-to-git-repo / путь / к / месту назначения /

Обычный старый bash работает просто отлично:)

Просто, как клон, удалите папку.git:

git clone url_of_your_repo path_to_export && rm -rf path_to_export/.git

Для пользователей 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 commit.

git archive --format zip --output /full/path/to/zipfile.zip master 

Я просто хочу указать, что в случае, если вы

  1. экспорт подпапки репозитория (именно так я использовал функцию экспорта SVN)
  2. все в порядке с копированием всего из этой папки в место назначения развертывания
  3. и так как у вас уже есть копия всего хранилища на месте.

Тогда вы можете просто использовать cp foo [destination] вместо упомянутого git-archive master foo | -x -C [destination],

Вы можете заархивировать удаленное репо при любом коммите в виде zip-файла.

git archive --format=zip --output=archive.zip --remote=USERNAME@HOSTNAME:PROJECTNAME.git HASHOFGITCOMMIT

Bash-реализация git-export.

Я сегментировал процессы создания и удаления файлов.empty по их собственной функции с целью их повторного использования в реализации 'git-archive' (будет опубликовано позже).

Я также добавил файл ".gitattributes" в процесс, чтобы удалить ненужные файлы из целевой папки экспорта. Включение многословия в процесс при одновременном повышении эффективности функции git-export.

"Пустой" empty_file =;

function create_empty () {
## Processing path (target-dir):
    TRG_PATH="${1}";
## 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="${1}";
    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="${1}";
    TRG_PATH="${2}";
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="${1}"; SRC_DIR="${2}";
    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;
  }

Выход:

$ git-export /tmp/rel-1.0.0

Добавление файлов.empty в пустую папку (и): ... готово.

Проверка компонентов индекса:... сделано.

Сброс HEAD и Index: ... сделано.

Чистка Git-специфических компонентов:...

'/tmp/rel-1.0.0/ndom.buildpath}' файлы... готово. '

'/tmp/rel-1.0.0/ndom.project}' files... done. '

'/tmp/rel-1.0.0/ enj.gitignore}' files... done. '

'/tmp/rel-1.0.0/ enj.git}' files... done. '

'/tmp/rel-1.0.0/ enj.gitattributes}' files... done. '

'/tmp/rel-1.0.0/ndom*.mno}' files... done. '

'/tmp/rel-1.0.0/ndom*~}' files... done. '

'/tmp/rel-1.0.0/ndom.*~}' files... done. '

'/tmp/rel-1.0.0/ndom*.swp}' files... done. '

'/tmp/rel-1.0.0/ndom*.swo}' файлы... готово. "

'/tmp/rel-1.0.0/ndom.DS_Store}' files... done. '

'/tmp/rel-1.0.0/ndom.settings}' files... done. '

'/tmp/rel-1.0.0/ndom.empty}' files ... done.'

сделанный.

Архивация извлеченных компонентов:... выполнено.

-rw-r - r-- 1 колесо администратора 25445901 3 ноября, 12:57 /tmp/rel-1.0.0.tgz

Теперь я включил функциональность 'git archive' в единый процесс, который использует функцию 'create_empty' и другие функции.

function git-archive () {
    PREFIX="${1}"; ## sudo mkdir -p ${PREFIX}
    REPO_PATH="`echo "${2}"|awk -F: '{print $1}'`";
    RELEASE="`echo "${2}"|awk -F: '{print $2}'`";
    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 [[ "${3}" =~ [--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;
  }

Если вы хотите что-то, что работает с подмодулями, это может стоить того.

Замечания:

  • MASTER_DIR = проверка с вашими подмодулями также проверены
  • DEST_DIR = где этот экспорт закончится
  • Если у вас есть rsync, я думаю, что вы сможете сделать то же самое с еще меньшей болевой болью.

Предположения:

  • Вам нужно запустить это из родительского каталога MASTER_DIR (т.е. из MASTER_DIR cd ..)
  • Предполагается, что DEST_DIR создан. Это довольно легко изменить, чтобы включить создание DEST_DIR, если вы хотите

cd MASTER_DIR && tar -zcvf ../DEST_DIR/export.tar.gz --exclude='.git*' . && cd ../DEST_DIR/ && tar xvfz export.tar.gz && rm export.tar.gz

На самом деле, я бы предпочел иметь цель dist в вашем Makefile (или другой системе сборки), которая экспортирует распространяемый архив вашего кода (.tar.bz2, .zip, .jar или что-то подходящее). Если вы используете автоинструменты GNU или системы Perl MakeMaker, я думаю, что это существует для вас автоматически. Если нет, я настоятельно рекомендую добавить его.

ETA (2012-09-06): Ух, резкие спады. Я все еще верю, что лучше создавать дистрибутивы с помощью инструментов сборки, а не инструмента контроля исходного кода. Я верю в создание артефактов с помощью инструментов сборки. В моей нынешней работе наш основной продукт построен с целью муравья. Мы находимся в процессе переключения систем управления исходным кодом, и наличие этой цели муравья означает еще одну проблему при миграции.

Как я понимаю вопрос, речь идет скорее о загрузке только определенного состояния с сервера, без истории и без данных других ветвей, а не о извлечении состояния из локального репозитория (как это делают многие anwsers).

Это можно сделать так:

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 как сообщается, является (было?) неисправным, но в случае экспорта упомянутые проблемы не должны иметь значения.

Экспорт git в zip-архив при добавлении префикса (например, имени каталога):

git archive master --prefix=directoryWithinZip/  --format=zip -o out.zip

Безусловно, самый простой способ, который я видел (и работает на Windows), это git bundle:

git bundle create /some/bundle/path.bundle --all

Смотрите этот ответ для более подробной информации: Как я могу скопировать мой репозиторий git со своего компьютера с Windows на компьютер с Linux через USB-накопитель?

Это скопирует файлы в диапазоне коммитов (от C до G) в файл tar. Примечание: это только передаст файлы. Не весь репозиторий. Слегка изменено здесь

Пример истории коммитов

A -> B -> 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~ -> Включить файлы из Commit C. Не только файлы с Commit C.

| xargs tar -rf myTarFile -> выводит данные в tar

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

GIT_WORK_TREE=outputdirectory git checkout -f

Это особенно полезно, если вы управляете веб-сайтом с помощью git-репозитория и хотите получить чистую версию в /var/www/, В этом случае добавьте эту команду в поле .git/hooks/post-receive сценарий (hooks/post-receive на голом репозитории, что больше подходит в данной ситуации)

Мне это нужно для сценария развертывания, и я не мог использовать ни один из вышеупомянутых подходов. Вместо этого я нашел другое решение:

#!/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

Делая это простым способом, это функция для.bash_profile, она непосредственно распаковывает архив в текущем местоположении, сначала настраивая ваш обычный [url: путь]. ПРИМЕЧАНИЕ: с помощью этой функции вы избегаете операции клонирования, она поступает непосредственно из удаленного репо.

gitss() {
    URL=[url:path]

    TMPFILE="`/bin/tempfile`"
    if [ "$1" = "" ]; then
        echo -e "Use: gitss repo [tree/commit]\n"
        return
    fi
    if [ "$2" = "" ]; then
        TREEISH="HEAD"
    else
        TREEISH="$2"
    fi
    echo "Getting $1/$TREEISH..."
    git archive --format=zip --remote=$URL/$1 $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]/$1 $2 \ > $GIT_TMPFILE && unzip $GIT_TMPFILE && rm $GIT_TMPFILE' -

Я думаю, что пост @Aredridel был ближе всего, но есть кое-что еще к этому - поэтому я добавлю это здесь; дело в том, что в svn, если вы находитесь в подпапке репо, и вы делаете:

/media/disk/repo_svn/subdir$ svn export . /media/disk2/repo_svn_B/subdir

затем svn будет экспортировать все файлы, которые находятся под контролем ревизии (они также могут быть недавно добавлены или изменены) - и если у вас есть другой "мусор" в этом каталоге (и я не считаю .svn подпапки здесь, но видны такие вещи, как .o файлы), он не будет экспортироваться; будут экспортированы только те файлы, которые зарегистрированы в репозитории SVN. Для меня одна приятная вещь состоит в том, что этот экспорт также включает файлы с локальными изменениями, которые еще не были зафиксированы; и еще одна приятная вещь - временные метки экспортируемых файлов такие же, как и у оригинальных. Или как svn help export кладет это:

  1. Экспортирует чистое дерево каталогов из рабочей копии, указанной в PATH1, при ревизии REV, если оно задано, в противном случае при РАБОТЕ, в PATH2. ... Если REV не указан, все локальные изменения будут сохранены. Файлы, не находящиеся под контролем версий, не будут скопированы.

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

... но, очевидно, в обоих случаях устанавливается "время модификации каждого файла"; тем самым не сохраняя фактические метки времени этих файлов!

Итак, чтобы также сохранить временные метки, вот 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

... и, надеюсь, увидеть те же временные метки (для тех файлов, которые были под контролем версий).

Надеюсь, это кому-то поможет,
Ура!

Если вам также нужны субмодули, это должно сработать: https://github.com/meitar/git-archive-all.sh/wiki

Вариант 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 но с некоторой опцией исключения (как спрашивается здесь).

Другие вопросы по тегам