我一直在想,是否有一个好的“gitexport”解决方案可以创建一个没有.git存储库目录的树的副本。我知道至少有三种方法:

git克隆,然后删除.git存储库目录。git签出索引暗示了这一功能,但以“只需将所需的树读入索引……”开头,我不完全确定该怎么做。gitexport是一个第三方脚本,本质上是将git克隆到临时位置,然后再将rsync--exclude='.git'复制到最终目标。

这些解决方案中没有一个让我感到满意。最接近svn导出的可能是选项1,因为两者都要求目标目录首先为空。但选项2似乎更好,假设我能够理解将树读入索引意味着什么。


当前回答

我需要这个作为部署脚本,但我不能使用上面提到的任何方法。相反,我想出了一个不同的解决方案:

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

其他回答

我的.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
}

我认为@Aredridel的帖子是最接近的,但还有更多的内容——所以我将在这里补充这一点;问题是,在svn中,如果你在repo的子文件夹中,并且你做到了:

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

然后svn将导出所有受修订控制的文件(它们也可能是新添加的;或已修改的状态)-如果您在该目录中有其他“垃圾”(我不在这里计算.svn子文件夹,而是像.o文件这样的可见文件),它将不会导出;将仅导出SVN repo注册的那些文件。对我来说,一件好事是,这个导出还包括尚未提交的具有本地更改的文件;另一个好处是导出文件的时间戳与原始文件的时间相同。或者,正如svn help export所说:

从指定的工作副本导出干净的目录树路径1,修订版本REV(如果给出),否则在工作时路径2….如果未指定REV,则所有本地将保留更改。不受版本控制的文件将不能复制。

要了解git不会保留时间戳,请比较以下命令的输出(在您选择的git repo的子文件夹中):

/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 -)

…无论如何,我注意到gitarchive会导致归档文件的所有时间戳都相同!git帮助存档说:

git存档在给定树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/subdr)中的内容,并且导出到的目标位置有些不方便,但它位于DEST环境变量中。请注意,使用此脚本;在运行上述脚本之前,必须自己手动创建DEST目录。

运行脚本后,您应该能够比较:

ls -la /media/disk/git_svn/subdir
ls -la /media/diskC/tmp/subdirB   # DEST

…并希望看到相同的时间戳(对于那些受版本控制的文件)。

希望这对某人有所帮助,干杯

可能最简单的方法是使用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的回答)

到目前为止,我看到的最简单的方法(也适用于windows)是gitbundle:

git bundle create/some/bundle/path.bundle--全部

有关更多详细信息,请参阅以下答案:如何通过usb驱动器将git存储库从windows机器复制到linux机器?

如果存储库托管在GitHub上,则为特殊情况。

只需使用svn导出。

据我所知,Github不允许存档--远程。虽然GitHub是svn兼容的,而且他们确实有所有的git repos svn可访问,所以你可以像平常一样使用svn导出,只需对GitHub url进行一些调整。

例如,要导出整个存储库,请注意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分支或主分支将使用主干:

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