如何检查有效的Git分支名称?

Ale*_*ain 17 python regex git githooks

我正在git post-receive用Python开发一个钩子.提供的数据stdin与类似的行

ef4d4037f8568e386629457d4d960915a85da2ae 61a4033ccf9159ae69f951f709d9c987d3c9f580 refs/heads/master
Run Code Online (Sandbox Code Playgroud)

第一个哈希是old-ref,第二个哈希是new-ref,第三列是要更新的引用.

我想将它分成3个变量,同时也验证输入.如何验证分支名称?

我目前正在使用以下正则表达式

^([0-9a-f]{40}) ([0-9a-f]{40}) refs/heads/([0-9a-zA-Z]+)$
Run Code Online (Sandbox Code Playgroud)

这不接受所有可能的分支名称,如man git-check-ref-format所示.例如,它排除名称build-master为有效的分支.

奖励标记

我实际上想要排除任何以"build-"开头的分支.这可以在同一个正则表达式中完成吗?

测试

鉴于下面的答案很好,我写了一些测试,可以在https://github.com/alexchamberlain/githooks/blob/master/miscellaneous/git-branch-re-test.py找到 .

状态:以下所有正则表达式都无法编译.这可能表示我的脚本存在问题或语法不兼容.

Joe*_*oey 30

让我们剖析各种规则并从中构建正则表达式部分:

  1. 它们可以包括/用于分层(目录)分组的斜杠,但是没有斜杠分隔的组件可以以点.或结束序列开头.lock.

    # must not contain /.
    (?!.*/\.)
    # must not end with .lock
    (?<!\.lock)$
    
    Run Code Online (Sandbox Code Playgroud)
  2. 它们必须包含至少一个/.这强制存在类似head /,tags /等的类别,但实际名称不受限制.如果使用该--allow-onelevel选项,则放弃此规则.

    .+/.+  # may get more precise later
    
    Run Code Online (Sandbox Code Playgroud)
  3. 他们不能在..任何地方连续两个点.

    (?!.*\.\.)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 它们不能具有ASCII控制字符(即值小于\040或等于的字节\177 DEL),空格,波浪号~,插入符号^或冒号:.

    [^\000-\037\177 ~^:]+   # pattern for allowed characters
    
    Run Code Online (Sandbox Code Playgroud)
  5. 它们不能在任何地方都有问号?,星号*或开括号[.有关--refspec-pattern此规则的例外情况,请参阅下面的选项.

    [^\000-\037\177 ~^:?*[]+   # new pattern for allowed characters
    
    Run Code Online (Sandbox Code Playgroud)
  6. 它们不能以斜杠开头或结尾,也不能/包含多个连续斜杠(有关--normalize此规则的例外情况,请参阅下面的选项)

    ^(?!/)
    (?<!/)$
    (?!.*//)
    
    Run Code Online (Sandbox Code Playgroud)
  7. 它们不能以点结尾..

    (?<!\.)$
    
    Run Code Online (Sandbox Code Playgroud)
  8. 它们不能包含序列@{.

    (?!.*@\{)
    
    Run Code Online (Sandbox Code Playgroud)
  9. 他们不能是单一的角色@.

    (?!@$)
    
    Run Code Online (Sandbox Code Playgroud)
  10. 他们不能包含\.

    (?!.*\\)
    
    Run Code Online (Sandbox Code Playgroud)

将它们拼凑在一起我们得到了以下怪物:

^(?!.*/\.)(?!.*\.\.)(?!/)(?!.*//)(?!.*@\{)(?!@$)(?!.*\\)[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock)(?<!/)(?<!\.)$
Run Code Online (Sandbox Code Playgroud)

如果你想要排除那些以那些开头的东西,build-那么只需添加另一个前瞻:

^(?!build-)(?!.*/\.)(?!.*\.\.)(?!/)(?!.*//)(?!.*@\{)(?!@$)(?!.*\\)[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock)(?<!/)(?<!\.)$
Run Code Online (Sandbox Code Playgroud)

通过混淆一些寻找常见模式的东西,可以稍微优化一下:

^(?!@$|build-|/|.*([/.]\.|//|@\{|\\))[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock|[/.])$
Run Code Online (Sandbox Code Playgroud)

  • 我猜猫比它们看起来更聪明。他们没有骗我! (2认同)

Cir*_*四事件 11

git check-ref-format <ref>subprocess.Popen可能:

import subprocess
process = subprocess.Popen(["git", "check-ref-format", ref])
exit_status = process.wait()
Run Code Online (Sandbox Code Playgroud)

好处:

  • 如果算法发生变化,检查将自动更新
  • 你肯定会把它做对,这对于怪物正则表达来说更难

缺点:

  • 由于子进程较慢.但过早的优化是所有邪恶的根源.
  • 需要Git作为二进制依赖.但是在钩子的情况下,它总会在那里.

pygit2,它使用C绑定到libgit2,如果check-ref-format暴露在那里会更好的可能性,因为它会更快Popen,但我还没有找到它.