| 1 | // Every rule `git check-ref-format` applies to a full ref name, checked in-process because a push can carry thousands of refs. |
| 2 | // oxlint-disable-next-line no-control-regex |
| 3 | const FORBIDDEN = / |
| 4 | |
| 5 | /** Whether git accepts `ref` as a full ref name under `refs/`. A ref git would refuse must never reach the log: no node could replay it. */ |
| 6 | export function isWellFormedRef(ref |
| 7 | if (!ref.startsWith |
| 8 | return false; |
| 9 | } |
| 10 | return ref |
| 11 | .split('/') |
| 12 | .every((part) |
| 13 | } |
| 14 | |
| 15 | /** Whether git accepts `name` as a branch or tag. Leading dashes and `HEAD` are refused too, so a name can never reach git as a flag or shadow the symbolic ref. */ |
| 16 | export function isValidRefName(namespace |
| 17 | if (name.startsWith |
| 18 | return isWellFormedRef(`refs/ |
| 19 | } |
| 20 | |
| 21 | /** A ref that cannot coexist with `ref`, since git stores `a` and `a/b` as a file and a directory of the same name; null when there is none. */ |
| 22 | export function directoryConflict(refs |
| 23 | const parts = |
| 24 | for (let end |
| 25 | const parent = |
| 26 | if (refs.has |
| 27 | } |
| 28 | // ponytail: a scan of every ref per pushed ref. Keep the refs sorted if a repository with a very large ref count pushes many refs at once. |
| 29 | const prefix = |
| 30 | for (const other |
| 31 | return null; |
| 32 | } |