GitHub branch naming

How Pyloq matches a pull request to a ticket, and how to enforce the convention on your team.
Connect GitHub from Pyloq under Connectors, then choose the repos Pyloq tracks and their dev and production branches.

Why this matters

Once a repo and dev branch are configured on the GitHub connector, Pyloq checks whether a ticket's pull request has merged into that branch. If it has — and the ticket's status in Jira or ClickUp hasn't caught up yet — the next standup question becomes specific instead of generic: “the PR for PYL-123 is merged — should I help move it to QA or Done?” instead of “what's the status?”

Pyloq matches a PR to a ticket by its branch name first, falling back to the PR titleif the branch doesn't reference a ticket key.

Branch naming convention

Name branches with the ticket key right after the prefix. Pyloq finds the key anywhere in the name, so whatever follows it is fine:

Branch names
feature/PYL-123-short-description   # new work or features
bugfix/PYL-123-short-description    # non-urgent bug fixes
hotfix/PYL-123-short-description    # urgent production fixes
release/v1.2.3                      # preparing a release (no ticket key)

If a branch wasn't named this way, putting the ticket key in the pull request title (e.g. PYL-123: add login page button) still works as a fallback.

Using ClickUp? The key is your Custom Task ID, like PYL-406. See Connect ClickUp.

Enforcing it automatically

The convention only works if branches actually follow it, so a git hook catches a bad branch name before it's pushed. .git/hooksisn't shared with your team because git doesn't track it, so the script goes in the repo and a hook runner wires it up on each machine.

1. Add the check script

Save this as scripts/check-branch-name.sh:

scripts/check-branch-name.sh
#!/usr/bin/env sh

VALID_BRANCH_REGEX="^(feature|bugfix|hotfix|chore)/[A-Z]+-[0-9]+-.+$|^release/v[0-9]+\.[0-9]+\.[0-9]+$"
PROTECTED_BRANCHES="^(main|master|develop|dev|staging|prod)$"

check_branch() {
  branch="$1"
  [ -z "$branch" ] && return 0

  # Shared integration branches (dev/staging/prod/main) aren't named with the
  # convention themselves — only feature/bugfix/hotfix/release branches are.
  echo "$branch" | grep -qE "$PROTECTED_BRANCHES" && return 0

  if ! echo "$branch" | grep -qE "$VALID_BRANCH_REGEX"; then
    echo "❌ Invalid branch name: $branch"
    echo "   Expected: feature/PYL-123-short-description"
    echo "   or:       release/v1.2.3"
    return 1
  fi
  return 0
}

# git hands pre-push the refs actually being pushed on stdin — which can differ
# from the checked-out branch (e.g. pushing a branch you're not on), so prefer
# it. Some hook runners invoke this without forwarding stdin, hence the fallback.
status=0
saw_ref=""

if [ ! -t 0 ]; then
  while read -r local_ref local_sha remote_ref remote_sha; do
    saw_ref="yes"
    check_branch "$(echo "$remote_ref" | sed 's#refs/heads/##')" || status=1
  done
fi

if [ -z "$saw_ref" ]; then
  check_branch "$(git rev-parse --abbrev-ref HEAD)" || status=1
fi

exit $status

2. Make it executable

Terminal
chmod +x scripts/check-branch-name.sh

It's a plain shell script, so it works the same whatever your project is written in — only the hook runner below differs.

3. Wire it into your git hooks

Pick your project's language:

Using Husky to run the script on every push.

1. Install Husky and initialize it

Husky
npm install husky --save-dev
npx husky init

2. Point the pre-push hook at the script

Husky
echo './scripts/check-branch-name.sh' > .husky/pre-push

3. Commit it

Husky
git add .husky/pre-push scripts/check-branch-name.sh
git commit -m "chore: enforce branch naming convention on pre-push"

Husky sets itself up via the prepare script, so teammates get the hook automatically on npm install.Pushing a branch that doesn't match the convention is rejected locally, before it ever reaches GitHub.