在Git中,`--`(破折号)是什么意思?

pgx2nnw8  于 2023-08-01  发布在  Git
关注(0)|答案(2)|浏览(118)

在阅读Git命令的手册页时,你经常会看到一个可选的--(破折号)。根据我的经验,--是不必要的,也没有什么区别。你什么时候需要?既然它出现在这么多命令中,那么它通常意味着什么呢?

yqlxgs2m

yqlxgs2m1#

git中的双破折号--对不同的命令有不同的含义,但一般来说,它将选项和参数分开。
git中,--的含义取决于你使用的是哪个子命令。它通常将子命令参数(如git checkout中的分支名称)与修订或文件名分开。有时它是完全可选的,仅用于防止不寻常的文件名被解释为程序选项。
例如

  • git checkout。要检出一个“提交”(在手册中称为“树型”,因为您实际上可以指定一系列对象类型),您可以使用

git checkout <commit>
要将 checkout 细化到一两个文件,可以使用--将“树型”参数与您希望 checkout 的“文件名”分开。

  • git commit。要提交“index”中的任何内容(即通过git add暂存的内容),只需发出git commit命令。

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

  • git add.要提交一个文件名以---开头的文件,必须告诉git add停止阅读参数,并开始读取文件名; --就是这么做的。

git add -- -sample.txt

  • git log。要查看仅限于影响文件的提交的提交历史,请使用

git log -- <filename>
如果你需要了解git命令的具体含义,你需要查看手册页。

rm5edbpk

rm5edbpk2#

这个问题要求对所有git命令中的双破折号有一个概念性的理解。
双破折号表示选项的结束,被认为对Git来说是“不够的”。
在Git 2.24(2019年第三季度)中,命令行解析器学习了“--end-of-options”表示法:
脚本编写者的标准约定是先在命令行上硬编码一组选项,并强制命令将最终用户输入视为非选项,这是**使用“--”作为分隔符,但这不适用于使用“--”作为revs和pathspec之间分隔符的命令。
参见commit 67feca3commit 51b4594commit 19e8789(2019年8月6日)by Jeff King ( peff )
(由Junio C Hamano -- gitster --合并至commit 4a12f89,2019年9月9日)

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

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

git rev-list --foo

字符串
你可以说:

git rev-list refs/heads/--foo


但是如果您不知道refname,特别是如果您是一个从其他地方传递值的脚本,那么这种方法就行不通了。
在大多数程序中,你可以使用“--“来结束选项解析,像这样:

some-prog -- "$revision"

但这对修订解析器不起作用,因为“--“已经有意义了:它将修订与路径规范分开。

因此,我们需要一些其他的标记来区分选项和修订。
此修补程序引入了“--end-of-options”,用于此目的:

git rev-list --oneline --end-of-options "$revision"


无论“$revision”中的内容是什么,它都将工作(如果你说“--“,它可能会失败,但它不会做一些危险的事情,比如触发一个意外的选项)。
名字很冗长,但这可能是件好事;这意味着用于可读性比简洁更重要的脚本调用。
一种替代方法是引入一个明确的选项来标记修订,例如:

git rev-list --oneline --revision="$revision"


这比这次提交的信息要多一点(因为它甚至会让像“--”这样的愚蠢的东西变得毫不含糊)。但是在git和其他命令中,使用分隔符“--”的模式已经很好地建立起来了,它使一些脚本任务变得更简单,比如:

git rev-list --end-of-options "$@"

parse-options:允许--end-of-options作为“--”的同义词

修订选项解析器最近了解了--end-of-options,但这对所有调用者来说还不够。
其中一些,如git-log,使用parse_options()选择一些选项,然后将剩余部分提供给setup_revisions()
对于这些情况,我们需要阻止parse_options()在看到--end-of-options时查找更多选项,并在argv中保留该选项,以便setup_revisions()也可以看到它。
让我们像处理“--”一样处理它。我们甚至可以使用PARSE_OPT_KEEP_DASHDASH的处理,因为任何想要保留其中一个的调用者都会想要保留另一个。
范例:

git update-ref refs/heads/--source HEAD &&\
git log --end-of-options --source


在Git 2.30(2021年第一季度)中,“git rev-parse”(man)学习了“--end-of-options”,以帮助脚本安全地获取一个应该是修订版的参数,例如:“git rev-parse --verify -q --end-of-options $rev(man)"。
参见commit 3a1f91ccommit 9033addcommit e05e2ae(2020年11月10日)by Jeff King ( peff )
(由Junio C Hamano -- gitster --合并到commit 0dd171f,2020年11月21日)

rev-parse:手柄--end-of-options

签收人:杰夫·金
我们教rev-list一种新的方法来区分19e8789b23中的选项和修订版本(“revision:allow --end-of-options to end option paralysis”,2019-08-06,Git v2.24.0-rc 0--merge中列出的batch #2),但rev-parse使用自己的解析器。
它应该知道--end-of-options,这不仅是为了一致性,而且因为它可能出现类似的模糊情况。例如,如果呼叫者这样做:

git rev-parse "$rev" -- "$path"


如果$rev包含类似于选项的字符串,比如“--local-env-vars”,那么它就会被混淆。
或者甚至是“--not-real“,我们会将其作为一个选项传递给rev-list。
或者更重要的是:

git rev-parse --verify "$rev"


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

git rev-parse --end-of-options "$rev" -- "$path"


以及:

git rev-parse --verify --end-of-options "$rev"


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

git rev-parse --verify -q "$rev"


目前正在工作。我在这里加了一个测试来确认我们没有破坏它。
一些实施说明:

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

  • 但是,我们必须将“--”解析从“does it start with dash”块中提取出来,因为即使我们已经看到了--end-of-options,我们也要解析它。

  • 我们将在输出中保留“--end-of-options“。这在技术上可能没有必要,因为谨慎的呼叫者会这样做:

git rev-parse --end-of-options $revs -- $paths
并且$revs中的任何内容都将被解析为对象ID。
但是,它确实可以帮助稍微不太小心的呼叫者,例如:

git rev-parse --end-of-options $revs_or_paths

其中路径“--foo”将保留在输出中,只要它也存在于磁盘上。
在这种情况下,保留--end-of-options以沿着rev-list是有帮助的,否则它只会看到“--foo”。
git rev-parse现在在其手册页中包括:
请注意,如果您正在验证来自不受信任来源的名称,则明智的做法是使用--end-of-options,这样name参数就不会被误认为是另一个选项。

$ git rev-parse --verify --end-of-options $REV^{commit}
$ git rev-parse --default master --verify --end-of-options $REV

在Git 2.31(2021年第一季度)中,“git mktag”(man)在写入标记对象之前使用自己的规则验证其输入-它已更新为与git fsck共享逻辑。
这意味着它也支持--end-of-options
参见commit 06ce791(2021年1月6日),commit 2aa9425commit 3f390a3commit 9a1a3a4commit acfc013commit 1f3299fcommit acf9de4commit 40ef015commit dfe3948commit 0c43911commit 692654dcommit 30f882ccommit ca9a1edcommit 47c95e7commit 3b9e4ddcommit 5c2303ecommit 317c176commit 0d35ccbcommit b5ca549commit aba5377commit 18430ed(2021年1月5日)和commit 9ce0fc3commit f59b61d(2020年12月23日)。
(由Junio C Hamano -- gitster --合并到commit c7d6d41,2021年1月25日)

mktag:转换为解析选项

签收人:埃瓦尔·阿恩菲约德·比亚尔马森
将“mktag“命令转换为使用parse-options.h,而不是它自己的ad-hoc argc处理。
这在实践中并不重要,因为它不支持任何选项,但它删除了代码库中的另一个特例,并使将来添加选项变得更容易。
它确实稍微改善了那些想要以一致的方式执行git命令的程序的情况,例如。始终使用--end-of-options
例如:
gitaly“就是这样做的,并且有一个不支持--end-of-options的内置程序的黑名单。
这是一个较少的特殊情况下,它和其他类似的程序支持。

相关问题