做一个“git export”(比如“svn export”)?

Do a “git export” (like “svn export”)?

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

  • git clone然后删除.git存储库目录。
  • git checkout-index暗示了这个功能,但是从"只需将所需的树读入索引......"开始,我不完全确定该怎么做。
  • git-export是第三方脚本,它基本上将git clone放入临时位置,然后将rsync --exclude='.git'放入最终目标。
  • 这些解决方案都没有让我感到满意。 最接近svn export的可能是选项1,因为这两者都要求目标目录首先为空。 但是假设我可以弄清楚将树读入索引意味着什么,选项2似乎更好。


    可能最简单的方法是使用git archive。如果你真的需要扩展树,你可以做这样的事情。

    1
    git archive master | tar -x -C /somewhere/else

    大多数时候我需要从git"导出"某些东西,我想要一个压缩存档,所以我做这样的事情。

    1
    git archive master | bzip2 >source-tree.tar.bz2

    ZIP存档:

    1
    git archive --format zip --output /full/path/to/zipfile.zip master

    git help archive了解更多细节,非常灵活。

    请注意,即使存档不包含.git目录,它也会包含其他隐藏的git特定文件,如.gitignore,.gitattributes等。如果您不想在存档中使用它们,请确保使用.gitattributes文件中的export-ignore属性并在进行归档之前提交此属性。阅读更多...

    注意:如果您对导出索引感兴趣,则命令为

    1
    git checkout-index -a -f --prefix=/destination/path/

    (有关详细信息,请参阅格雷格的答案)


    我发现了2选项意味着什么。从存储库中,您可以执行以下操作:

    1
    git checkout-index -a -f --prefix=/destination/path/

    路径末尾的斜杠很重要,否则会导致文件位于/ destination中,前缀为"path"。

    由于在正常情况下索引包含存储库的内容,因此"将所需的树读入索引"没有什么特别之处。它已经存在了。

    检查索引中的所有文件需要-a标志(我不确定在这种情况下省略此标志意味着什么,因为它不能满足我的要求)。 -f标志强制覆盖输出中的任何现有文件,此命令通常不会执行此操作。

    这似乎是我正在寻找的那种"git export"。


    git archive也适用于远程存储库。

    1
    2
    git archive --format=tar \
    --remote=ssh://remote_server/remote_repository master | tar -xf -

    要在repo中导出特定路径,请添加尽可能多的路径作为git的最后一个参数,例如:

    1
    2
    git archive --format=tar \
    --remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv


    enter image description here

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

    只需使用svn export

    据我所知,Github不允许archive --remote。虽然GitHub是svn兼容的,并且它们确实可以访问所有git repos svn,所以你可以像通常那样使用svn export对你的GitHub网址进行一些调整。

    例如,要导出整个存储库,请注意URL中的trunk如何替换master(或项目的HEAD分支设置为):

    1
    svn export https://github.com/username/repo-name/trunk/

    您可以导出单个文件甚至某个路径或文件夹:

    1
    svn export https://github.com/username/repo-name/trunk/src/lib/folder

    使用jQuery JavaScript库的示例

    HEAD分支或主分支将使用trunk

    1
    svn ls https://github.com/jquery/jquery/trunk

    HEAD分支可在/branches/下访问:

    1
    svn ls https://github.com/jquery/jquery/branches/2.1-stable

    /tags/下的所有标签都以相同的方式:

    1
    svn ls https://github.com/jquery/jquery/tags/2.1.3


    从Git手册:

    使用git-checkout-index"导出整个树"

    前缀能力基本上使得git-checkout-index用作"export as tree"函数变得微不足道。只需将所需的树读入索引,然后执行:

    $ git checkout-index --prefix=git-export-dir/ -a


    我写了一个围绕git-checkout-index的简单包装器,你可以像这样使用:

    1
    git export ~/the/destination/dir

    如果目标目录已存在,则需要添加-f--force

    安装简单;只需将脚本放在PATH中的某个位置,并确保它是可执行的。

    git-export的github存储库


    对于Git而言,这似乎不是SVN的问题。 Git只在存储库根目录中放置一个.git文件夹,而SVN在每个子目录中放置一个.svn文件夹。所以"svn export"避免了递归命令行魔术,而Git递归则没有必要。


    相当于

    1
    svn export . otherpath

    在现有的回购中是

    1
    git archive branchname | (cd otherpath; tar x)

    相当于

    1
    svn export url otherpath

    1
    git archive --remote=url branchname | (cd otherpath; tar x)


    如果您不排除.gitattributes export-ignore的文件,请尝试git checkout

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

    -f
    When checking out paths from the index, do not fail upon unmerged
    entries; instead, unmerged entries are ignored.

    -q
    Avoid verbose

    此外,您可以获取任何分支或标记,或者从SVN中的特定提交修订版添加SHA1(Git中的SHA1等同于SVN中的修订号)

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

    /path/to/checkout/必须为空,Git不会删除任何文件,但会覆盖具有相同名称的文件而不会发出任何警告

    更新:
    为了避免斩首问题或在使用checkout导出标签,分支或SHA1时保持工作存储库完整,您需要在末尾添加-- ./

    双破折号--告诉git破折号后的所有内容都是路径或文件,并且在这种情况下告诉git checkout不要更改HEAD

    例子:

    此命令将只获取libs目录以及完全提交的readme.txt文件

    1
    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两个提交

    1
    git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout HEAD^2 -f -q -- ./my_file_2_behind_HEAD.txt

    获得另一个分支的导出

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

    请注意,./是相对于存储库的根目录


    我广泛使用git-submodules。
    这个对我有用:

    1
    rsync -a ./FROM/ ./TO --exclude='.*'


    在寻找导出git存储库的方法时,我经常点击此页面。我对这个问题的回答考虑了svn export与git相比设计的三个属性,因为svn遵循集中式存储库方法:

    • 它通过不导出所有修订版来最小化到远程存储库位置的流量
    • 它不包含导出目录中的元信息
    • 使用svn导出某个分支是通过指定适当的路径来完成的

      1
      2
      git clone --depth 1 --branch master git://git.somewhere destination_path
      rm -rf destination_path/.git

    在构建特定版本时,克隆稳定分支(例如--branch stable--branch release/0.9)很有用。


    这将复制所有内容,减去.dot文件。我使用它来将git克隆的项目导出到我的web应用程序的git repo而没有.git的东西。

    cp -R ./path-to-git-repo /path/to/destination/

    普通的老bash工作得很好:)


    就像克隆一样简单,然后删除.git文件夹:


    git clone url_of_your_repo path_to_export && rm -rf path_to_export/.git


    是的,这是一个干净利落的命令,用于存档您的代码,而不会在存档中包含任何git,并且可以传递而不必担心任何git提交历史记录。

    1
    git archive --format zip --output /full/path/to/zipfile.zip master


    对于GitHub用户,git archive --remote方法不能直接使用,因为导出URL是短暂的。您必须向GitHub询问URL,然后下载该URL。 curl让事情变得简单:

    1
    curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -

    这将为您提供本地目录中的导出代码。例:

    1
    2
    3
    $ curl -L https://api.github.com/repos/jpic/bashworks/tarball | tar xzf -
    $ ls jpic-bashworks-34f4441/
    break  conf  docs  hack  LICENSE  mlog  module  mpd  mtests  os  README.rst  remote  todo  vcs  vps  wepcrack

    编辑
    如果您希望将代码放入特定的现有目录(而不是github中的随机目录):

    1
    2
    curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | \
    tar xzC /path/you/want --strip 1

    我只想指出你的情况

  • 导出存储库的子文件夹(这就是我以前使用SVN导出功能的方式)
  • 将所有内容从该文件??夹复制到部署目标都可以
  • 因为您已经拥有整个存储库的副本。
  • 然后你可以使用cp foo [destination]代替上面提到的git-archive master foo | -x -C [destination]


    您可以将任何提交的远程仓库归档为zip文件。

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

    Bash实现git-export。

    我已经在自己的函数上对.empty文件创建和删除过程进行了细分,目的是在'git-archive'实现中重用它们(稍后将发布)。

    我还将'.gitattributes'文件添加到进程中,以便从目标导出文件夹中删除不需要的文件。
    在使'git-export'功能更有效的同时包含了流程的冗长。

    "空" EMPTY_FILE =;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    function create_empty () {
    ## Processing path (target-dir):
        TRG_PATH="${1}";
    ## Component(s):
        EXCLUDE_DIR=".git";
    echo -en"
    Adding '${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"
    Purging 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.
    "
    ## 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"
    ${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"
    Checking-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;
      }

    Output:

    $ git-export /tmp/rel-1.0.0

    Adding '.empty' files to empty folder(s): ... done.

    Checking-Out Index component(s): ... done.

    Resetting HEAD and Index: ... done.

    Purging Git-Specific component(s): ...

    '/tmp/rel-1.0.0/{.buildpath}' files ... done.'

    '/tmp/rel-1.0.0/{.project}' files ... done.'

    '/tmp/rel-1.0.0/{.gitignore}' files ... done.'

    '/tmp/rel-1.0.0/{.git}' files ... done.'

    '/tmp/rel-1.0.0/{.gitattributes}' files ... done.'

    '/tmp/rel-1.0.0/{*.mno}' files ... done.'

    '/tmp/rel-1.0.0/{*~}' files ... done.'

    '/tmp/rel-1.0.0/{.*~}' files ... done.'

    '/tmp/rel-1.0.0/{*.swp}' files ... done.'

    '/tmp/rel-1.0.0/{*.swo}' files ... done.'

    '/tmp/rel-1.0.0/{.DS_Store}' files ... done.'

    '/tmp/rel-1.0.0/{.settings}' files ... done.'

    '/tmp/rel-1.0.0/{.empty}' files ... done.'

    done.

    Archiving Checked-Out component(s): ... done.

    -rw-r--r-- 1 admin wheel 25445901 3 Nov 12:57 /tmp/rel-1.0.0.tgz

    I have now incorporated the 'git archive' functionality into a single process that makes use of 'create_empty' function and other features.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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"
    ";
    #    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;
      }


    如果你想要一些适用于子模块的东西,这可能是值得的。

    注意:

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

    假设:

    • 你需要从MASTER_DIR的父目录运行它(即从MASTER_DIR cd ..)
    • 假设已创建DEST_DIR。如果您愿意,这很容易修改以包括创建DEST_DIR

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


    这会将提交范围(C到G)中的文件复制到tar文件中。注意:这只会提交文件。不是整个存储库。从这里略微修改

    提交历史示例

    A - > B - > C - > D - > E - > F - > G - > H - > I

    1
    git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT C~..G | xargs tar -rf myTarFile.tar

    git-diff-tree手册

    -r - >递归到子树

    --no-commit-id - > git diff-tree在适用时输出带有提交ID的行。此标志禁止提交ID输出。

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

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

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

    C~ - >包含来自Commit C的文件。不仅仅是自Commit C以来的文件。

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


    我的偏好实际上是在Makefile(或其他构建系统)中有一个dist目标,它导出代码的可分发存档(.tar.bz2,.zip,.jar或任何合适的东西)。如果您碰巧使用GNU autotools或Perl的MakeMaker系统,我认为这是自动存在的。如果没有,我强烈建议添加它。

    ETA(2012-09-06):哇,苛刻的downvotes。我仍然认为使用构建工具而不是源代码控制工具构建发行版会更好。我相信使用构建工具构建工件。在我目前的工作中,我们的主要产品是用蚂蚁目标建造的。我们正在切换源代码控制系统,并且这个蚂蚁目标的存在意味着迁移中的麻烦减少了。


    这样做很简单,这是.bash_profile的一个功能,它直接在当前位置解压缩存档,首先配置您通常的[url:path]。注意:使用此功能可以避免克隆操作,它可以直接从远程仓库获取。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    gitss() {
        URL=[url:path]

        TMPFILE="`/bin/tempfile`"
        if ["$1" ="" ]; then
            echo -e"Use: gitss repo [tree/commit]
    "
            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"
    Done
    "
        rm $TMPFILE
    }

    .gitconfig的别名,需要相同的配置(TAKE CARE执行.git项目中的命令,它总是先前跳转到基础目录,如此处所述,直到修复此我个人更喜欢该功能

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/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


    正如我理解这个问题一样,它更多的是从服务器下载某个状态,没有历史记录,没有其他分支的数据,而不是从本地存储库中提取状态(这里有很多答案)。

    这可以这样做:

    1
    2
    git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
    && rm -rf repo/.git/
    • --single-branch自Git 1.7.10(2012年4月)起可用。
    • --depth据报道是错误的,但对于出口情况,上述问题无关紧要。


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

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

    我认为@Aredridel的帖子最接近,但还有更多 - 所以我会在这里添加;问题是,在svn中,如果您在回购的子文件夹中,并执行以下操作:

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

    然后svn将导出所有受版本控制的文件(它们也可以新添加;或者已修改状态) - 如果你在该目录中有其他"垃圾"(我在这里不算.svn子文件夹,但可见的东西,如.o文件),它不会被导出;只导出SVN仓库注册的文件。对我来说,一个好处是这个导出还包括尚未提交的本地更改的文件;另一个好处是导出文件的时间戳与原始文件的时间戳相同。或者,正如svn help export所说:

  • Exports a clean directory tree from the working copy specified by
    PATH1, at revision REV if it is given, otherwise at WORKING, into
    PATH2. ... If REV is not specified, all local
    changes will be preserved. Files not under version control will
    not be copied.
  • 要意识到git不会保留时间戳,请比较这些命令的输出(在您选择的git repo的子文件夹中):

    1
    /media/disk/git_svn/subdir$ ls -la .

    ......和:

    1
    /media/disk/git_svn/subdir$ git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)

    ...在任何情况下,我都注意到git archive会导致归档文件的所有时间戳都相同! git help archive说:

    git archive behaves differently when given a tree ID versus when given a commit ID or tag ID. In the first case the
    current time is used as the modification time of each file in the archive. In the latter case the commit time as recorded
    in the referenced commit object is used instead.

    ......但显然两种情况都设定了"每个文件的修改时间";从而不保留这些文件的实际时间戳!

    所以,为了也保留时间戳,这里是一个bash脚本,实际上是一个"单行",虽然有点复杂 - 所以下面是多个行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /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/subdir)中的内容 - 并且您导出的目标位置有些不方便,但它位于DEST环境变量中。请注意,使用此脚本;在运行上述脚本之前,必须自己手动创建DEST目录。

    运行脚本后,您应该可以比较:

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

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

    希望这有助于某人,
    干杯!


    到目前为止,我所见过的最简单的方法(也适用于Windows)是git bundle

    git bundle create /some/bundle/path.bundle --all

    有关更多详细信息,请参阅此答案:如何通过USB驱动器将我的git存储库从我的Windows机器复制到linux机器?


    如果您要在要创建导出的计算机上拥有存储库的本地副本,我还有另一种解决方案可以正常工作。在这种情况下,请移至此存储库目录,然后输入以下命令:

    GIT_WORK_TREE=outputdirectory git checkout -f

    如果您使用git存储库管理网站并希望在/var/www/中签出一个干净的版本,这将特别有用。在这种情况下,在.git/hooks/post-receive脚本中添加此命令(裸存储库上的hooks/post-receive,在这种情况下更合适)


    如果你也需要子模块,这应该可以解决这个问题:https://github.com/meitar/git-archive-all.sh/wiki


    我的.bashrc文件中有以下实用程序函数:它在git存储库中创建当前分支的存档。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function garchive()
    {
      if [["x$1" =="x-h" ||"x$1" =="x" ]]; then
        cat <<EOF
    Usage: garchive
    create zip archive of the current branch into
    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
    }

    选项1听起来效率不高。如果客户端中没有空间来执行克隆然后删除.git文件夹,该怎么办?

    今天我发现自己试图这样做,客户端是Raspberry Pi,几乎没有空间。此外,我还想从存储库中排除一些繁重的文件夹。

    选项2和其他答案在这种情况下无济于事。 git archive(因为需要提交.gitattributes文件,我不想将此排除保存在存储库中)。

    在这里,我分享我的解决方案,类似于选项3,但不需要git clone

    1
    2
    3
    tmp=`mktemp`
    git ls-tree --name-only -r HEAD > $tmp
    rsync -avz --files-from=$tmp --exclude='fonts/*' . raspberry:

    更改压缩的等效行的rsync行也可用作git archive但具有一种排除选项(如此处所述)。