13

给定一个简单的测试存储库,其中包含两个文件的单个提交,a并且b,我可以获得特定文件的列表:

$ git ls-files a
a

或不包括特定文件的所有文件的列表:

$ git ls-files . ':!b'
a

我可以创建特定文件的存档:

$ git archive HEAD a | tar tf -
a

但我无法创建除特定文件之外的所有文件的存档:

$ git archive HEAD . ':!b' | tar tf -
a
b

在我的真实存储库中,使用特定文件存档的选项对我来说不是一个选项,因为它超过了最大命令行参数长度。

我知道我可以.gitattributes通过export-ignore属性存储要排除的文件列表,但该列表是动态生成的。我可以自动更改文件,但在另一次提交之前不会收到更改。

是否有其他一些无需再次提交即可工作的调用?

4

5 回答 5

9

我想你几乎搞定了:属性可以从几个地方读取,.gitattributes只是其中最常见的。第二个——考虑到每个存储库的配置——是$GIT_DIR/info/attributes.

引用手册:

请注意,属性默认取自.gitattributes正在归档的树中的文件。如果您想调整事后生成输出的方式(例如,您提交时没有 export-ignore在其 中添加适当的.gitattributes),请根据需要调整签出.gitattributes文件并使用--worktree-attributes选项。或者,您可以保留在归档 $GIT_DIR/info/attributes文件中的任何树时应该应用的必要属性。

因此,如果可能,请将您的列表粘贴到该文件中,然后执行git archive.

另一种方法是不使用git archive而仅使用传递接受文件的命令行选项tar的工作树。这不适用于裸存储库,但如果您可以在存档之前检查内容,这可以通过执行并提供正确的环境来完成。变量。tar--exclude-fromgit read-treegit checkout-index$GIT_INDEX_FILE$GIT_WORK_TREE

另一种可能的解决方法是反转该方法:(tar至少 GNU tar)支持一个鲜为人知的选项,即能够从管道中的存档中删除内容。

基本上,你可以做

 $ tar -C a_path -c -f - . \
   | tar -f - --wildcards --delete '*.pdf' >result.tar

这样tar管道中的第一个归档所有内容,而第二个传递所有内容,但与*.pdfshell glob patten 匹配的文件除外。

因此,如果使用 shell glob 指定要删除的文件可以符合命令行限制,只需将输出通过管道传输git archivetar删除不需要的东西的过程。

于 2016-08-03T08:44:16.083 回答
4

您可以创建一个 tar 然后删除不需要在里面的文件夹和文件

git archive HEAD -o archive.tar
tar -f archive.tar --delete listoffiles1
tar -f archive.tar --delete listoffiles2
tar -f archive.tar --delete listoffiles..
tar -f archive.tar --delete listoffilesN

这样,您可以拆分命令行以保持在最大 cli 参数长度以下

于 2016-08-03T08:35:08.993 回答
3

除了放入export-ignore(committed) 之外.gitattributes,您还可以将其放入 (not commited)$GIT_DIR/info/attributes文件中。或者留下.gitattributes未提交的选项并使用该--worktree-attributes选项,这也可能不太好,因为它会使您的工作树变脏。

于 2016-08-03T08:44:24.103 回答
1

使用 Git 2.20 版(Windows)和 Gitolite 服务器(未知版本),这对我来说可以排除名为“b”的文件和文件夹:

git archive HEAD . ":!b" | tar tf -

这也有效:

git archive HEAD . ":(exclude)b" | tar tf -

请注意,我必须在 Windows 平台上使用双引号,不确定其他平台。

于 2020-03-18T15:08:32.670 回答
0

一种可能的解决方案在于git archive希望树状存档的事实。

您正在通过它HEAD(可能是最常见的选择)。为了实现你的意思,这个 ref 会自动解析为它指向的对象——很明显,这将是一个提交。并且提交对象被解析为附加到它的树对象。所以你得到了当前提交的内容。到目前为止,如此明显。

但是你可以传递任何你想要的树对象!这有什么帮助?好吧,您始终可以使用索引的当前状态创建一个树对象git write-tree——它返回它刚刚在标准输出上创建的树对象的 SHA1。您不必创建提交或类似的东西。

因此,您可以git rm --cached在 tarball 中添加您不想要的所有内容,然后创建一个树对象以传递给git archive. 而且由于您不关心树对象,因此您可以将其组合到git archive命令中:

git archive $( git write-tree )

在那之后,你就git reset --hard可以开始了。

全部一起:

git rm --cached foo bar baz
git archive $( git write-tree )
git reset --all
于 2021-10-25T13:07:08.803 回答