20

git post-receivePython でフックを開発しています。データは次stdinのような行で提供されます

ef4d4037f8568e386629457d4d960915a85da2ae 61a4033ccf9159ae69f951f709d9c987d3c9f580 refs/heads/master

最初のハッシュは古い参照、2 番目のハッシュは新しい参照、3 番目の列は更新される参照です。

入力を検証しながら、これを 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にあるいくつかのテストを 作成しました。

ステータス: 以下の正規表現はすべてコンパイルに失敗しています。これは、スクリプトに問題があるか、構文に互換性がないことを示している可能性があります。

4

6 に答える 6

41

さまざまなルールを分析して、それらから正規表現の部分を構築しましょう。

  1. 階層 (ディレクトリ) グループ化のためにスラッシュを含めることができます/が、スラッシュで区切られたコンポーネントをドットで開始し.たり、シーケンスで終了したりすることはできません.lock

     # must not contain /.
     (?!.*/\.)
     # must not end with .lock
     (?<!\.lock)$
    
  2. 少なくとも 1 つ含まれている必要があります/。これにより、heads/、tags/ などのカテゴリの存在が強制されますが、実際の名前は制限されません。オプションを使用する--allow-onelevelと、このルールは適用されません。

     .+/.+  # may get more precise later
    
  3. どこにも2 つの連続したドットを含めることはできません..

     (?!.*\.\.)
    
  4. \040ASCII 制御文字 (値が、 またはより小さいバイト\177 DEL)、スペース、チルダ~、キャレット^、またはコロンを:どこにも含めることはできません。

     [^\000-\037\177 ~^:]+   # pattern for allowed characters
    
  5. 疑問符?、アスタリスク*、または開き括弧を[どこにも含めることはできません。--refspec-patternこの規則の例外については、以下のオプションを参照してください。

     [^\000-\037\177 ~^:?*[]+   # new pattern for allowed characters
    
  6. /スラッシュで開始または終了したり、複数の連続したスラッシュを含めたりすることはできません(--normalizeこの規則の例外については、以下のオプションを参照してください) 。

     ^(?!/)
     (?<!/)$
     (?!.*//)
    
  7. ドットで終わることはできません.

     (?<!\.)$
    
  8. シーケンスを含めることはできません@{

     (?!.*@\{)
    
  9. を含めることはできません\

     (?!.*\\)
    

すべてをつなぎ合わせると、次の怪物にたどり着きます。

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

そして、で始まるものを除外したい場合はbuild-、別の先読みを追加するだけです:

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

これは、共通のパターンを探すいくつかのものを混同することで、少し最適化することもできます。

^(?!@$|build-|/|.*([/.]\.|//|@\{|\\))[^\000-\037\177 ~^:?*[]+/[^\000-\037\177 ~^:?*[]+(?<!\.lock|[/.])$
于 2012-08-23T14:31:12.667 に答える
19

git check-ref-format <ref>可能性subprocess.Popenがあります:

import subprocess
process = subprocess.Popen(["git", "check-ref-format", ref])
exit_status = process.wait()

利点:

  • アルゴリズムが変更された場合、チェックは自動的に更新されます
  • これは、モンスターの正規表現では難しいことです

短所:

  • サブプロセスのため遅くなります。しかし、時期尚早の最適化は諸悪の根源です。
  • バイナリ依存関係として Git が必要です。しかし、フックの場合は常に存在します。

libgit2への C バインディングを使用するpygit2check-ref-formatは、そこに公開されている場合、よりも高速であるため、さらに良い可能性がありますPopenが、私はそれを見つけていません。

于 2014-07-28T08:41:26.620 に答える
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++ ですが、いくつか修正を加えました。

于 2013-05-31T12:54:44.103 に答える
2

有効な Git ブランチ名と一致する PCRE 正規表現を探してこの質問に来る人にとっては、次のとおりです。

^(?!/|.*([/.]\.|//|@\{|\\\\))[^\040\177 ~^:?*\[]+(?<!\.lock|[/.])$

これはJoeyによって書かれた正規表現の修正版です。ただし、このバージョンでは、斜めは必要ありません (branchNameではなく、一致させるためですrefs/heads/branchName)。

この質問に対する彼の正解を参照してください。git-check-ref-format(1)彼は、正規表現の各部分の完全な内訳と、それがマニュアル ページで指定された各要件とどのように関連しているかを提供します。

于 2012-12-05T14:52:06.033 に答える
1

リンクされたページから直接ルールを取得すると、次の正規表現はrefs/heads、「build-」で始まらない有効なブランチ名のみに一致する必要があります。

refs/heads/(?!.)(?!build-)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+))(?<!\.)(?<!\.lock)

これはrefs/headsあなたのように始まります。

次に(?!build-)、次の 6 文字が ではないことbuild-(?!.)確認し、分岐が で始まっていないことを確認し.ます。

グループ全体(((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+)がブランチ名と一致します。

(?!\.\.)は、2 つのピリオドが連続して存在しないことを(?!@{)確認し、ブランチに が含まれていないことを確認します@{

次に、制御文字と、明確に禁止されている残りのすべての[^\cA-\cZ ~^:?*[\\]文字を除外することにより、許可された文字のいずれかに一致します。\cA-\cZ

最後に(?<!\.)、ブランチ名がピリオドで終わっていないことを(?<!.lock)確認し、. で終わっていないことを確認し.\lockます。

これは、任意のフォルダー内の有効なブランチ名と同様に一致するように拡張できます。

(?!.)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+))(/(?!.)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+)))*?/(?!.)(?!build-)((?!\.\.)(?!@{)[^\cA-\cZ ~^:?*[\\])+))(?<!\.)(?<!\.lock)

これは、ブランチ名の各部分に基本的に同じルールを適用しますが、最後のものがで始まらないことのみをチェックしますbuild-

于 2012-08-23T14:33:41.770 に答える