我一直在想,是否有一个好的“gitexport”解决方案可以创建一个没有.git存储库目录的树的副本。我知道至少有三种方法:
git克隆,然后删除.git存储库目录。git签出索引暗示了这一功能,但以“只需将所需的树读入索引……”开头,我不完全确定该怎么做。gitexport是一个第三方脚本,本质上是将git克隆到临时位置,然后再将rsync--exclude='.git'复制到最终目标。
这些解决方案中没有一个让我感到满意。最接近svn导出的可能是选项1,因为两者都要求目标目录首先为空。但选项2似乎更好,假设我能够理解将树读入索引意味着什么。
我发现了选项2的含义。从存储库中,您可以执行以下操作:
git checkout-index -a -f --prefix=/destination/path/
路径结尾处的斜线很重要,否则将导致文件位于带有前缀“path”的/target中。
因为在正常情况下,索引包含存储库的内容,所以“将所需的树读入索引”没有什么特别的事情可做。它已经在那里了。
签出索引中的所有文件都需要-a标志(我不确定在这种情况下省略此标志意味着什么,因为它不能满足我的需要)。-f标志强制覆盖输出中的任何现有文件,而此命令通常不会这样做。
这似乎是我想要的那种“git导出”。
选项1听起来效率不高。如果客户机中没有空间进行克隆,然后删除.git文件夹,该怎么办?
今天我发现自己正在尝试这样做,客户是一个几乎没有空间的树莓派。此外,我还想从存储库中排除一些较重的文件夹。
选项2和此处的其他答案在这种情况下没有帮助。两个git存档(因为需要提交.gitattributes文件,我不想将此排除保存在存储库中)。
这里我分享了我的解决方案,类似于选项3,但不需要gitclone:
tmp=`mktemp`
git ls-tree --name-only -r HEAD > $tmp
rsync -avz --files-from=$tmp --exclude='fonts/*' . raspberry:
将rsync行更改为压缩的等效行也可以作为git存档,但有一种排除选项(如这里所要求的)。
可能最简单的方法是使用git存档。如果你真的只需要扩展的树,你可以这样做。
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帮助存档,它非常灵活。
请注意,即使存档文件不包含.git目录,但它也会包含其他隐藏的特定于git的文件,如.gitignore、.gitattributes等。如果您不希望它们在存档文件中,请确保在.gitattr文件中使用export-ignore属性,并在进行存档之前提交该属性。阅读更多。。。
注意:如果您对导出索引感兴趣,命令是
git checkout-index -a -f --prefix=/destination/path/
(更多详情请参见Greg的回答)
Bash实现git导出。
我已经将.empty文件的创建和删除过程划分为各自的功能,目的是在“gitarchive”实现中重新使用它们(稍后将发布)。
我还将“.gitattributes”文件添加到进程中,以便从目标导出文件夹中删除不需要的文件。在使“gitexport”功能更高效的同时,还包含了对流程的详细描述。
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导出/tmp/rel-1.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/{*~}”文件。。。完成。”“/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 3 11月12:57/tmp/rel-1.0.tgz我现在已经将“gitarchive”功能合并到一个使用“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;
}