git clone --filter选项的语法是什么?

imzjd6km  于 2023-03-06  发布在  Git
关注(0)|答案(3)|浏览(132)

Git 2.17 changelog描述了这个选项:

  • 克隆和获取的机制(依次涉及打包和解包对象)已被告知如何使用

其他主题引入的过滤机制。它现在知道
将结果包标记为允许丢失的约定包
对象,为“狭义”克隆奠定了基础。
这个标志可以使用了吗?或者它很可能很不稳定?有人知道传递的正确语法吗?无论我传递什么标志,都会被当作无效的过滤器规范而拒绝。例如,我尝试按目录过滤:

git clone file://path --depth=1 --filter '--subdirectory-filter Assets' TestRepo
git clone file://path --depth=1 --filter --subdirectory-filter Assets TestRepo
git clone file://path --depth=1 --filter Assets TestRepo
b4lqfgs4

b4lqfgs41#

filter-spec的格式是在git rev-list --help的选项部分定义的,你也可以在文档中看到它,下面是它目前的内容:

--过滤器=

只对其中一个--object * 有用;从打印对象列表中省略对象(通常是斑点)。可以是下列之一:
--filter=blob:none省略了所有blob。
格式--filter=blob:limit=<n>[kmg]省略大于n字节或单位的blob。n可以是零。后缀k、m和g可用于命名KiB、MiB或GiB单位。例如,blob:limit= 1 k与blob:limit=1024相同。
表单--filter=sparse:oid=<blob-ish>使用blob(或blob表达式)中包含的稀疏检出规范来忽略对请求的引用进行稀疏检出时不需要的blob。

nfs0ujit

nfs0ujit2#

git clone --filter选项的语法是什么?
至少在Git 2.27(2020年第二季度)中这一点更加清晰
在此之前,这里有一个快速的TLDR;该命令的示例(与(cone) sparse-checkout

#fastest clone possible:
git clone --filter=blob:none --no-checkout https://github.com/git/git
cd git
git sparse-checkout init --cone
git read-tree -mu HEAD

这将只恢复顶层文件夹文件,默认情况下不包括任何子文件夹。
由于git clone --filter=blob:none --no-checkout步骤,初始克隆仍然较快。
现在,我们来看一下git clone --filter选项的语法:
参见commit 4a46544(2020年3月22日)。
(由Junio C Hamano -- gitster --合并至commit fa0c1eb,2020年4月22日)

clone:文档--filter选项

签署人:德里克·斯托利
事实证明,"--filter=<filter-spec>"选项并没有出现在"git clone"页面的任何地方,而是在"git rev-list"中详细描述了它的用途。
在文档中添加一点关于这个选项的内容。在"git clone"文档中创建一个关于部分克隆的概念以及它如何成为一种令人惊讶的体验的小节是值得的。例如,"git checkout"可能会触发一个包下载。
git clone文档现在包括:

--filter=<filter-spec>

使用部分克隆特性并请求服务器根据给定的对象筛选器发送可访问对象的子集。
使用--filter时,提供的<filter-spec>用于部分克隆滤波器。
例如,--filter=blob:none会过滤掉所有blob(文件内容),直到Git需要为止。
此外,--filter=blob:limit=<size>将过滤掉大小至少为<size>的所有blob。
有关滤波器规格的详细信息,请参阅git rev-list中的--filter选项。
这个选项没有我希望的那么有用(它不能用来组合clonefilter-branch)。
然而,这种过滤机制是克隆相关机制的扩展,用于实现partial cloning (or narrow clone) introduced in Dec. 2017 with Git 2.16
但您的Git存储库托管服务器必须支持**protocol v2**,目前(2018年10月)支持only by GitLab
这意味着你可以将--filtergit clone一起使用,正如最近的Git 2.20补丁所示(见下文)。
然后将该过滤器添加到this patch series中的git fetch
它是新的包协议功能"filter"的一部分,添加到获取包和上载包协商中。
参见文档/技术/pack-protocol中的"过滤器",它指的是修订列表选项。
在Git 2.20(Q4 2018)中,被配置为延迟获取丢失对象的部分克隆将按需向原始仓库发出"git fetch"请求,以填充尚未获取的对象。
通过告诉原始存储库不需要blob,请求已经针对请求树对象(而不是其中包含的leaf blob对象)进行了优化。
参见commit 4c7f956commit 12f19a9(2018年10月3日)和Jonathan Tan ( jhowtan )
(由Junio C Hamano -- gitster --合并至commit fa54ccc,2018年10月19日)

fetch-pack:延迟获取树时排除blob

使用"git clone --filter=tree:none <repo>"可以获得缺失树的部分克隆.
在这样的储存库中,当树需要被惰性地获取时,它直接或间接引用的任何树或blob也被获取,而不管原始命令是否需要这些对象,或者本地储存库是否已经具有它们中的一些。
这是因为延迟提取使用的提取协议不允许客户端请求只发送所需的对象,而这是理想的解决方案。此补丁程序实现了部分解决方案:指定"blob:none"过滤器,稍微减少获取有效负载。
这个改变在延迟获取blob时没有效果(由于过滤器的工作方式)。如果延迟获取一个提交(这样的仓库很难构建,我们也不太支持,但这是可能的),被引用的提交和树仍然会被获取--只有blob不会被获取。
您可以通过以下方式进一步优化:
参见第一版15f1x、第一版16f1x、第一版17f1x、第一版18f1x(2018年9月27日),作者为第一版19f1x。
(由Junio C Hamano -- gitster --合并至commit 0527fba,2018年10月19日)

运输:允许跳过引用列表

get_refs_via_connect()函数执行握手(包括确定协议版本)和获取远程引用列表。
然而,fetch协议v2支持不列出引用的对象,因此通过创建一个新的handshake()函数,用户可以跳过列表
注意,语法在Git 2.21(Q1 2019)及其协议消息规范的更新中发生了变化,只允许有限地使用缩放量。
这是为了确保潜在的兼容性问题不会失控。
参见Josh Steadmon ( steadmon )commit 87c2d9d(2019年1月8日)。
参见commit 8272f26commit c813a7c(2019年1月9日)和Matthew DeVore ( matvore )
(由Junio C Hamano -- gitster --合并至commit 073312b,2019年2月5日)

filter-options:扩展标度数

与远程服务器或子进程通信时,请使用扩展数字,而不是对象过滤器规范中带缩放后缀的数字(例如,"limit:blob=1k"变为"limit:blob=1024")。
更新协议文档,注意客户端应该始终执行此扩展,以允许服务器实现之间的更大兼容性。

顺便说一句,Git 2.23(Q3 2019)认为"invalid filter-spec"消息是面向用户的,而不是一个BUG,因此它可以本地化。
参见Matthew DeVore ( matvore )commit 5c03bc8(2019年5月31日)。
(由Junio C Hamano -- gitster --合并至commit ca02d36,2019年6月21日)

list-objects-filter-options:错误可定位

"invalid filter-spec"消息是面向用户的,而不是BUG,因此使其可本地化。
以下上下文中显示的消息仅供参考:

$ git rev-list --filter=blob:nonse --objects HEAD
fatal: invalid filter-spec 'blob:nonse'

在Git 2.24(Q4 2019)中,http传输缺乏一些原生传输学习到的优化,以避免不必要的ref通告,这一问题已经得到修复。
参见commit fddf2ebcommit ac3fda8(2019年8月21日)和Jonathan Tan ( jhowtan )
(由Junio C Hamano -- gitster --合并至commit f67bf53,2019年9月18日)

传输助手:如果不必要,跳过ls-refs

Commit e70a303("fetch:2018 - 10 - 07,Git v2.20.0-rc0),它的祖先教导Git,作为一种优化,在协议v2获取过程中,当不需要ls-refs步骤时(例如,当懒惰获取部分克隆中丢失的对象时,或当运行"git fetch --no-tags <remote> <SHA-1>"时),跳过ls-refs步骤。
但这只适用于本地支持的协议;特别是不支持HTTP。
教导Git在使用支持连接或无状态连接的远程助手时跳过ls-refs
Git 2.24中的另一项优化(Q4 2019)
参见Jonathan Tan ( jhowtan )commit d8bc1a5(2019年10月8日)。
(由Junio C Hamano -- gitster --合并至commit c7d2ced,2019年10月15日)

send-pack:检查排除项时从不获取

签署人:陈宗泽
在构建要发送的包文件时,send_pack()会得到一个用作排除项的远程引用列表。
对于每个ref,它首先检查该ref是否存在于本地,如果存在,则使用"^"前缀将其传递给pack-objects

    • 但是,在部分克隆中,检查可能会触发延迟获取**。

在这样的获取期间获得的附加提交祖先信息可以示出将被发送的某些对象已经为服务器所知,从而导致发送较小的包。
但这是以从许多可能不相关的引用中获取为代价的,并且在客户端与被推送的分支的上游保持最新的典型情况下,延迟获取根本没有帮助。
确保不发生这些延迟读取。
最后,Git 2.24(2019年第4季度)包含了一个针对延迟获取故障的临时解决方案,它演示了filter语法的一种用法。
参见commit c7aadcc(2019年10月23日),作者:Jonathan Tan ( jhowtan )
(由Junio C Hamano -- gitster --合并至commit c32ca69,2019年11月4日)

fetch:延迟fetch_if_missing=0直到配置后

签署人:陈宗泽
假设,从一个包含".gitmodules"的存储库中,我们使用--filter=blob:none进行克隆:

git clone --filter=blob:none --no-checkout \
https://kernel.googlesource.com/pub/scm/git/git

然后我们获取:

git -C git fetch

这将导致"unable to load config blob object",因为cmd_fetch()中的fetch_config_from_gitmodules()调用将尝试加载".gitmodules"(Git知道它存在,因为客户端有HEAD树),而fetch_if_missing设置为0。
fetch_if_missing过早设置为0-此处的".gitmodules"应延迟获取。
Git必须在提取之前将fetch_if_missing设置为0,因为作为提取的一部分,会发生packfile协商(并且我们不想在检查对象是否存在时提取任何丢失的对象),但我们不需要这么早设置它。
fetch_if_missing的设置移动到cmd_fetch()中可能的最早点,正好在任何提取发生之前。
在Git 2.25(Q1 2020)中,对延迟克隆的调试支持得到了一些改进。
git fetch v2现在充分利用了promisor文件。
参见Jonathan Tan ( jhowtan )commit 5374a29(2019年10月15日)。
(由Junio C Hamano -- gitster --合并至commit 026587c,2019年11月10日)

fetch-pack:将获取的引用写入.promisor

签署人:陈宗泽
确认人:Josh Steadmon
promisor packfiles的规范(在partial-clone.txt中)声明packfiles附带的.promisor文件无关紧要(就像.keep文件一样),因此每当从promisor远程数据库获取packfile时,Git都会写入空的.promisor文件。
但这些文件可能包含更多有用的信息。
因此,不要写入空文件,而是将获取的refs写入这些文件。
这使得调试部分克隆的问题变得更容易,因为我们可以识别在下载包文件时获取了哪些引用(及其相关的哈希),如果需要,可以将这些哈希与promisor remote现在报告的哈希进行比较。
这是通过指导fetch-pack在知道包的锁定文件名时写入自己的非空.promisor文件来实现的。
这涵盖了用户使用内部协议或HTTP协议v2(transport.c中的fetch_refs_via_pack()设置lock_pack)和HTTP协议v0/v1(remote-curl.c中的fetch_git()将"--lock-pack"传递给"fetch-pack")运行"git fetch"的情况。
在Git 2.29(Q4 2020)之前,从一个延迟克隆的仓库中获取会导致服务器端尝试延迟获取客户端拥有的对象,其中许多对象无论如何都无法从第三方获得。
参见Jonathan Tan ( jhowtan )commit 77aa094(2020年7月16日)。
(由Junio C Hamano -- gitster --合并至commit 37f382a,2020年7月30日)

upload-pack:不延迟获取"have"对象

签署人:陈宗泽

upload-pack接收到一个包含"have"哈希值的请求时,它会检查所服务的存储库是否有相应的对象。但是,它不会使用OBJECT_INFO_SKIP_FETCH_OBJECT标志来执行此操作,因此,如果服务于部分克隆,则会首先触发延迟获取。
当用户从一个部分克隆(到另一个部分克隆-尽管如果要读取到的存储库不是一个部分克隆,也会发生这种情况)中进行读取时,在$DAYJOB中发现了这种情况。
因此,无论何时检查"have"散列是否存在,都要传递OBJECT_INFO_SKIP_FETCH_OBJECT标志。
还要添加OBJECT_INFO_QUICK标志以提高性能,因为这类对象通常不存在于服务存储库中,并且误报的后果很小(通常,发送的包稍大一些)。
在Git 2.29(Q4 2020)中,响应"git fetch"(man)请求的组件变得更可配置,以选择性地允许或拒绝用于部分克隆的对象过滤规范。
参见commit 6cc275e(2020年8月5日)。
参见Taylor Blau ( ttaylorr )commit 5b01a4ecommit 6dd3456(2020年8月3日)和commit b9ea214(2020年7月31日)。
(由Junio C Hamano -- gitster --合并到commit 73a9255,2020年8月11日)

upload-pack.c:允许禁止某些对象筛选器

帮助人:杰夫·金
签署人:泰勒·布劳
Git客户端可能会向服务器请求部分对象集,其中所请求的对象集由一个或多个对象过滤器细化。服务器管理员可以通过将变量"uploadpack.allowFilter"分别设置为"true"或"false"来配置"git upload-packman)"以允许或禁止这些过滤器。
然而,使用位图的管理员可能希望允许某些类型的对象过滤器,但禁止其他类型的对象过滤器。具体地说,他们可能希望允许可以通过使用位图来优化的对象过滤器,而拒绝其他不是位图的对象过滤器,并表示感知到的性能下降(以及服务器上增加的负载因子)。
允许通过引入两个新的配置变量来配置"git upload-packman)",以支持基于具体情况的对象筛选器:

  • 'uploadpackfilter.allow'
  • 'uploadpackfilter.<kind>.allow'

其中""可以是"blobNone"、"blobLimit"、"tree"等中的一个。
将第二个配置变量设置为"<kind>"的任何有效值,将明确允许或不允许限制此类对象过滤器。
如果客户端请求对象过滤器<kind>,并且没有设置相应的配置值,则"git upload-packman)"将默认为值"uploadpackfilter.allow,"该值本身默认为"true"以保持向后兼容性.
请注意,这与"uploadpack.allowfilter"不同,后者控制是否通告"filter"功能。
git config现在在其手册页中包括:

上载包过滤器.允许

为未指定的对象过滤器提供默认值(请参见:以下配置变量)。
默认值为true

uploadpackfilter.<filter>.allow

显式允许或禁止与<filter>对应的对象筛选器,其中<filter>可以是以下项之一:一个一米129一个x、一米130一个x、一米131一个x、一米132一个x或一米133一个x。
如果使用组合筛选器,则必须允许combine和所有嵌套筛选器种类。
默认值为uploadpackfilter.allow
在Git 2.30(Q1 2021)中,修复了响应部分克隆请求时潜在的服务器端资源释放问题。
参见Taylor Blau ( ttaylorr )commit 8d133f5commit aab179d(2020年12月3日)。
(由Junio C Hamano -- gitster --合并到commit 21127fa,2020年12月17日)

upload-pack.c:不要释放allowed_filters工具指针

签署人:泰勒·布劳
为了跟踪哪些对象过滤器被允许或不被允许,"git upload-pack"(man)将每个过滤器的名称存储在string_list,中,并将其->util指针设置为0或1,以指示它是被禁止还是被允许。
稍后,我们试图清除这个列表,但是我们错误地要求util指针也是free()'d的,这个行为(在6dd3456a8c("[ upload-pack.c ](https://github.com/git/git/blob/8d133f500a5390a089988141cdec8154a732764d/upload-pack.c)中引入):允许禁止某些对象过滤器",2020 - 08 - 03,Git v2.29.0-rc0--merge列于batch #6))导致无效释放,并导致崩溃。
为了触发此操作,需要从服务器获取
(a)至少允许一个对象筛选器,并且
(b)发出包含允许的过滤器的子集的获取(即,我们不能请求禁止的过滤器,因为这使我们在命中假的string_list_clear()之前到达die())。
在这种情况下,无论存在什么被禁止的过滤器都将导致noop free()(因为那些->util指针被设置为0),但我们尝试释放的第一个被允许的过滤器将使我们崩溃。
我们在测试中从未注意到这一点,因为我们没有设置"uploadPackFilter"配置变量,然后执行有效提取的示例。第一个新的"git clone"(man)阻止了此处的进一步回归。为了在顶部进行良好测量,请添加一个测试,以检查树深度大于0时的相同行为。

最近的"git clone"(man)修复程序在传输层返回故障时留下了一个临时目录。
Git 2.33(Q3 2021)修正了这个问题。
参见Jeff King ( peff )commit 6aacb7d(2021年5月19日)。
(2021年6月14日,由Junio C Hamano -- gitster --合并至commit f4f7304

clonetransport_fetch_refs()失败后清理目录

签署人:杰夫·金
git-cloneman)开始考虑来自aab179d中传输子系统的错误("builtin/clone.c:不要忽略transport_fetch_refs()错误",2020年12月3日,Git v2.30.0-rc1--merge).
但是,该提交并没有很好地处理文件系统的清理。
cmd_clone()创建的目录的清理是由atexit()处理程序完成的,我们用一个标志来控制它。
它以JUNK_LEAVE_NONE("清除所有内容")开始,然后当我们知道我们有一个有效的repo但没有工作树时前进到JUNK_LEAVE_REPO,最后当我们成功 checkout 时前进到JUNK_LEAVE_ALL

siotufzp

siotufzp3#

第一个月:* 子模块 * 版本。

(see my previous answer用于常规存储库git clone --filter
部分克隆子模块(稀疏检出)的概念已经开始出现:
在Git 2.29(2020年第4季度)中,当transfer.fsckobjects被设置时,这个懒惰/部分clone --filter甚至可以与子模块一起工作。
参见Jonathan Tan ( jhowtan )commit 1b03df5(2020年8月20日)。
(由Junio C Hamano -- gitster --合并至commit 63728e4,2020年8月31日)

fetch-pack:在部分克隆中,传递--promisor

签署人:陈宗泽
从promisor远程数据库获取包时,需要创建相应的.promisor文件。
"fetch-pack"最初是通过将"--promisor"传递给"index-pack"来实现这一点的,但在5374a290aa("fetch-pack:将获取的引用写入. promisor ",2019 - 10 - 16,Git v2.25.0-rc0--merge列在batch #1中)," fetch-pack "被教导自己执行此操作,因为它需要在.promisor文件中存储引用信息。
当设置transfer.fsckobjects时,这会导致超级项目出现问题,因为在当前实现中,是"index-pack"调用fsck_finish()来检查对象;在5374a290aa之前,fsck_finish()将看到.gitmodules是约定对象并且容忍它丢失,但是在5374a290aa之后,没有.promisor文件(在通过"index-pack"调用fsck_finish()时)来告诉它.gitmodules是约定对象,因此它返回错误。
因此,示教"fetch-pack"以再次将"--promisor"传递到步进包。
"fetch-pack"随后将使用ref信息覆盖此文件。
另一种方法是将对象检查移到"fetch-pack",让"index-pack"只索引文件。
但是,由于"index-pack"必须膨胀对象才能为它们建立索引,因此让它检查对象(这也需要膨胀文件)似乎是合理的。
提醒:
部分克隆允许我们避免在克隆和获取操作期间 * 提前 * 下载这些不需要的对象,从而减少下载时间和磁盘使用。
丢失的对象可以在以后需要时"按需获取"。
一个可以在以后提供丢失的对象的远程对象被称为promisor远程对象,因为它承诺在被请求时发送对象。
最初Git只支持一个promisor远程节点,即用户克隆的origin远程节点,它是在"extensions.partialClone"配置选项中配置的。
后来实现了对多个promisor远程的支持。
使用部分克隆要求用户联机,并且源远程或其他约定者远程可用于按需提取丢失的对象。
这对于用户来说可能有问题,也可能没有问题。
例如,如果用户可以停留在源树的预先选择的子集内,则他们可能不会遇到任何丢失的对象。
或者,如果用户知道自己将要脱机,则可以尝试预取各种对象。
在Git 2.33(Q3 2021)中,准备好内部构件,以便从子模块的promisor remote中惰性地获取对象。
参见第一季第十集、第一季第十一集、第一季第十二集、第一季第十三集、第一季第十四集(2021年6月17日)。
(由Junio C Hamano -- gitster --合并至commit 8721e2e,2021年7月16日)

promisor-remote:在任何存储库中教lazy-fetch

签署人:陈宗泽
审核人:伊莱贾·纽伦
这是向支持部分克隆子模块迈出的一步。
即使在这个补丁之后,我们仍然缺乏部分克隆子模块的支持,主要是因为很多访问子模块对象的Git代码都是通过添加它们的对象存储作为替代来实现的,这意味着任何在子模块中发生的延迟获取都是基于超级项目的配置,而不是子模块的配置。
这也会阻止通过面向用户的命令测试此修补程序中的功能。
在Git 2.36(Q2 2022)中,"git clone --filter=... --recurse-submodules"(man)"只会部分克隆顶层模块,而子模块会被完全克隆。
此行为被更改为将相同的过滤器向下传递到子模块。
参见Josh Steadmon ( steadmon )commit f05da2b(2022年2月4日)。
(由Junio C Hamano -- gitster --合并至commit 2e65591,2022年2月25日)

clone, submodule:将部分克隆筛选器传递给子模块

签署人:乔什·斯蒂德蒙
克隆--filter且启用--recurse-submodules的存储库时,部分克隆过滤器仅适用于顶级存储库。
对于包含大型子模块的项目,这可能会导致意外的带宽和磁盘使用。
例如,用户可能希望制作Gerrit的部分克隆,并运行:git clone --recurse-submodules --filter=blob:5k https://gerrit.googlesource.com/gerrit(男性)。
但是,只有超级项目是部分克隆;所有子模块将下载所有BLOB而不管它们的大小。
通过这一更改,同样的过滤器也可以应用于子模块,这意味着预期的带宽和磁盘节省一致地适用。
要避免更改默认行为,请添加新的克隆标志--also-filter-submodules
当它与--filter--recurse-submodules一起设置时,过滤器规范会传递到git-submoduleman)和git-submodule--helper,这样子模块克隆也会应用过滤器。
这将对超级项目和所有子模块应用相同的过滤器。

需要按子模块定制过滤器的用户需要使用--no-recurse-submodules进行克隆,然后使用适当的过滤器手动初始化每个子模块。
由于Jonathan Tan最近的工作[a, b, c]消除了使用替代项作为访问子模块对象的方法,因此对子模块应用过滤器应该是安全的,所以如果被访问的对象丢失,任何子模块对象访问现在都会触发从子模块的promisor远程对象的惰性获取。
此修补程序是[d]的返工版本,它是在Jonathan Tan之前创建的。

git config现在在其手册页中包括:

clone.filterSubmodules

如果提供了部分克隆过滤器(请参见git rev-list中的--filter)并使用了--recurse-submodules,则还应将过滤器应用于子模块。
git clone现在在其手册页中包括:
[--filter=<filter> [--also-filter-submodules]] [--] <repository>
git clone现在在其手册页中包括:

--also-filter-submodules

同时将部分克隆过滤器应用于存储库中的任何子模块。需要--filter--recurse-submodules
这可以通过设置clone.filterSubmodules配置选项默认打开。
git submodule现在在其手册页中包括:
如果指定了--filter <filter spec>,则给定的部分克隆筛选器将应用于子模块。
有关滤波器规格的详细信息,请参见git rev-list
在Git 2.37(2022年第3季度)中,"git remote -v"(man)现在显示从远程数据库获取数据时使用的list-objects-filter(如果可用)。
参见commit ef6d15c(2022年5月9日),作者:Abhradeep Chakraborty ( Abhra303 )
(2022年5月26日由Junio C Hamano -- gitster --合并到commit 2785b71

builtin/remote.c:指示-v列出promisor远程的筛选器

git remote -v(man)(--verbose)列出了远程的名称及其URL。
用户还可以指定promisor远程的过滤器类型。
像这样的事-

origin    remote-url (fetch) [blob:none]
origin    remote-url (push)

git remote -v也为promisor远程指定过滤器。
关闭:https://github.com/gitgitgadget/git/issues/1211签署人:Abhradeep Chakraborty www.example.com签名人:chakrabortyabhradeep79@gmail.com Signed-off-by: Junio C Hamano gitster@pobox.com
git remote现在在其手册页中包括:
对于promisor远程,还要显示配置了哪些筛选器(blob:none等)。
示例:

git clone --filter=blob:none "file://$(pwd)/srv.bare"
git remote -v
    srv.bare (fetch) [blob:none]

git -C pc config remote.origin.partialCloneFilter object:type=commit
git -C pc remote -v
    srv.bare (fetch) [object:type=commit]

相关问题