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

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

这些解决方案中没有一个让我感到满意。最接近svn导出的可能是选项1,因为两者都要求目标目录首先为空。但选项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项目中执行命令,它总是跳转到前面所说的基本目录,直到修复为止,我个人更喜欢这个函数

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' -

其他回答

如果你想要一些与子模块一起工作的东西,这可能值得一试。

注:

MASTER_DIR=同时检出子模块的检出DEST_DIR=此导出的结束位置如果你有rsync,我想你可以用更少的球疼做同样的事情。

假设:

您需要从MASTER_DIR的父目录(即MASTER_DIRcd..)运行此命令DEST_DIR假定已创建。如果需要,这很容易修改为包含DEST_DIR的创建

cd MASTER_DIR&&tar-zcvf/DEST_DIR/export.tar.gz--exclude='.git*'.&&cd/DEST_DIR/&&tar xvfz导出.tar.gz&&rm导出.tar.gif

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

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

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

这将把一系列提交(C到G)中的文件复制到tar文件中。注意:这只会提交文件。不是整个存储库。此处略有修改

提交历史记录示例

A-->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

git diff树手册页

-r-->递归到子树中

--nocommit-id-->gitdiff树在适用时输出带有commit-id的行。此标志抑制了提交ID输出。

--name only-->仅显示已更改文件的名称。

--diff filter=ACMRT-->仅选择这些文件。请参阅此处以获取文件的完整列表

C..G-->此提交范围内的文件

C~-->包括提交C中的文件。不仅仅是提交C之后的文件。

|xargs tar-rf myTarFile-->输出到tar

从Git手册:

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

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

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

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