Allow all branch names to be glob patterns

01b85955ec11cb99ee24a5af62d7cbbb0e92151e

Tucker McKnight <tmcknight@instructure.com> | Mon Jan 19 2026

Allow all branch names to be glob patterns

Change the way that branches are matched to those patterns so that,
if multiple patterns match a branch name, the most specific pattern
is the one that is used.

Also allows new fields on a branch: description and compareTo. Prints
out the branch description on the branches page.

Also makes the max value work -- kicks out branches from the list if
there are already the max number of branches in the list. TODO:
need to make sure this only kicks out the branches that are the oldest
(that is, not recently committed to).
js_templates/branches.ts:19
Before
18
19
20
21
22
23
                  ${branch.branchName === data.branchInfo.branchName ? '<div class="badge rounded-pill bg-secondary mx-1">current</div>' : ''}
                  ${branch.branchName === data.reposConfig.repos[branch.repoName].defaultBranch ? '<div class="badge rounded-pill bg-info text-dark mx-1">default</div>' : ''}
                </div>
                <div class="card-body">Data about branch goes here</div>
              </div>
            `
            : ''
After
18
19
20
21
22
23
                  ${branch.branchName === data.branchInfo.branchName ? '<div class="badge rounded-pill bg-secondary mx-1">current</div>' : ''}
                  ${branch.branchName === data.reposConfig.repos[branch.repoName].defaultBranch ? '<div class="badge rounded-pill bg-info text-dark mx-1">default</div>' : ''}
                </div>
                <div class="card-body">${branch.description || ''}</div>
              </div>
            `
            : ''
schemas/ReposConfiguration.json:14
Before
13
14
15
16
17
18



19
20
21



22
23
24
25
26
27
              {
                "additionalProperties": false,
                "properties": {
                  "glob": {
                    "type": "string"
                  },
⁣
⁣
⁣
                  "max": {
                    "type": "number"
                  }
⁣
⁣
⁣
                },
                "required": [
                  "glob",
                  "max"
                ],
                "type": "object"
              }
After
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

31
32
              {
                "additionalProperties": false,
                "properties": {
                  "compareTo": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "max": {
                    "type": "number"
                  },
                  "pattern": {
                    "type": "string"
                  }
                },
                "required": [
                  "pattern"
⁣
                ],
                "type": "object"
              }
src/branches.ts:10
Before
9
10
11
12
13
14
15



16
17

  cachedBranches = repos.flatMap((repo) => {
    return repo.branches.map((branch) => {
      return {
        branchName: branch.name,
        repoName: repo.name,
      }
⁣
⁣
⁣
    })
  })
After
9
10
11
12
13
14
15
16
17
18
19
20

  cachedBranches = repos.flatMap((repo) => {
    return repo.branches.map((branch) => {
      const result = {
        branchName: branch.name,
        repoName: repo.name,
      }
      if (branch.description) { result['description'] = branch.description }
      if (branch.compareTo) { result['compareTo'] = branch.compareTo }
      return result
    })
  })
src/configTypes.ts:11
Before
10
11
12
13
14
15
 *   repos: {
 *     "My Git Project": {
 *       defaultBranch: 'main',
 *       branches: ['main', 'develop']
 *     },
 *   },
 * }
After
10
11
12
13
14
15
 *   repos: {
 *     "My Git Project": {
 *       defaultBranch: 'main',
 *       branchesToPull: ['main', 'develop']
 *     },
 *   },
 * }
src/configTypes.ts:53
Before
52
53
54
55
56
57
  location: string,
  description?: string,
  defaultBranch: string,
  branchesToPull: Array<string | {glob: string, max: number}>,
  tags?: Array<string | {glob: string, max: number}>,
  languageExtensions?: {
    [fileExtension: string]: string
After
52
53
54
55
56
57
  location: string,
  description?: string,
  defaultBranch: string,
  branchesToPull: Array<string | {pattern: string, max?: number, compareTo?: string, description?: string}>,
  tags?: Array<string | {glob: string, max: number}>,
  languageExtensions?: {
    [fileExtension: string]: string
src/dataTypes.ts:5
Before
4
5
6


7
8
  defaultBranch: string,
  branches: Array<{
    name: string,
⁣
⁣
    head: string,
    fileList: Array<string>,
  }>,
After
4
5
6
7
8
9
10
  defaultBranch: string,
  branches: Array<{
    name: string,
    description?: string,
    compareTo?: string,
    head: string,
    fileList: Array<string>,
  }>,
src/repos.ts:14
Before
13
14
15
16
17
18
19
20

const exec = util.promisify(childProcess.exec)

const branchesForReposMap: Map<string, string[]> = new Map()

const getBranchNames = async (repoConfig: GitConfig, repoName: string): Promise<Array<string>> => {
  const cachedBranchNames = branchesForReposMap.get(repoName)
  if (cachedBranchNames !== undefined) {
    return cachedBranchNames
After
13
14
15
16
17
18
19
20

const exec = util.promisify(childProcess.exec)

const branchesForReposMap: Map<string, Array<{name: string, description?: string, compareTO?: string}>> = new Map()

const getBranches = async (repoConfig: GitConfig, repoName: string): Promise<Array<{name: string, description?: string, compareTo?: string}>> => {
  const cachedBranchNames = branchesForReposMap.get(repoName)
  if (cachedBranchNames !== undefined) {
    return cachedBranchNames
src/repos.ts:24
Before
After
src/repos.ts:68
Before
After
wiki/projects/branch-globs.md:42
Before
41
42




























    - this is a good reason to put the deployed repo config on the public site, too.
      I currently have different example site configs between my laptop and the deployed
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
      site.
After
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    - this is a good reason to put the deployed repo config on the public site, too.
      I currently have different example site configs between my laptop and the deployed
      site.

## Jan 18, 2026

*An idea:* allow the object with a glob in it to also specify things like the description
and which parent branch the branch should be compared to.

Multiple branch patterns (let's use the word "pattern" instead of "glob") can match
the same branch -- the more specific one should be used.

E.g.:

```
branchesToPull: [
  {
    pattern: "deploy/**",
    description: "A deployed branch",
  },
  {
    pattern: "deploy/v2**",
    description: "A version 2 deployed branch",
  }
]
```

In the above example, branch `deploy/v1.0.1` should have the description "A deployed
branch," but branch `deploy/v2.0.1` should have the description "A version 2
deployed branch."

Is the "more specific pattern" just always the one that is longer? Try this for now.