在寻找git hook示例时,我看到了以下帖子:https://github.com/Movidone/git-hooks/blob/master/pre-receive和我想了解下面的命令:
git rev-list $new_list --not --all
字符串
其中new_list是从:
NULL_SHA1="0000000000000000000000000000000000000000" # 40 0's
new_list=
any_deleted=false
while read oldsha newsha refname; do
case $oldsha,$newsha in
*,$NULL_SHA1) # it's a delete
any_deleted=true;;
$NULL_SHA1,*) # it's a create
new_list="$new_list $newsha";;
*,*) # it's an update
new_list="$new_list $newsha";;
esac
done
型
我认为rev-list显示提交的时间顺序相反。
但是,有人可以分享更多关于-not
和-all
选项的含义吗?
根据文件:
--not
Reverses the meaning of the ^ prefix (or lack thereof) for all following revision specifiers, up to the next --not.
--all
Pretend as if all the refs in refs/ are listed on the command line as <commit>.
型
我不能完全理解这些选项。
[更新]在做了一些测试提交后,我发现如果我不使用--not
和--all
选项,那么git rev-list
列出了分支上的所有提交,而不是我打算推送的那一个。
然而,想了解为什么当--all
选项被传递时,它不打印sha值在终端上?
2条答案
按热度按时间mwyxok5s1#
git rev-list
命令是Git中一个 * 非常 * 复杂**中心 * 的命令,因为它所做的是 * 遍历图 。这里的 graph 指的是提交图本身,在某些情况下,指的是下一层(Git objects * reached from commits)。我认为rev-list显示提交的时间顺序相反。
不完全是,但很接近:
rev-list
更深入,以便包括树和blob对象,甚至标签对象。这适用于git fetch
和git push
(调用git pack-objects
)和git pack-objects
等程序。我打算在这里完全忽略这种可能性,但我觉得我至少应该提一下。😀所以 default 是以逆时间顺序列出一些提交。精确指定x 1 m6n1x遍历图的哪些部分是很重要的,也有点棘手:在 some commits 中的 some。
但是,有人可以分享更多关于
--not
和--all
选项的含义吗?作为VonC notes,这里的 effect 是列出接收存储库的新提交。这取决于这个
git rev-list
命令运行在 pre-receive hook 中。它通常不会在这个特定钩子之外做任何有用的事情。因此,正如您所看到的,在Git中,钩子的运行时环境通常至少有点特殊。(这不仅仅适用于预接收钩子:必须考虑每个钩子的激活上下文。)更多关于
--not --all
--all
选项的功能正是您在文档中引用的功能:假装
refs/
中的所有引用都列在命令行上...这相当于
git for-each-ref refs
:它在每个引用上循环。包括分支名称的(master
或main
、develop
、feature/tall
等等,所有这些都是在refs/heads/
中)、标记名(v1.2
,实际上是refs/tags/v1.2
),远程跟踪名称(origin/develop
,实际上是refs/remotes/origin/develop
),替换引用(refs/replace/
),stash(refs/stash
),平分引用,Gerrit引用,如果你使用Gerrit,等等。请注意,它 * 不 * 在reflog条目上循环。--not
前缀是一个简单的布尔运算。在gitrevision语法中-参见the gitrevisions documentation-我们可以写像develop
这样的东西,意思是 * 我告诉你从develop
开始并向后工作,* 包括 * 这些提交 ,但也可以写像^develop
这样的东西,意思是 * 我告诉你从develop
开始并向后工作, 排除 * 这些提交 *。所以如果我写:字符串
我要求Git从
feature1
和feature2
标识的提交中遍历可达的提交,但从main
标识的提交中排除可达的提交。更多关于 * 可达性 * 和图形行走的一般概念,请参阅Think Like (a) Git。--not
操作符有效地翻转每个ref上的^
:型
可以说是简写
型
这遍历了
main
可访问的提交列表,但排除了feature1
或feature2
可访问的提交。通常 * 所有 * 提交都可以通过
--all
找到如果你以正常的日常方式使用Git,* 和 * 目前还没有“分离的HEAD”--分离的HEAD模式并不完全 * 异常 *,但它不是通常的工作方式--
git rev-list
的--all
选项告诉它包含 all 提交,因为所有提交 * 都可以 * 从所有引用中获得。因此,将--not --all
添加到任何git rev-list
中,否则将列出一些提交,这将产生禁止列表的效果。输出为空:我们为什么要麻烦如果你在分离HEAD模式下,并且已经做了几个新的提交-这可能发生在你处于交互式或冲突的rebase中间,例如-那么
git rev-list HEAD --not --all
会列出那些 * 可以 * 从HEAD
* 到达但 * 不能 * 从任何分支名称。例如,在这个rebase中,这将只是您目前为止复制的那些提交。因此,“分离HEAD”模式将是一次在命令行中使用
git rev-list --not --all
的地方。但是对于您正在研究的情况-一个 * 预接收钩子 *-我们并不真正使用命令行。预收挂钩
当有人使用
git push
发送commit * 到 * 你自己的Git时,你的Git:在实际执行所请求的任何更新之前,您的Git:
1.将整个列表馈送到预接收挂钩。那个钩子可以说“不”;如果是,则整个推送作为一个整体被拒绝。
1.如果显示“ok”,则将列表一次一个请求馈送到update钩子。当钩子说“ok”时,就更新了。如果钩子说“否”,你的Git拒绝一个更新,但继续检查其他更新。
1.在步骤2中接受或拒绝所有更新之后,将接受的列表馈送到后接收挂钩。
在步骤2中添加到ref中的所需对象将从隔离区移到Git的对象数据库中。那些被拒绝的人不是。
现在,考虑一个典型的
git push
。我们得到了一些新的commit(s)和一个请求:* 创建一个新的分支名称feature/short
,或者我们得到一些新的提交和请求: 更新现有分支名称develop
,以包括这些新提交,沿着旧提交 *。在上面的步骤1中,我们有一个新的哈希ID。我们运行了一个循环来读取所有的ref名称,以及它们的当前和新的hash ID,循环只运行了一次,因为只有一个 name 被
git push
-ed。该哈希ID指的是 new commit或commits,它们要么将被添加到这个现有分支,要么是tip和其他对新分支独占的commits。我们现在要检查这些提交,而不是从任何现有分支可访问的任何现有提交。为了简单起见,而不是我的另一个答案中的
$new_list
,让我们假设我们只有一个新的哈希ID$new
和旧的哈希ID$old
:如果分支是全新的,则为全零;如果分支是现有分支名称,则为某个有效的现有提交。如果新的提交是在一个全新的分支上,那么:
型
例如,如果我们知道唯一存在的分支是这四个(并且没有标记等需要担心),那么我们将覆盖它们。但是如果它们被添加到
develop
中呢?然后我们想排除develop
上 * 当前 * 的提交。我们可以使用$old
哈希ID来实现这一点:型
这将再次列出运行
git push origin develop
的任何人想要添加到develop
中的新提交。但是想想
$old
。这是哈希ID。Git从哪里得到的?Git * 从 namedevelop
获取 * 这个哈希ID。这是一个 * 预接收钩子 *;namedevelop
尚未更新。因此,名称develop
* 是旧哈希ID$old
的名称。这意味着:型
我也会做好这份工作。
如果
git rev-list $new
后面跟着“and not all existing”就可以完成任务,那么:型
会做这份工作。这几乎就是我们在这里拥有的。
只使用
--branches
的bug是它没有得到任何标签或其他引用。我们可以使用--not --branches --tags
,但--not --all
更短,也可以获得所有其他参考。这就是
--not --all
的来源:这取决于预接收钩的特殊情况。我们列出了新的哈希ID,这是运行git push
的人提出的,Git已经作为行列表传递给我们的。我们让git rev-list
遍历建议更新的提交图,查看隔离区中的新提交,但排除了存储库中已经存在的所有提交。rev-list命令生成这些散列ID,每行一个,然后我们在shell循环中读取这些ID,并做任何我们喜欢的检查 * 每个提交。1隔离区在Git 2.11中是新的。在此之前,新对象可以在存储库中保留一段时间,即使推送被拒绝。隔离区对大多数人来说并不是什么大问题,但对于像GitHub这样的大型服务器来说,它可以为他们节省大量磁盘空间。
2请求可以是强制的或非强制的,如果是强制的,可以是强制的,也可以不是强制的。这个信息在pre-receive hook中是不可用的(在update hook中也是不可用的),也就是说,嗯,让我们这么说吧,不是很好,但是添加它会有兼容性的问题。不过,大多数都是宜居的。钩子可以判断它是一个 * createnewref * 还是 delete existing ref 请求,因为如果是的话,两个hash ID中的一个-old或new-将是全零的“null hash”(这是保留的;不允许散列ID为全零)。
siotufzp2#
意思是:
$new_list
,新的、修改的或删除的提交)的父链接可到达的提交^
的提交中可到达的提交,这里是“all”,即所有HEADS提交或标记提交。这将rev-list限制为仅接收到的新提交,而不是所有提交(接收到的并且已经存在于接收存储库中)
请注意,现在可以将相同的限制应用到带有pseudo-opts的标准din:
在Git 2.42(2023年第3季度)中,
get_revision()
API的设置代码现在允许在--stdin
模式下提供--all
和--not
等馈送选项。参见commit c40f0b7,commit af37a20,commit cc80450(2023年6月15日)由Patrick Steinhardt (
pks-t
)。(由Junio C Hamano --
gitster
--合并到commit 812907d,2023年7月4日)revision
:我的天啊在--stdin
模式下处理伪选项签收人:帕特里克·斯坦哈特
虽然
git-rev-list
和git-log
都支持--stdin
,但它只接受提交和文件。最值得注意的是,不可能通过stdin传递任何伪选项,如
--all
、--glob=
或其他。这使得在某些脚本化的场景中很难使用这个函数,比如当人们希望支持针对特定修订版本的查询时,也希望支持针对引用模式的查询时。
虽然这在理论上是可以通过使用参数实现的,但一旦我们使用足够大的查询达到平台限制,这可能会遇到问题。
而且因为
--stdin
不能处理伪opts,唯一的替代方法就是混合使用参数和标准输入,这很麻烦。在这两个命令中实现对伪选项的处理支持,以更好地支持此用例。
这里一个值得注意的限制是
--stdin
只支持--glob=foo
形式的“卡住”参数。这是因为“unstuck”参数还需要我们阅读下一行,这会给代码增加相当多的复杂性。
这个限制对于脚本化的使用应该是很好的。
rev-list-options
现在在其手册页中包括:除了从命令行获取参数外,还可以读取它们作为标准输入。
它接受提交和伪选项,如
--all
和--glob=
。当看到--
分隔符时,以下输入被视为路径并用于限制结果。现在这是可能的:
字符串