我正在开发git
post-receive
hook in Python。数据在stdin
上提供,其行与
ef4d4037f8568e386629457d4d960915a85da2ae 61a4033ccf9159ae69f951f709d9c987d3c9f580 refs/heads/master
第一个哈希是old-ref,第二个是new-ref,第三列是要更新的引用。
我想将其拆分为3个变量,同时验证输入。 如何验证分支名称?
我目前正在使用以下正则表达式
^([0-9a-f]{40}) ([0-9a-f]{40}) refs/heads/([0-9a-zA-Z]+)$
这不接受所有可能的分支名称,如man git-check-ref-format所述。例如,它会以名称build-master
排除分支,该分支有效。
我实际上想要排除任何以“build-”开头的分支。这可以在同一个正则表达式中完成吗?
鉴于下面的答案很好,我写了一些测试,可以在这里找到 https://github.com/alexchamberlain/githooks/blob/master/miscellaneous/git-branch-re-test.py
状态:以下所有正则表达式都无法编译。这可能表示我的脚本存在问题或语法不兼容。
答案 0 :(得分:29)
让我们剖析各种规则并从中构建正则表达式部分:
它们可以包括用于分层(目录)分组的斜杠/
,但没有斜杠分隔的组件可以以点.
开头或以序列.lock
结束。 / p>
# must not contain /.
(?!.*/\.)
# must not end with .lock
(?<!\.lock)$
它们必须包含至少一个/
。这强制存在类似head /,tags /等的类别,但实际名称不受限制。如果使用--allow-onelevel
选项,则免除此规则。
.+/.+ # may get more precise later
他们不能在任何地方连续两个点..
。
(?!.*\.\.)
它们不能包含ASCII控制字符(即值小于\040
或\177 DEL
的字节),空格,波浪号~
,插入符^
,或冒号:
。
[^\000-\037\177 ~^:]+ # pattern for allowed characters
他们不能在任何地方添加问号?
,星号*
或开括号[
。请参阅下面的--refspec-pattern
选项,了解此规则的例外情况。
[^\000-\037\177 ~^:?*[]+ # new pattern for allowed characters
它们不能以斜杠/
开头或结尾,也不能包含多个连续斜杠(有关此规则的例外情况,请参阅下面的--normalize
选项)
^(?!/)
(?<!/)$
(?!.*//)
它们不能以点.
结尾。
(?<!\.)$
它们不能包含序列@{
。
(?!.*@\{)
它们不能是单个字符@
。
(?!@$)
它们不能包含\
。
(?!.*\\)
将它们拼凑在一起我们得到了以下怪物:
^(?!.*/\.)(?!.*\.\.)(?!/)(?!.*//)(?!.*@\{)(?!@$)(?!.*\\)[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock)(?<!/)(?<!\.)$
如果您想要排除那些以build-
开头的内容,那么只需添加另一个前瞻:
^(?!build-)(?!.*/\.)(?!.*\.\.)(?!/)(?!.*//)(?!.*@\{)(?!@$)(?!.*\\)[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock)(?<!/)(?<!\.)$
通过混淆一些寻找常见模式的东西,可以对此进行优化:
^(?!@$|build-|/|.*([/.]\.|//|@\{|\\))[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock|[/.])$
答案 1 :(得分:11)
git check-ref-format <ref>
与subprocess.Popen
有可能:
import subprocess
process = subprocess.Popen(["git", "check-ref-format", ref])
exit_status = process.wait()
优点:
缺点:
libgit2,如果check-ref-format
暴露在那里会更好,因为它会比Popen
更快,但我没找到它。
答案 2 :(得分:3)
没有必要在Perl中编写怪物。只需使用/ x:
# RegExp rules based on git-check-ref-format
my $valid_ref_name = qr%
^
(?!
# begins with
/| # (from #6) cannot begin with /
# contains
.*(?:
[/.]\.| # (from #1,3) cannot contain /. or ..
//| # (from #6) cannot contain multiple consecutive slashes
@\{| # (from #8) cannot contain a sequence @{
\\ # (from #9) cannot contain a \
)
)
# (from #2) (waiving this rule; too strict)
[^\040\177 ~^:?*[]+ # (from #4-5) valid character rules
# ends with
(?<!\.lock) # (from #1) cannot end with .lock
(?<![/.]) # (from #6-7) cannot end with / or .
$
%x;
foreach my $branch (qw(
master
.master
build/master
ref/HEAD/blah
/HEAD/blah
HEAD/blah/
master.lock
head/@{block}
master.
build//master
build\master
build\\master
),
'master blaster',
) {
print "$branch --> ".($branch =~ $valid_ref_name)."\n";
}
Joey ++的一些代码,虽然我做了一些更正。
答案 3 :(得分:1)
直接从链接页面获取规则,以下正则表达式应仅匹配refs/heads
中不以“build - ”开头的有效分支名称:
refs/heads/(?!.)(?!build-)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+))(?<!\.)(?<!\.lock)
这一开始就是refs/heads
。
然后(?!build-)
会检查接下来的6个字符不是build-
而(?!.)
会检查分支是否以.
开头。
整个组(((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+)
与分支名称匹配。
(?!\.\.)
检查连续两个句点没有实例,(?!@{)
检查分支是否包含@{
。
然后[^\cA-\cZ ~^:?*[\\]
通过排除控制字符\cA-\cZ
和所有其他特别禁止的字符来匹配任何允许的字符。
最后,(?<!\.)
确保分支名称不以句点结束,并(?<!.lock)
检查它是否以.\lock
结尾。
这可以扩展为类似地匹配任意文件夹中的有效分支名称,您可以使用
(?!.)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+))(/(?!.)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+)))*?/(?!.)(?!build-)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+))(?<!\.)(?<!\.lock)
这基本上对每个分支名称应用相同的规则,但仅检查最后一个不以build-
开头
答案 4 :(得分:1)
对于前来这个问题寻找PCRE正则表达式以匹配有效Git分支名称的人,它是以下内容:
^(?!/|.*([/.]\.|//|@\{|\\\\))[^\040\177 ~^:?*\[]+(?<!\.lock|[/.])$
这是由Joey编写的正则表达式的修订版本。但是,在此版本中,不需要倾斜(用于匹配branchName
而不是refs/heads/branchName
)。
请参阅他的正确answer to this question。
他提供了正则表达式各部分的完整细分,以及它与git-check-ref-format(1)
manual pages中指定的每个要求的关系。
答案 5 :(得分:0)
如果要检查引用对pygit2是否有效,可以执行该功能(code copied from documentation):
from pygit2 import reference_is_valid_name
reference_is_valid_name("refs/heads/master")