执行“git 导出” (如“svn 导出”)?

发布于 2024-07-06 16:57:22 字数 640 浏览 7 评论 0 原文

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

  1. git clone,然后删除.git存储库目录。
  2. git checkout-index 暗示了此功能,但以“将所需的树读入索引...”开头,我不完全确定该怎么做。
  3. git-export 是一个第三方脚本,本质上是将 git clone 复制到临时位置,然后将 rsync --exclude='.git' 复制到最终目的地。

这些解决方案都没有让我真正满意。 与 svn export 最接近的可能是选项 1,因为两者都要求目标目录首先为空。 但选项 2 似乎更好,假设我可以弄清楚将树读入索引意味着什么。

I've been wondering whether there is a good "git export" solution that creates a copy of a tree without the .git repository directory. There are at least three methods I know of:

  1. git clone followed by removing the .git repository directory.
  2. git checkout-index alludes to this functionality but starts with "Just read the desired tree into the index..." which I'm not entirely sure how to do.
  3. git-export is a third-party script that essentially does a git clone into a temporary location followed by rsync --exclude='.git' into the final destination.

None of these solutions really strike me as being satisfactory. The closest one to svn export might be option 1, because both require the target directory to be empty first. But option 2 seems even better, assuming I can figure out what it means to read a tree into the index.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

云归处 2024-07-13 16:57:22

实现这一目标的最简单方法可能是使用 git archive。 如果你真的只需要扩展树,你可以这样做。

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 help archive 了解更多详细信息,非常详细灵活的。


请注意,即使存档不包含 .git 目录,它也会包含其他隐藏的 git 特定文件,如 .gitignore、.gitattributes 等。如果您不希望它们出现在存档中,请确保您使用 .gitattributes 文件中的 export-ignore 属性,并在归档之前提交该属性。 了解更多...


注意:如果您有兴趣导出索引,则命​​令是

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

(有关更多详细信息,请参阅 Greg'sanswer


下面是在 Linux 上使用 libchrony 的真实示例:

mkdir $HOME/dev
cd $HOME/dev
pushd /tmp
git clone https://gitlab.com/chrony/libchrony.git
cd libchrony
BRANCH=$(git rev-parse --abbrev-ref HEAD)
git archive -o ../libchrony.zip --prefix="libchrony/" $BRANCH
popd
unzip /tmp/libchrony.zip

这些命令生成一个 zip 文件并将其解压到 $HOME/dev/libchrony 中。 我们可以使用以下命令查看存档:

$ unzip -v /tmp/libchrony
Archive:  /tmp/libchrony.zip
e0a3807f770b56f6b0e9833254baa7c4fc13564b
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 2023-07-20 09:37 00000000  libchrony/
      49  Defl:N       47   4% 2023-07-20 09:37 37c3f2e2  libchrony/.gitignore
   26530  Defl:N     9350  65% 2023-07-20 09:37 5622583e  libchrony/COPYING
     961  Defl:N      467  51% 2023-07-20 09:37 da9221e3  libchrony/Makefile
     475  Defl:N      304  36% 2023-07-20 09:37 cae27f70  libchrony/README.adoc
    3313  Defl:N     1119  66% 2023-07-20 09:37 37eb110f  libchrony/chrony.h
    7673  Defl:N     2261  71% 2023-07-20 09:37 5d455a52  libchrony/client.c
    6190  Defl:N     2093  66% 2023-07-20 09:37 7ea9d81b  libchrony/example-reports.c
   16348  Defl:N     3855  76% 2023-07-20 09:37 e82f5fe3  libchrony/message.c
    2946  Defl:N     1099  63% 2023-07-20 09:37 945ee82b  libchrony/message.h
--------          -------  ---                            -------
   64485            20595  68%                            10 files

Probably the simplest way to achieve this is with git archive. If you really need just the expanded tree you can do something like this.

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

Most of the time that I need to 'export' something from git, I want a compressed archive in any case so I do something like this.

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

ZIP archive:

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

git help archive for more details, it's quite flexible.


Be aware that even though the archive will not contain the .git directory, it will, however, contain other hidden git-specific files like .gitignore, .gitattributes, etc. If you don't want them in the archive, make sure you use the export-ignore attribute in a .gitattributes file and commit this before doing your archive. Read more...


Note: If you are interested in exporting the index, the command is

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

(See Greg's answer for more details)


Here's a real-world example using libchrony on Linux:

mkdir $HOME/dev
cd $HOME/dev
pushd /tmp
git clone https://gitlab.com/chrony/libchrony.git
cd libchrony
BRANCH=$(git rev-parse --abbrev-ref HEAD)
git archive -o ../libchrony.zip --prefix="libchrony/" $BRANCH
popd
unzip /tmp/libchrony.zip

Those commands produce a zip file and extract it into $HOME/dev/libchrony. We can peek into the archive using:

$ unzip -v /tmp/libchrony
Archive:  /tmp/libchrony.zip
e0a3807f770b56f6b0e9833254baa7c4fc13564b
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 2023-07-20 09:37 00000000  libchrony/
      49  Defl:N       47   4% 2023-07-20 09:37 37c3f2e2  libchrony/.gitignore
   26530  Defl:N     9350  65% 2023-07-20 09:37 5622583e  libchrony/COPYING
     961  Defl:N      467  51% 2023-07-20 09:37 da9221e3  libchrony/Makefile
     475  Defl:N      304  36% 2023-07-20 09:37 cae27f70  libchrony/README.adoc
    3313  Defl:N     1119  66% 2023-07-20 09:37 37eb110f  libchrony/chrony.h
    7673  Defl:N     2261  71% 2023-07-20 09:37 5d455a52  libchrony/client.c
    6190  Defl:N     2093  66% 2023-07-20 09:37 7ea9d81b  libchrony/example-reports.c
   16348  Defl:N     3855  76% 2023-07-20 09:37 e82f5fe3  libchrony/message.c
    2946  Defl:N     1099  63% 2023-07-20 09:37 945ee82b  libchrony/message.h
--------          -------  ---                            -------
   64485            20595  68%                            10 files
莫言歌 2024-07-13 16:57:22

我明白了选项2的含义。 从存储库中,您可以执行以下操作:

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

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

由于在正常情况下索引包含存储库的内容,因此无需执行任何特殊操作即可“将所需的树读入索引”。 它已经在那里了。

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

这似乎是我正在寻找的那种“git 导出”。

I found out what option 2 means. From a repository, you can do:

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

The slash at the end of the path is important, otherwise it will result in the files being in /destination with a prefix of 'path'.

Since in a normal situation the index contains the contents of the repository, there is nothing special to do to "read the desired tree into the index". It's already there.

The -a flag is required to check out all files in the index (I'm not sure what it means to omit this flag in this situation, since it doesn't do what I want). The -f flag forces overwriting any existing files in the output, which this command doesn't normally do.

This appears to be the sort of "git export" I was looking for.

游魂 2024-07-13 16:57:22

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

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

要导出存储库内的特定路径,请添加任意多个路径作为 git 的最后一个参数,例如:

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

git archive also works with remote repository.

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

To export particular path inside the repo add as many paths as you wish as last argument to git, e.g.:

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv
木槿暧夏七纪年 2024-07-13 16:57:22

在此处输入图像描述

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

只需使用svn导出

据我所知,Github 不允许 archive --remote。 尽管 GitHub 是 svn 兼容 并且他们确实拥有所有 git 存储库 svn< /code> 可访问,因此您可以像平常一样使用 svn export ,只需对 GitHub url 进行一些调整即可。

例如,要导出整个存储库,请注意 URL 中的 trunk 如何替换 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 分支或 ma​​ster 分支将可使用 < code>trunk:

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

enter image description here

A special case answer if the repository is hosted on GitHub.

Just use svn export.

As far as I know Github does not allow archive --remote. Although GitHub is svn compatible and they do have all git repos svn accessible so you could just use svn export like you normally would with a few adjustments to your GitHub url.

For example to export an entire repository, notice how trunk in the URL replaces master (or whatever the project's HEAD branch is set to):

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

And you can export a single file or even a certain path or folder:

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

Example with jQuery JavaScript Library

The HEAD branch or master branch will be available using trunk:

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

The non-HEAD branches will be accessible under /branches/:

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

All tags under /tags/ in the same fashion:

svn ls https://github.com/jquery/jquery/tags/2.1.3
影子的影子 2024-07-13 16:57:22

来自 Git 手册< /a>:

使用 git-checkout-index 来“导出整个树”

前缀功能基本上使得使用 git-checkout-index 作为“导出为树”功能变得微不足道。 只需将所需的树读入索引,然后执行:

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

From the Git Manual:

Using git-checkout-index to "export an entire tree"

The prefix ability basically makes it trivial to use git-checkout-index as an "export as tree" function. Just read the desired tree into the index, and do:

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

失退 2024-07-13 16:57:22

我已经为 git-checkout-index 编写了一个简单的包装器,您可以像这样使用:

git export ~/the/destination/dir

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

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

git-export的 github 存储库

I've written a simple wrapper around git-checkout-index that you can use like this:

git export ~/the/destination/dir

If the destination directory already exists, you'll need to add -f or --force.

Installation is simple; just drop the script somewhere in your PATH, and make sure it's executable.

The github repository for git-export

沉默的熊 2024-07-13 16:57:22

看来 Git 的问题比 SVN 的问题要小。 Git 仅在存储库根目录中放置一个 .git 文件夹,而 SVN 在每个子目录中放置一个 .svn 文件夹。 因此“svn export”避免了递归命令行魔法,而使用 Git 则不需要递归。

It appears that this is less of an issue with Git than SVN. Git only puts a .git folder in the repository root, whereas SVN puts a .svn folder in every subdirectory. So "svn export" avoids recursive command-line magic, whereas with Git recursion is not necessary.

挽袖吟 2024-07-13 16:57:22

相当于

svn export . otherpath

在现有存储库中是

git archive branchname | (cd otherpath; tar x)

相当于

svn export url otherpath

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

The equivalent of

svn export . otherpath

inside an existing repo is

git archive branchname | (cd otherpath; tar x)

The equivalent of

svn export url otherpath

is

git archive --remote=url branchname | (cd otherpath; tar x)
迷离° 2024-07-13 16:57:22

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

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

-f
从索引中检查路径时,未合并时不会失败
条目; 相反,未合并的条目将被忽略。

-q
避免冗长

此外,您可以从特定的提交修订中获取任何分支或标签,例如在 SVN 中只需添加 SHA1(Git 中的 SHA1 相当于 SVN 中的修订号)

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

/path/to/checkout/ 必须为空,Git 不会删除任何文件,但会覆盖同名文件且没有任何警告

更新:
请注意上例中末尾的 -- ./。 这是为了避免使用带有标签、分支或 SHA1 的 checkout 导出时出现斩首问题。 双破折号 -- 告诉 git 破折号后面的所有内容都是路径或文件,并且在这种情况下告诉 git checkout 不要更改 HEAD。 路径 ./ 相对于存储库的根目录。

其他示例:

此命令将仅获取 libs 目录以及来自另一个分支的 readme.txt 文件

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

这将在 head 后面创建(覆盖)my_file_2_behind_HEAD.txt 两次提交 <代码>HEAD^2

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

更新2:
为了避免在使用自定义 SHA1(或标签、分支)时出现索引更改问题,请强制 Git 使用临时索引文件

GIT_INDEX_FILE=/path/to/tmp/index git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout 2ef2e1f2de -f -q -- ./
rm /path/to/tmp/index

(注意:使用 GIT_INDEX_FILE 的绝对路径更安全)。

If you're not excluding files with .gitattributes export-ignore then try git checkout

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.

and

-q
Avoid verbose

Additionally you can get any Branch or Tag or from a specific Commit Revision like in SVN just adding the SHA1 (SHA1 in Git is the equivalent to the Revision Number in SVN)

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

The /path/to/checkout/ must be empty, Git will not delete any file, but will overwrite files with the same name without any warning

UPDATE:
Note -- ./ at the end in the above example. It is to avoid the beheaded problem when using checkout for export with tags, branches or SHA1. The double dash -- tells git that everything after the dashes are paths or files, and also in this case tells git checkout to not change the HEAD. The path ./ is relative to the root of the repository.

Other examples:

This command will get just the libs directory and also the readme.txt file from another branch

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

This will create(overwrite) my_file_2_behind_HEAD.txt two commits behind the head HEAD^2

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

UPDATE 2:
To avoid problem with changed index when using custom SHA1 (or tag, branch), force Git to use temporary index file

GIT_INDEX_FILE=/path/to/tmp/index git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout 2ef2e1f2de -f -q -- ./
rm /path/to/tmp/index

(Note: It's safer to use absolute path for GIT_INDEX_FILE).

随波逐流 2024-07-13 16:57:22

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

  • 它通过不导出所有修订来最小化远程存储库位置的流量

  • 它不在导出目录中包含元信息

  • 使用svn导出某个分支是通过指定适当的路径来完成的

     git clone --深度 1 --branch main git://git.somewhere 目的地路径 
        rm -rf 目标路径/.git 
      

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

I have hit this page frequently when looking for a way to export a git repository. My answer to this question considers three properties that svn export has by design compared to git, since svn follows a centralized repository approach:

  • It minimizes the traffic to a remote repository location by not exporting all revisions

  • It does not include meta information in the export directory

  • Exporting a certain branch using svn is accomplished by specifying the appropriate path

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

When building a certain release it is useful to clone a stable branch as for example --branch stable or --branch release/0.9.

萌面超妹 2024-07-13 16:57:22

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

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

I use git-submodules extensively.
This one works for me:

rsync -a ./FROM/ ./TO --exclude='.*'
呢古 2024-07-13 16:57:22

这将复制所有内容,减去 .dot 文件。 我用它来将 git 克隆项目导出到我的 Web 应用程序的 git 存储库中,而无需 .git 内容。

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

普通的旧 bash 效果很好:)

This will copy all contents, minus the .dot files. I use this to export git cloned projects into my web app's git repo without the .git stuff.

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

Plain old bash works just great :)

姜生凉生 2024-07-13 16:57:22

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

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

As simple as clone then delete the .git folder:

git clone url_of_your_repo path_to_export && rm -rf path_to_export/.git
夜深人未静 2024-07-13 16:57:22

对于 GitHub 用户,git archive --remote 方法无法直接使用,因为 导出 URL 是临时的。 您必须向 GitHub 请求 URL,然后下载该 URL。 curl 让这变得简单:

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

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

$ 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 的随机目录):

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

For GitHub users, the git archive --remote method won't work directly, as the export URL is ephemeral. You must ask GitHub for the URL, then download that URL. curl makes that easy:

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

This will give you the exported code in a local directory. Example:

$ 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

Edit
If you want the code put into a specific, existing directory (rather than the random one from github):

curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | \
tar xzC /path/you/want --strip 1
失去的东西太少 2024-07-13 16:57:22

是的,是一个干净整洁的命令,用于存档代码,存档中不包含任何 git,并且很适合传递不用担心任何 git 提交历史记录。

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

Yes, this is a clean and neat command to archive your code without any git inclusion in the archive and is good to pass around without worrying about any git commit history.

git archive --format zip --output /full/path/to/zipfile.zip master 
吝吻 2024-07-13 16:57:22

我只是想指出,如果您要

  1. 导出存储库的子文件夹(这就是我过去使用 SVN 导出功能的方式),则
  2. 可以将该文件夹中的所有内容复制到部署目标
  3. ,因为您已经有了一个副本整个存储库到位。

然后你可以使用 cp foo [destination] 代替提到的 git-archive master foo | -x -C [目标]。

I just want to point out that in the case that you are

  1. exporting a sub folder of the repository (that's how I used to use SVN export feature)
  2. are OK with copying everything from that folder to the deployment destination
  3. and since you already have a copy of the entire repository in place.

Then you can just use cp foo [destination] instead of the mentioned git-archive master foo | -x -C [destination].

韬韬不绝 2024-07-13 16:57:22

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

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

You can archive a remote repo at any commit as zip file.

git archive --format=zip --output=archive.zip --remote=USERNAME@HOSTNAME:PROJECTNAME.git HASHOFGITCOMMIT
温馨耳语 2024-07-13 16:57:22

如果您想要与子模块一起使用的东西,这可能值得一试。

注意:

  • 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 导出.tar.gz && rm 导出.tar.gz

If you want something that works with submodules this might be worth a go.

Note:

  • MASTER_DIR = a checkout with your submodules checked out also
  • DEST_DIR = where this export will end up
  • If you have rsync, I think you'd be able to do the same thing with even less ball ache.

Assumptions:

  • You need to run this from the parent directory of MASTER_DIR ( i.e from MASTER_DIR cd .. )
  • DEST_DIR is assumed to have been created. This is pretty easy to modify to include the creation of a DEST_DIR if you wanted to

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

高速公鹿 2024-07-13 16:57:22

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

ETA (2012-09-06):哇,严厉的反对票。 我仍然相信使用构建工具构建发行版比使用源代码控制工具更好。 我相信使用构建工具来构建工件。 在我目前的工作中,我们的主要产品是用 ant 目标构建的。 我们正在切换源代码控制系统,而这个 ant 目标的存在意味着迁移过程中减少了一些麻烦。

My preference would actually be to have a dist target in your Makefile (or other build system) that exports a distributable archive of your code (.tar.bz2, .zip, .jar, or whatever is appropriate). If you happen to be using GNU autotools or Perl's MakeMaker systems, I think this exists for you automatically. If not, I highly recommend adding it.

ETA (2012-09-06): Wow, harsh downvotes. I still believe it is better to build your distributions with your build tools rather than your source code control tool. I believe in building artifacts with build tools. In my current job, our main product is built with an ant target. We are in the midst of switching source code control systems, and the presence of this ant target means one less hassle in migration.

且行且努力 2024-07-13 16:57:22

据我了解这个问题,它更多的是从服务器下载某些状态,没有历史记录,也没有其他分支的数据,而不是从本地存储库中提取状态(就像这里的许多 anwsers 所做的那样)。

可以这样完成:

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 月)起可用。
  • 据报道,--深度是(曾经是?) 有缺陷,但对于导出的情况,上述问题应该无关紧要。

As I understand the question, it it more about downloading just certain state from the server, without history, and without data of other branches, rather than extracting a state from a local repository (as many anwsers here do).

That can be done like this:

git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
  • --single-branch is available since Git 1.7.10 (April 2012).
  • --depth is (was?) reportedly faulty, but for the case of an export, the mentioned issues should not matter.
安静被遗忘 2024-07-13 16:57:22

git 导出的 Bash 实现。

我根据自己的功能对 .empty 文件创建和删除过程进行了分段,目的是在“git-archive”实现中重新使用它们(稍后发布)。

我还将“.gitattributes”文件添加到该进程中,以便从目标导出文件夹中删除不需要的文件。
流程更加详细,同时使“git-export”功能更加高效。

EMPTY_FILE=".空";

function create_empty () {
## Processing path (target-dir):
    TRG_PATH="${1}";
## Component(s):
    EXCLUDE_DIR=".git";
echo -en "\nAdding '${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 "\nPurging 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.\n"
## 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 "\n${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 "\nChecking-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;
  }

输出:

$ git-export /tmp/rel-1.0.0

将“.empty”文件添加到空文件夹:...完成。

签出索引组件:...完成。

重置 HEAD 和索引:...完成。

清除特定于 Git 的组件:...

“/tmp/rel-1.0.0/{.buildpath}”文件...完成。'

“/tmp/rel-1.0.0/{.project}”文件...完成。'

“/tmp/rel-1.0.0/{.gitignore}”文件...完成。'

“/tmp/rel-1.0.0/{.git}”文件...完成。'

“/tmp/rel-1.0.0/{.gitattributes}”文件...完成。'

“/tmp/rel-1.0.0/{*.mno}”文件...完成。'

'/tmp/rel-1.0.0/{*~}' 文件...完成。'

“/tmp/rel-1.0.0/{.*~}”文件...完成。'

“/tmp/rel-1.0.0/{*.swp}”文件...完成。'

“/tmp/rel-1.0.0/{*.swo}”文件...完成。'

“/tmp/rel-1.0.0/{.DS_Store}”文件...完成。”

“/tmp/rel-1.0.0/{.settings}”文件...完成。'

“/tmp/rel-1.0.0/{.empty}”文件...完成。'

完成。

归档签出的组件:...完成。

-rw-r--r-- 1 个管理轮 25445901 11 月 3 日 12:57 /tmp/rel-1.0.0.tgz

我现在已将“git archive”功能合并到一个使用“create_empty”函数和其他功能的进程中。

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 "\n";
#    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;
  }

Bash-implementation of git-export.

I have segmented the .empty file creation and removal processes on their own function, with the purpose of re-using them in the 'git-archive' implementation (will be posted later on).

I have also added the '.gitattributes' file to the process in order to remove un-wanted files from the target export folder.
Included verbosity to the process while making the 'git-export' function more efficient.

EMPTY_FILE=".empty";

function create_empty () {
## Processing path (target-dir):
    TRG_PATH="${1}";
## Component(s):
    EXCLUDE_DIR=".git";
echo -en "\nAdding '${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 "\nPurging 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.\n"
## 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 "\n${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 "\nChecking-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.

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 "\n";
#    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;
  }
魂归处 2024-07-13 16:57:22

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

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

a git export to a zip archive while adding a prefix (e.g. directory name):

git archive master --prefix=directoryWithinZip/  --format=zip -o out.zip
酒中人 2024-07-13 16:57:22

这会将一系列提交(C 到 G)中的文件复制到 tar 文件。 注意:这只会获取已提交的文件。 不是整个存储库。 从此处

示例提交 稍作修改历史

A --> B——> C--> D——> E--> F——> G--> H——> 我

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 输出。

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

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

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

C~ --> 包括来自提交 C 的文件。不仅仅是自提交 C 以来的文件

。 xargs tar -rf myTarFile --> 输出到焦油

This will copy the files in a range of commits (C to G) to a tar file. Note: this will only get the files commited. Not the entire repository. Slightly modified from Here

Example Commit History

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-tree Manual Page

-r --> recurse into sub-trees

--no-commit-id --> git diff-tree outputs a line with the commit ID when applicable. This flag suppressed the commit ID output.

--name-only --> Show only names of changed files.

--diff-filter=ACMRT --> Select only these files. See here for full list of files

C..G --> Files in this range of commits

C~ --> Include files from Commit C. Not just files since Commit C.

| xargs tar -rf myTarFile --> outputs to tar

风为裳 2024-07-13 16:57:22

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

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

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

By far the easiest way i've seen to do it (and works on windows as well) is git bundle:

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

See this answer for more details: How can I copy my git repository from my windows machine to a linux machine via usb drive?

标点 2024-07-13 16:57:22

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

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

I needed this for a deploy script and I couldn't use any of the above mentioned approaches. Instead I figured out a different solution:

#!/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
情独悲 2024-07-13 16:57:22

方法很简单,这是 .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' -

Doing it the easy way, this is a function for .bash_profile, it directly unzips the archive on current location, configure first your usual [url:path]. NOTE: With this function you avoid the clone operation, it gets directly from the remote repo.

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
}

Alias for .gitconfig, same configuration required (TAKE CARE executing the command inside .git projects, it ALWAYS jumps to the base dir previously as said here, until this is fixed I personally prefer the function

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' -
夜雨飘雪 2024-07-13 16:57:22

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

GIT_WORK_TREE=outputdirectory git checkout -f

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

I have another solution that works fine if you have a local copy of the repository on the machine where you would like to create the export. In this case move to this repository directory, and enter this command:

GIT_WORK_TREE=outputdirectory git checkout -f

This is particularly useful if you manage a website with a git repository and would like to checkout a clean version in /var/www/. In this case, add thiscommand in a .git/hooks/post-receive script (hooks/post-receive on a bare repository, which is more suitable in this situation)

新人笑 2024-07-13 16:57:22

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

If you need submodules as well, this should do the trick: https://github.com/meitar/git-archive-all.sh/wiki

残花月 2024-07-13 16:57:22

我认为 @Arredridel 的帖子是最接近的,但还有更多内容 - 所以我将在这里添加它; 问题是,在 svn 中,如果您位于存储库的子文件夹中,并且执行以下操作:

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

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

  • 从指定的工作副本中导出干净的目录树
    PATH1,在修订版 REV(如果已给出),否则在 WORKING 处,进入
    路径2。 ...如果未指定 REV,则所有本地
    更改将被保留。 不受版本控制的文件将
    不得复制。
  • 要认识到 git 不会保留时间戳,请比较这些命令的输出(在您选择的 git 存储库的子文件夹中):

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

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

    当给定树 ID 和给定提交 ID 或标记 ID 时,git 存档的行为有所不同。 在第一种情况下
    当前时间用作存档中每个文件的修改时间。 在后一种情况下,记录的提交时间
    而是使用引用的提交对象中的内容。

    ...但显然这两种情况都设置了“每个文件的修改时间”; 因此保留这些文件的实际时间戳!

    因此,为了也保留时间戳,这里有一个 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/subdir) - 并且您要导出到的目标位置有点不方便,但它位于DEST 环境变量。 请注意,使用此脚本; 在运行上述脚本之前,您必须自己手动创建 DEST 目录。

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

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

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

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

    I think @Aredridel's post was closest, but there's a bit more to that - so I will add this here; the thing is, in svn, if you're in a subfolder of a repo, and you do:

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

    then svn will export all files that are under revision control (they could have also freshly Added; or Modified status) - and if you have other "junk" in that directory (and I'm not counting .svn subfolders here, but visible stuff like .o files), it will not be exported; only those files registered by the SVN repo will be exported. For me, one nice thing is that this export also includes files with local changes that have not been committed yet; and another nice thing is that the timestamps of the exported files are the same as the original ones. Or, as svn help export puts it:

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

    To realize that git will not preserve the timestamps, compare the output of these commands (in a subfolder of a git repo of your choice):

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

    ... and:

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

    ... and I, in any case, notice that git archive causes all the timestamps of the archived file to be the same! git help archive says:

    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.

    ... but apparently both cases set the "modification time of each file"; thereby not preserving the actual timestamps of those files!

    So, in order to also preserve the timestamps, here is a bash script, which is actually a "one-liner", albeit somewhat complicated - so below it is posted in multiple lines:

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

    Note that it is assumed that you're exporting the contents in "current" directory (above, /media/disk/git_svn/subdir) - and the destination you're exporting into is somewhat inconveniently placed, but it is in DEST environment variable. Note that with this script; you must create the DEST directory manually yourself, before running the above script.

    After the script is ran, you should be able to compare:

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

    ... and hopefully see the same timestamps (for those files that were under version control).

    Hope this helps someone,
    Cheers!

    逆光下的微笑 2024-07-13 16:57:22

    选项 1 听起来不太有效。 如果客户端没有空间进行克隆并删除 .git 文件夹怎么办?

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

    选项 2 和此处的其他答案在这种情况下没有帮助。 都不是 git archive (因为需要提交 .gitattributes 文件,并且我不想将此排除项保存在存储库中)。

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

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

    rsync 行更改为压缩的等效行也将作为 >git archive 但具有某种排除选项(如所要求的 这里)。

    The option 1 sounds not too efficient. What if there is no space in the client to do a clone and then remove the .git folder?

    Today I found myself trying to do this, where the client is a Raspberry Pi with almost no space left. Furthermore, I also want to exclude some heavy folder from the repository.

    Option 2 and others answers here do not help in this scenario. Neither git archive (because require to commit a .gitattributes file, and I don't want to save this exclusion in the repository).

    Here I share my solution, similar to option 3, but without the need of git clone:

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

    Changing the rsync line for an equivalent line for compress will also work as a git archive but with a sort of exclusion option (as is asked here).

    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文