在Git中, - (破折号)意味着什么?

Ser*_*Ala 46 git

在阅读Git命令的手册页时,您经常会看到一个可选的--(破折号).根据我的经验,这--不是必要的,没有任何区别.你什么时候需要它?一般来说它是什么意思,因为它出现在如此众多的命令中?

Dav*_*ave 45

双破折号-在混帐意味着不同的事情不同的命令,但在总体上分开的参数选项.

具体来说,在git中,-取决于您使用的子命令.它通常将子命令参数(如git checkout中的分支名称)与修订版或文件名分开.有时它完全是可选的,仅用于防止异常文件名被解释为程序选项.

例如

  • git checkout.要检查"提交"(手册中称为"tree-ish",因为您实际上可以指定一系列对象类型),请使用

    git checkout commit

    要将结帐细化为一两个文件,请使用-将"tree-ish"参数与您要查看的"文件名"分开.

  • git commit.提交"索引"中的任何内容(即,您通过git add暂存的内容,简单发出git commit命令.

    git commit [-m message]

    要忽略通过git add添加的任何内容并提交特定文件中的更改,请使用git commit - filename

  • git add.要提交以" - "或" - "开头的文件,您必须告诉git add停止读取参数,并开始阅读文件名.' - '做到了.

    git add - -myfile

如果需要了解其具体含义,则需要检查手册页中是否有您使用的git命令.


Von*_*onC 9

\n

这个问题要求对所有 git 命令中的双破折号有一个概念性的理解。

\n
\n

双破折号表示选项结束,对于 Git 来说被认为“不够”。

\n

在 Git 2.24(2019 年第 3 季度)中,命令行解析器学习了“ --end-of-options”符号:

\n

脚本编写者首先在命令行上硬编码选项集并强制命令将最终用户输入视为非选项的标准约定是使用--”作为分隔符,但这对于以下命令不起作用使用“ --”作为转速和路径规范之间的分隔符。

\n

请参阅Jeff King的提交 67feca3提交 51b4594提交 19e8789(2019 年 8 月 6 日。\n (由Junio C Hamano 合并 -- --提交 4a12f89,2019 年 9 月 9 日)peff
gitster

\n
\n

revision: 允许--end-of-options结束选项解析

\n
\n
\n

目前没有可靠的方法来告诉 Git 某个特定选项是修订版本,而不是选项。
\n所以如果你有一个分支“ refs/heads/--foo”,你不能只说:

\n
git rev-list --foo\n
Run Code Online (Sandbox Code Playgroud)\n

你可以说:

\n
git rev-list refs/heads/--foo\n
Run Code Online (Sandbox Code Playgroud)\n

但是,如果您不知道引用名称,特别是如果您是从其他地方传递值的脚本,那么这种情况就会崩溃。
\n在大多数程序中,您可以使用“ --”来结束选项解析,如下所示:

\n
some-prog -- "$revision"\n
Run Code Online (Sandbox Code Playgroud)\n

但这对于修订解析器不起作用,因为“ --”在那里已经有意义:它将修订与路径规范分开。
\n因此我们需要一些其他标记来将选项与修订版分开。

\n

这个补丁引入了“ --end-of-options”,它就是为了这个目的:

\n
git rev-list --oneline --end-of-options "$revision"\n
Run Code Online (Sandbox Code Playgroud)\n

无论“$revision”中的内容如何,​​它都会起作用(好吧,如果你说“ --”,它可能会失败,但它不会做一些危险的事情,比如触发意外的选项)。

\n

这个名字很冗长,但这可能是一件好事;这适用于可读性比简洁性更重要的脚本调用。

\n

一种替代方法是引入一个显式选项来标记修订,例如:

\n
git rev-list --oneline --revision="$revision"\n
Run Code Online (Sandbox Code Playgroud)\n

这比这个提交的信息稍微丰富一些(因为它甚至使像“--”这样的愚蠢的东西变得明确)。但是使用像“”这样的分隔符的模式--在 git 和其他命令中已经很好地建立起来,并且它使一些脚本任务变得更简单,例如:

\n
git rev-list --end-of-options "$@"\n
Run Code Online (Sandbox Code Playgroud)\n
\n
\n
\n

解析选项:允许--end-of-options作为“--”的同义词

\n
\n
\n

修订选项解析器最近了解了--end-of-options,但这对于所有调用者来说还不够。
\n其中一些,例如git-log,使用 挑选一些选项parse_options(),然后将剩余的提供给setup_revisions()
\n对于这些情况,我们需要parse_options()在看到 时停止寻找更多选项--end-of-options,并保留该选项,argv以便setup_revisions()也可以看到它。

\n

让我们像处理“ --”一样处理这个问题。我们甚至可以利用 的处理PARSE_OPT_KEEP_DASHDASH,因为任何想要保留其中一个的调用者都会想要保留另一个。

\n
\n

例子:

\n
git update-ref refs/heads/--source HEAD &&\\\ngit log --end-of-options --source\n
Run Code Online (Sandbox Code Playgroud)\n
\n

在 Git 2.30(2021 年第 1 季度)中,“ git rev-parse( man )学会了“ --end-of-options”来帮助脚本安全地获取应该是修订版本的参数,例如“ ( man ) ”。git rev-parse --verify -q --end-of-options $rev

\n

请参阅Jeff King的提交 3a1f91c提交 9033add提交 e05e2ae(2020 年 11 月 10 日。\n (由Junio C Hamano 合并 -- --提交 0dd171f中,2020 年 11 月 21 日)peff
gitster

\n
\n

rev-parse: 处理--end-of-options

\n

签署人:杰夫·金

\n
\n
\n

我们在19e8789b23中教授了 rev-list 一种将选项与修订版分开的新方法(“ revision:allow --end-of-options to end option parsing”,2019-08-06,Git v2.24.0-rc0 --批量合并列出)#2),但rev-parse使用自己的解析器。
\n它应该知道--end-of-options不仅是为了一致性,而且因为它可能会出现类似的模棱两可的情况。例如,如果呼叫者这样做:

\n
git rev-parse "$rev" -- "$path"  \n
Run Code Online (Sandbox Code Playgroud)\n

解析不受信任的输入,如果$rev包含像“”这样的类似选项的字符串,它会感到困惑--local-env-vars
\n或者甚至是“ --not-real”,我们将其保留为传递给 rev-list 的选项。

\n

或者更重要的是:

\n
git rev-parse --verify "$rev"  \n
Run Code Online (Sandbox Code Playgroud)\n

可能会被选项混淆,即使其目的是安全地解析不受信任的输入。
\n从好的方面来说,它总是会使该--verify部分失败,因为它不会解析修订版,因此调用者通常会“失败关闭”,而不是继续使用不受信任的字符串。
\n但它仍然会触发“”中的任何选项$rev;这应该是无害的,因为 rev-parse 选项都是只读的,但我没有仔细审核所有路径。

\n

该补丁允许调用者编写:

\n
git rev-parse --end-of-options "$rev" -- "$path"  \n
Run Code Online (Sandbox Code Playgroud)\n

和:

\n
git rev-parse --verify --end-of-options "$rev"  \n
Run Code Online (Sandbox Code Playgroud)\n

这都将$rev始终将“”视为修订参数。
\n后者有点笨拙。如果我们定义“ --verify”来要求它的下一个参数是修订版,那就更好了。
\n但我们历史上没有这样做过,并且:

\n
git rev-parse --verify -q "$rev"  \n
Run Code Online (Sandbox Code Playgroud)\n

目前有效。我在这里添加了一个测试来确认我们没有破坏它。

\n

一些实施注意事项:

\n
    \n
  • 我们不必重新缩进主要选项解析块,因为我们可以将“我们是否看到选项结尾”检查与“它是否以破折号开头”结合起来。预设置选项是个例外,它需要自己的块。

    \n
  • \n
  • 然而,我们必须将“ --”解析从“它是否以破折号开头”块中取出,因为即使我们已经看到了,我们也想解析它--end-of-options

    \n
  • \n
  • 我们将--end-of-options在输出中留下“”。这在技术上可能不是必需的,因为细心的调用者会这样做:

    \n

    git rev-parse --选项结束 $revs -- $paths

    \n
  • \n
\n

$revs 中的任何内容都将解析为对象 id。
\n但是,它确实可以帮助不太细心的调用者,例如:

\n
git rev-parse --end-of-options $revs_or_paths  \n
Run Code Online (Sandbox Code Playgroud)\n

只要路径“ --foo”也存在于磁盘上,它就会保留在输出中。
\n在这种情况下,保留传递给 rev-list 是有帮助的--end-of-options,否则它只会看到“ --foo”。

\n
\n

git rev-parse现在包含在其手册页中:

\n
\n

请注意,如果您要验证来自不受信任来源的名称,则最好使用该名称参数,--end-of-options以免将名称参数误认为是其他选项。

\n
$ git rev-parse --verify --end-of-options $REV^{commit}\n$ git rev-parse --default master --verify --end-of-options $REV\n
Run Code Online (Sandbox Code Playgroud)\n
\n
\n

在 Git 2.31(2021 年第一季度)中,“ git mktagman在编写标签对象之前使用自己的规则验证其输入——它已更新为与“共享逻辑git fsck

\n

这意味着它也支持--end-of-options.

\n

请参阅提交 06ce791(2021 年 1 月 6 日)、提交 2aa9425提交 3f390a3、提交9a1a3a4提交 acfc013、提交1f3299f提交 acf9de4提交 40ef015提交 dfe3948提交 0c43911、提交692654d、提交30f882c提交 ca9a1ed提交 47c95e7提交 3b9e4dd提交 5c2303e提交 317c176提交 0d35ccb提交 b5ca549提交 aba5377提交 18430ed(2021 年 1 月 5 日)和提交 9ce0fc3提交 f59b61d(2020 年 12 月 23 日),作者:\xc3\x86var Arnfj\xc3\xb6r\ xc3\xb0 比贾梅森( avar)
\n (由Junio C Hamano 合并 -- gitster--提交 c7d6d41中,2021 年 1 月 25 日)

\n
\n

mktag: 转换为解析选项

\n

签署人:\xc3\x86var Arnfj\xc3\xb6r\xc3\xb0 Bjarmason

\n
\n
\n

转换要使用的“ mktag”命令,parse-options.h而不是其自己的临时 argc 处理。
\n这在实践中并不重要,因为它不支持任何选项,但删除了我们的代码库中的另一个特殊情况,并使将来更容易向其添加选项。

\n

它确实稍微改善了想要以一致的方式执行 git 命令的程序的情况,例如始终使用--end-of-options.
\n例如
\n" gitaly" 就是这样做的,并且有一个不支持的内置程序黑名单--end-of-options
\n这是它和其他需要支持的类似程序的一种不太特殊的情况。

\n
\n
\n

在 Git 2.44(2024 年第 1 季度)之前,“ git $cmd --end-of-options --rev -- --pathfor some$cmd无法解释--rev为 rev,“ --path” 无法解释为路径。 \n这对于许多程序(如“ ”和“ ”)
已修复。resetcheckout

\n

请参阅Jeff King ( )的提交 9385174(2023 年 12 月 6 日)。\n (由Junio C Hamano 合并 -- --提交 9eec6a1中,2023 年 12 月 20 日)peff
gitster

\n
\n

parse-options:解耦“ --end-of-options”和“ --

\n

签署人:杰夫·金

\n
\n
\n

当我们在51b4594中添加通用选项结束支持时(“ parse-options:允许--end-of-options作为 --”的同义词,2019-08-06,Git v2.24.0-rc0 --合并在批次 #2中列出),我们使它们为真同义词。\n它们都停止选项解析,并且如果使用
该标志,它们都会在结果 argv 中返回。KEEP_DASHDASH

\n

希望这对所有调用者都有效:

\n
    \n
  • 大多数通用调用者不会通过KEEP_DASHDASH,,因此只会做正确的事情(在那里停止解析),而无需了解更多信息。
  • \n
  • 调用者KEEP_DASHDASH通常会依赖setup_revisions(),它知道要进行--end-of-options特殊处理
  • \n
\n

但结果却错过了很多通过的案例,KEEP_DASHDASH而是进行了自己的手动解析。
\n例如, " git reset" ( man )、 " git checkout" ( man )等需要通过,KEEP_DASHDASH以便它们可以支持:

\n
git reset $revs -- $paths\n
Run Code Online (Sandbox Code Playgroud)\n

但当然不会真正进行遍历,因此它们不会调用setup_revisions(). \n这些情况目前因留在原地而
变得混乱,例如:--end-of-options

\n
$ git reset --end-of-options HEAD\nfatal: option \'--end-of-options\' must come before non-option arguments\n
Run Code Online (Sandbox Code Playgroud)\n

我们可以教每个调用者显式地处理剩余选项。
\n但是让我们尝试更聪明一点,看看我们是否可以在 中集中解决它parse-options.c

\n

这里的虚假假设是告诉我们调用者希望在结果中KEEP_DASHDASH看到。\n但实际上,需要知道已达到的调用者是那些可能从 argv 解析更多选项的调用者。\n换句话说,就是那些通过标志的人。--end-of-options
--end-of-options
KEEP_UNKNOWN_OPT

\n

如果这样的调用者知道--end-of-options(例如,因为他们调用setup_revisions()了结果),那么这将继续做正确的事情,将之后的任何事情视为--end-of-options非选项。

\n

如果调用者不知道--end-of-options,他们最好保持原样,因为:

\n
    \n
  1. 无论如何,他们只是将选项传递给其他人,在这种情况下,有人需要了解标记--end-of-options
  2. \n
  3. 他们将自己解析剩余的内容,此时窒息--end-of-options比默默地删除它要好得多。
    \n重点是避免来自不受信任的命令行参数的选项注入,并且保释比悄悄地将不受信任的参数视为选项要好。
  4. \n
\n

请注意,这确实为那些想知道我们是否到达选项结束的调用者关上了大门,但又不需要保留未知的选项。
\n这里显而易见的事情是将其输入 DWIMverify_filename()机器。
\n事实上,即使对于已经理解的命令来说,这也是一个问题--end-of-options
\n例如,如果没有此补丁,您将得到:

\n
$ git log --end-of-options --foo\nfatal: option \'--foo\' must come before non-option arguments\n
Run Code Online (Sandbox Code Playgroud)\n

因为我们拒绝接受“ --foo”作为文件名(因为它以破折号开头),即使我们知道我们看到了选项结束。
\n该verify_filename()函数根本不接受此额外信息。

\n

这就是现状,这个补丁进一步加强了这一点。
\n像“ git reset”这样的命令也有同样的问题,但它们甚至不知道解析选项看到了--end-of-options!因此,即使我们修复了verify_filename(),他们也不会有任何东西可以传递给它。

\n

但实际上我认为这没什么大不了的。
\n如果您在使用 时足够小心--end-of-options,那么您还应该--首先使用“”来消除歧义并避免 DWIM 行为。
\n换句话说,做:

\n
git log --end-of-options --this-is-a-rev -- --this-is-a-path\n
Run Code Online (Sandbox Code Playgroud)\n

工作正常,并将继续这样做。
\n同样,现在有了这个补丁:

\n
git reset --end-of-options --this-is-a-rev -- --this-is-a-path\n
Run Code Online (Sandbox Code Playgroud)\n

也会起作用。

\n
\n