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

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

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


当前回答

在添加前缀(例如目录名)时将git导出到zip存档:

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

其他回答

从Git手册:

使用git签出索引“导出整个树”

前缀功能基本上使使用git签出索引作为“导出为树”函数变得简单。只需将所需的树读入索引,然后执行以下操作:

$git签出索引--prefix=git导出目录/-a

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

如果您也需要子模块,这应该可以做到:https://github.com/meitar/git-archive-all.sh/wiki

我认为@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导出到zip存档:

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