Search code examples
regexgitregex-group

Regex for git branch naming


I am looking for a regex to enforce a valid git branch naming convention.

Rules are

  1. A branch name can only be main, master, development
  2. A branch name can start with features, tests, bugfix, hotfix; followed by / description, number, -, _ (or nesting of it but max allowed in upto 2)
  3. A branch name can start with release/ then version number, and it can have beta, alpha or rc tag with or without number.

Here are the example of few valid name

main
bugfix/user-list
bugfix/user_list
bugfix/123
bugfix/123/account-update
bugfix/123/account_update
bugfix/User_crud/account-update
bugfix/User_crud/account_update
tests/api
tests/123
tests/123/hello
release/1.0.1
release/1.0.1-beta1
release/1.0.1-beta
release/1.0.1-rc3

I had written this regex (https://regex101.com/r/n0CAuM/1), but it is not matching all the above example

^(development|master|main|(((features|tests|bugfix|hotfix)\/(([0-9A-Za-z-_]+)|((\/[0-9A-Za-z-_]+)))|release\/(?:(\d+)\.)?(?:(\d+)\.)?(\d+)?(-(alpha|beta|rc)[0-9]))))

Also note as I will be using the regex in a bash script which only support POSIX regex engine.


Solution

  • You can put the alternations for all 3 parts in their own part of the pattern.

    For the groupings, instead of a non capture group you can use a capture group, and for the digits use [0-9] instead of \d.

    If there is maximum of 1-2 parts, you can use a quantifier {1,2}

    You could write the pattern as:

    ^(main|development|master|(features|tests|(bug|hot)fix)(\/[a-zA-Z0-9]+([-_][a-zA-Z0-9]+)*){1,2}|release\/[0-9]+(\.[0-9]+)*(-(alpha|beta|rc)[0-9]*)?)$
    
    • ^ Start of string
    • ( Start outer grouping to match 1 of the 3 allowed patterns
      • main|development|master Match 1 of the single named alternatives
      • | Or
      • (features|tests|(bug|hot)fix)(\/[a-zA-Z0-9]+([-_][a-zA-Z0-9]+)*){1,2} Match a variation for features, tests and fixes a following with / and not starting with - or _ and repeat that part 1 or 2 times
      • | Or
      • release\/[0-9]+(\.[0-9]+)*(-(alpha|beta|rc)[0-9]*)? Match a variation for the release branch with optional alpha, beta or rc
    • ) Close outer grouping
    • $ End of string

    See a regex demo and a Bash demo.

    Example

    array=(development main bugfix/user-list bugfix/user_list bugfix/123 bugfix/123/account-update bugfix/123/account_update bugfix/User_crud/account-update bugfix/User_crud/account_update tests/api tests/123 tests/123/hello release/1.0.1 release/1.0.1-beta1 release/1.0.1-beta release/1.0.1-rc3 bugfix/ bugfix/- bugfix/_ bugfix/-name bugfix/_name bugfix/-/name bugfix/-/- bugfix/-/_ release/v1.0.1)
    
    for i in "${array[@]}"
    do
        if [[ "$i" =~ ^(main|development|master|(features|tests|(bug|hot)fix)(/[a-zA-Z0-9]+([-_][a-zA-Z0-9]+)*){1,2}|release/[0-9]+(\.[0-9]+)*(-(alpha|beta|rc)[0-9]*)?)$ ]]; then
          echo "Match: "$i
      else
          echo "No match: "$i
      fi
    done
    

    Output

    Match: development
    Match: main
    Match: bugfix/user-list
    Match: bugfix/user_list
    Match: bugfix/123
    Match: bugfix/123/account-update
    Match: bugfix/123/account_update
    Match: bugfix/User_crud/account-update
    Match: bugfix/User_crud/account_update
    Match: tests/api
    Match: tests/123
    Match: tests/123/hello
    Match: release/1.0.1
    Match: release/1.0.1-beta1
    Match: release/1.0.1-beta
    Match: release/1.0.1-rc3
    No match: bugfix/
    No match: bugfix/-
    No match: bugfix/_
    No match: bugfix/-name
    No match: bugfix/_name
    No match: bugfix/-/name
    No match: bugfix/-/-
    No match: bugfix/-/_
    No match: release/v1.0.1