我一直想知道是否有一个好的“git 导出”解决方案可以创建一个没有 .git
存储库目录的树的副本。我知道的方法至少有以下三种:
git clone 然后删除 .git 存储库目录。 git checkout-index 暗示了此功能,但以“只需将所需的树读入索引...”开头,我不完全确定该怎么做。 git-export 是一个第三方脚本,它本质上是将 git 克隆到一个临时位置,然后 rsync --exclude='.git' 到最终目的地。
这些解决方案中没有一个真正让我感到满意。最接近 svn export
的可能是选项 1,因为两者都要求目标目录首先为空。但是选项 2 似乎更好,假设我可以弄清楚将树读入索引意味着什么。
git archive --format zip --output "output.zip" master -0
会给你一个未压缩的存档(-0 是未压缩的标志)。 git-scm.com/docs/git-archive。
export
一个 250 kB 的子目录(否则它的大小可能是 200 MB,不包括修订版) - 我只会访问网络进行 250 kB(左右)的下载传输。使用 git
,必须在服务器上启用 archive
(所以我不能尝试) - 服务器上的 clone --depth 1
仍可能检索到 25 MB 的存储库,其中仅 .git
子文件夹就需要 15 MB。因此,我仍然会说答案是“不”。
git archive -o latest.zip HEAD
实现此目的的最简单方法可能是使用 git archive
。如果你真的只需要扩展的树,你可以做这样的事情。
git archive master | tar -x -C /somewhere/else
大多数时候,我需要从 git 中“导出”某些东西,无论如何我都想要一个压缩存档,所以我做这样的事情。
git archive master | bzip2 >source-tree.tar.bz2
压缩包:
git archive --format zip --output /full/path/to/zipfile.zip master
git help archive
有关更多详细信息,它非常灵活。
请注意,即使存档不包含 .git 目录,它也会包含其他隐藏的特定于 git 的文件,如 .gitignore、.gitattributes 等。如果您不希望它们在存档中,请确保您在 .gitattributes 文件中使用 export-ignore 属性并在归档之前提交它。 Read more...
注意:如果你有兴趣导出索引,命令是
git checkout-index -a -f --prefix=/destination/path/
(有关详细信息,请参阅 Greg's answer)
我发现了选项 2 的含义。从存储库中,您可以执行以下操作:
git checkout-index -a -f --prefix=/destination/path/
路径末尾的斜杠很重要,否则将导致文件位于 /destination 中,前缀为“路径”。
由于在正常情况下索引包含存储库的内容,因此“将所需的树读入索引”没有什么特别的事情要做。它已经在那里了。
-a
标志是检查索引中所有文件所必需的(我不确定在这种情况下省略这个标志意味着什么,因为它不符合我的要求)。 -f
标志强制覆盖输出中的任何现有文件,此命令通常不会这样做。
这似乎是我正在寻找的那种“git export”。
git add
命令更改索引中的内容,因此无论 git status
显示为“待提交”的内容都是 HEAD 和索引内容之间的差异。
~
的目录(不是 '~'
!)将在您的工作目录中创建。在这方面,git checkout-index
没有什么特别之处:mkdir '~/dest'
也是如此(不要那样做!)。避免需要引用的文件名的另一个很好的理由(例如,其中有空格):-)
git archive
也适用于远程存储库。
git archive --format=tar \
--remote=ssh://remote_server/remote_repository master | tar -xf -
要在 repo 中导出特定路径,请添加任意数量的路径作为 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 -
(确保您的存档位于文件夹中)
git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git master
并得到了致命的:协议不支持操作。命令流意外结束。
curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -
每docs
https://i.stack.imgur.com/p73W2.png
如果存储库托管在 GitHub 上,则为特殊情况的答案。
只需使用 svn export
。
据我所知 Github 不允许archive --remote
。尽管 GitHub 是 svn compatible 并且他们确实可以访问所有 git repos svn
,因此您可以像往常一样使用 svn export
,只需对您的 GitHub url 进行一些调整。
例如,要导出整个存储库,请注意 URL 中的 trunk
如何替换 master
(或任何 project's HEAD branch is set to):
svn export https://github.com/username/repo-name/trunk/
您可以导出单个文件甚至某个路径或文件夹:
svn export https://github.com/username/repo-name/trunk/src/lib/folder
使用 jQuery JavaScript 库的示例
HEAD
分支或 master 分支将可使用 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 协议,只需将 URL 中的 https://
替换为 git://
即可。我不知道为什么 GitHub 不宣传这个隐藏功能。
fatal: The remote end hung up unexpectedly
。使用 jQuery github repo 在两个不同的服务器上进行了尝试。
git config url.<base>.insteadOf
来缓存远程存储库。因此,我实际上使用的是 file://
URL。我怀疑 git archive
是否可以与 git://
URL 一起使用,因为它需要能够在远程端运行 git-upload-archive
。应该可以使用 ssh
协议,但 github 不允许它 (Invalid command: 'git-upload-archive'
)。
从 Git Manual:
使用 git-checkout-index “导出整棵树”
前缀功能基本上使得使用 git-checkout-index 作为“导出为树”功能变得微不足道。只需将所需的树读入索引,然后执行以下操作:
$ git checkout-index --prefix=git-export-dir/ -a
git read-tree bar:foo
然后 git checkout-index --prefix=export_dir/ -a
之后也许你应该做 git update-index master
我围绕 git-checkout-index
编写了一个简单的包装器,您可以像这样使用它:
git export ~/the/destination/dir
如果目标目录已存在,则需要添加 -f
或 --force
。
安装简单;只需将脚本放在 PATH
中的某个位置,并确保它是可执行的。
The github repository for git-export
与 SVN 相比,这似乎对 Git 来说不是问题。 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)
git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)
...但是,使用时间戳归档并不是一件容易的事,所以我发布了 example below。
git archive branchname | tar xC otherpath
C
选项仅是 GNU Tar。
如果您没有使用 .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 从索引中检出路径时,不要在未合并的条目上失败;相反,未合并的条目将被忽略。
和
-q 避免冗长
此外,您可以获取任何分支或标签或从特定的提交修订版,如在 SVN 中只需添加 SHA1(Git 中的 SHA1 等同于 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-submodules。这个对我有用:
rsync -a ./FROM/ ./TO --exclude='.*'
.htaccess
?
rsync
副本将参数列为 --cvs-exclude
。此外,它仍会复制 .gitattributes
和 .gitignore
在寻找导出 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
方法不适用于与 POSIX 不兼容的 shell 环境(例如,AppVeyor 的基于 CMD 或 PowerShell 的 CI) ,这是不理想的。 git checkout
方法修改了主工作树的索引,这很糟糕。 git checkout-index
方法需要预先修改主工作树的索引,这更糟糕。传统的 git clone
方法会在删除该历史记录之前克隆整个存储库的历史记录,这是一种浪费。这是剩下的唯一合理的解决方案。
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."
并执行标准而不是浅层克隆,从而破坏了此答案的全部目的。 祝你好运!
这将复制所有内容,减去 .dot 文件。我使用它来将 git 克隆的项目导出到我的 web 应用程序的 git repo 中,而不需要 .git 的东西。
cp -R ./path-to-git-repo /path/to/destination/
普通的旧 bash 效果很好:)
.gitignore
中的内容,这不会。
就像克隆一样简单,然后删除 .git 文件夹:
git clone url_of_your_repo path_to_export && rm -rf path_to_export/.git
--depth 1
。第三,即使这个答案得到了改进,它也不会对 the Lars Schillingmann's answer 增加任何内容。
对于 GitHub 用户,git archive --remote
方法不会像 the export URL is ephemeral 那样直接工作。您必须向 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
是的,this 是一个干净整洁的命令,用于存档您的代码,存档中不包含任何 git,并且可以很好地传递而无需担心任何 git 提交历史记录。
git archive --format zip --output /full/path/to/zipfile.zip master
我只想指出,如果你是
导出存储库的子文件夹(这就是我过去使用 SVN 导出功能的方式)可以将所有内容从该文件夹复制到部署目标,因为您已经拥有整个存储库的副本。
然后您可以只使用 cp foo [destination]
而不是提到的 git-archive master foo | -x -C [destination]
。
您可以在任何提交时将远程存储库归档为 zip 文件。
git archive --format=zip --output=archive.zip --remote=USERNAME@HOSTNAME:PROJECTNAME.git HASHOFGITCOMMIT
如果您想要与子模块一起使用的东西,这可能值得一试。
笔记:
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
我的偏好实际上是在您的 Makefile(或其他构建系统)中有一个 dist 目标,该目标导出您的代码的可分发存档(.tar.bz2、.zip、.jar 或任何合适的)。如果您碰巧使用 GNU 自动工具或 Perl 的 MakeMaker 系统,我认为这会自动为您提供。如果没有,我强烈建议添加它。
ETA (2012-09-06):哇,严厉的反对票。我仍然认为使用构建工具而不是源代码控制工具来构建发行版会更好。我相信使用构建工具构建工件。在我目前的工作中,我们的主要产品是使用 ant 目标构建的。我们正在切换源代码控制系统,而这个 ant 目标的存在意味着迁移的麻烦减少了。
据我了解这个问题,它更多的是从服务器下载某些状态,没有历史记录,也没有其他分支的数据,而不是从本地存储库中提取状态(就像这里的许多回答者所做的那样)。
可以这样做:
git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
--single-branch 从 Git 1.7.10(2012 年 4 月)开始可用。
--depth 是(曾经?)据报道有问题,但对于出口的情况,上述问题应该无关紧要。
--depth
的 anwser,这意味着 --single-branch
除非给出 --no-single-branch
,这意味着这可能具有相同的效果。不过不确定,有专家可能会证实?
git-export 的 Bash 实现。
我已经根据自己的功能对 .empty 文件的创建和删除过程进行了分段,目的是在“git-archive”实现中重新使用它们(稍后将发布)。
我还在进程中添加了“.gitattributes”文件,以便从目标导出文件夹中删除不需要的文件。在使“git-export”功能更高效的同时,包括对流程的详细说明。
EMPTY_FILE=".empty";
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 和索引:...完成。清除特定于 Git 的组件:...'/tmp/rel-1.0.0/{.buildpath}' 文件...完成。' '/tmp/rel-1.0.0/{.project}' 文件...完成。' '/tmp/rel-1.0.0/{.gitignore}' 文件...完成。' '/tmp/rel-1.0.0/{.git}' 文件...完成。' '/tmp/rel-1.0.0/{.gitattributes}' 文件...完成。' '/tmp/rel-1.0.0/{*.mno}' 文件...完成。' '/tmp/rel-1.0.0/{*~}' 文件...完成。' '/tmp/rel-1.0.0/{.*~}' 文件...完成。' '/tmp/rel-1.0.0/{*.swp}' 文件...完成。' '/tmp/rel-1.0.0/{*.swo}' 文件...完成。' '/tmp/rel-1.0.0/{.DS_Store}' 文件...完成。' '/tmp/rel-1.0.0/{.settings}' 文件...完成。' '/tmp/rel-1.0.0/{.empty}' 文件...完成。'完毕。归档签出组件:...完成。 -rw-r--r-- 1 管理轮 25445901 11 月 3 日 12:57 /tmp/rel-1.0.0.tgz 我现在已将“git 存档”功能合并到一个使用“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;
}
这会将一系列提交(C 到 G)中的文件复制到 tar 文件中。注意:这只会提交文件。不是整个存储库。对 Here 稍作修改
示例提交历史
--> 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
-r --> 递归到子树
--no-commit-id --> git diff-tree 在适用时输出带有提交 ID 的行。此标志抑制了提交 ID 输出。
--name-only --> 仅显示更改文件的名称。
--diff-filter=ACMRT -->仅选择这些文件。 See here for full list of files
C..G --> 此提交范围内的文件
C~ --> 包括来自 Commit C 的文件。不仅仅是 Commit C 之后的文件。
| xargs tar -rf myTarFile --> 输出到 tar
在添加前缀(例如目录名称)的同时将 git 导出到 zip 存档:
git archive master --prefix=directoryWithinZip/ --format=zip -o out.zip
到目前为止,我见过的最简单的方法(也适用于 Windows)是 git bundle
:
git bundle create /some/bundle/path.bundle --all
有关详细信息,请参阅此答案:How can I copy my git repository from my windows machine to a linux machine via usb drive?
git bundle
包括 .git
文件夹,这是 OP 不想要的; git archive
似乎是更合适的方式
--all
开关的文档在哪里?
我需要将其用于部署脚本,但我无法使用上述任何方法。相反,我想出了一个不同的解决方案:
#!/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 "$2" && git --git-dir="$1" archive HEAD | tar -x -C "$2"
的操作,但有些冗长。
这样做很简单,这是 .bash_profile 的一个功能,它直接将存档解压缩到当前位置,首先配置您通常的 [url:path]。注意:使用此功能可以避免克隆操作,它直接从远程仓库获取。
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 项目中执行命令,它总是跳转到之前的基本目录 as said here,直到修复此问题我个人更喜欢该功能
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' -
如果您在要创建导出的机器上有存储库的本地副本,我还有另一个解决方案可以正常工作。在这种情况下,移动到此存储库目录,并输入以下命令:
GIT_WORK_TREE=outputdirectory git checkout -f
如果您管理具有 git 存储库的网站并希望在 /var/www/
中检出一个干净的版本,这将特别有用。在这种情况下,在 .git/hooks/post-receive
脚本中添加此命令(hooks/post-receive
在裸存储库上,更适合这种情况)
我认为 @Aredridel 的帖子最接近,但还有更多内容 - 所以我将在此处添加;问题是,在 svn
中,如果您在 repo 的子文件夹中,并且您这样做:
/media/disk/repo_svn/subdir$ svn export . /media/disk2/repo_svn_B/subdir
然后 svn
将导出所有受修订控制的文件(它们也可能是新添加的;或已修改状态) - 如果您在该目录中有其他“垃圾”(我这里不计算 .svn
子文件夹,但像 .o
文件这样可见的东西),它将不会被导出;只有那些由 SVN repo 注册的文件才会被导出。对我来说,一件好事是,此导出还包括具有本地更改但尚未提交 的文件;另一个好处是导出文件的时间戳与原始文件相同。或者,正如 svn help export
所说:
从 PATH1 指定的工作副本中导出一个干净的目录树,如果给出,则在修订版本 REV,否则在 WORKING,到 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 archive 在给定树 ID 与给定提交 ID 或标签 ID 时的行为不同。在第一种情况下,当前时间用作存档中每个文件的修改时间。在后一种情况下,将使用引用的提交对象中记录的提交时间。
...但显然这两种情况都设置了“每个文件的修改时间”;从而不保留这些文件的实际时间戳!
因此,为了也保留时间戳,这里有一个 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
我的 .bashrc 文件中有以下实用程序函数:它在 git 存储库中创建当前分支的存档。
function garchive()
{
if [[ "x$1" == "x-h" || "x$1" == "x" ]]; then
cat <<EOF
Usage: garchive <archive-name>
create zip archive of the current branch into <archive-name>
EOF
else
local oname=$1
set -x
local bname=$(git branch | grep -F "*" | sed -e 's#^*##')
git archive --format zip --output ${oname} ${bname}
set +x
fi
}
git archive --format zip --output /full/path master
git archive --format zip --output /path/to/file.zip --prefix=newdir/ master
,输出将被称为“file.zip”,但当您解压缩它时,顶级目录将是“newdir”。 (如果省略 --prefix 属性,顶级目录将是“文件”。)git archive -o latest.zip HEAD
它创建一个 Zip 存档,其中包含当前分支上最新提交的内容。请注意,输出格式由输出文件的扩展名推断。