我一直在想,是否有一个好的“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

其他回答

我认为@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

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

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

如果不排除具有.gitattributes导出忽略的文件,请尝试git签出

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

-f级从索引中检出路径时,不要在未合并时失败条目;相反,将忽略未合并的条目。

and

-问避免冗长

此外,您可以从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签出不更改HEAD

示例:

该命令将仅获取libs目录以及来自该提交的readme.txt文件

git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout fef2e1f2de5f3d4f5e87df7d8 -f -q -- ./libs ./docs/readme.txt

这将在头部HEAD^2后面创建(覆盖)my_file_2_behind_HEAD.txt两次提交

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手册:

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

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

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

这将复制除.dot文件之外的所有内容。我使用这个将git克隆项目导出到我的web应用程序的git repo中,而不使用.git文件。

cp-R/git repo/path/to/destination的路径/

简单的旧bash非常有用:)

您可以在任何提交时将远程回购存档为zip文件。

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