Worktrees

To complement branches, Antora can use the worktree that is linked to each branch it discovers in a local repository. This behavior is controlled using the worktrees key. The worktrees key accepts a keyword or a list of exact branch names or glob patterns.

Worktrees are only relevant for branches, not tags.

worktrees key

The worktrees key is optional. If not specified, Antora will automatically use the main (i.e., primary) worktree of a local repository if the current branch of that repository is among the branches matched by the branches key. If such a match is made, Antora will take the files from the worktree instead of the files from the git tree for that branch.

By default, Antora only uses the main worktree (not to be confused with the main branch), not linked worktrees. To customize this behavior, you can set the worktrees key.

The main worktree is not necessarily linked to the main branch, but rather to the current branch of the local repository.

The worktrees key is specified on the entry for a content source. The key accepts a keyword or a list of branch name patterns. Each branch name pattern can either be an exact branch name or a positive or negative glob pattern.

To enable the use of all worktrees, simply set the worktrees key to the keyword value true.

Example 1. antora-playbook.yml
content:
  sources:
  - url: /path/to/repo-a/main
    branches: [v1.0, v2.0, main]
    worktrees: true

In order for Antora to discover linked worktrees, the url key must point to the location of the main worktree (where the .git folder is located). If the url points directly to a linked worktree, Antora will not recognize it as a valid git repository.

Linked worktree as content source

It’s possible to get Antora to support using a linked worktree as a content source with the help of an extension. The following Antora extension will detect when the url key of a content source points to a linked worktree, then reconfigure the content source to point to the main worktree instead.

'use strict'

/* Copyright (c) 2022 OpenDevise, Inc.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License Version 2.0. If a copy of this license was not distributed
 * with this file, you can obtain one at http://mozilla.org/MPL/2.0/.
 */
const { promises: fsp } = require('fs')
const ospath = require('path')

/**
 * Rewrites local content sources to support the use of linked worktrees.
 *
 * @author Dan Allen <dan@opendevise.com>
 */
module.exports.register = function () {
  this.once('playbookBuilt', async ({ playbook }) => {
    const expandPath = this.require('@antora/expand-path-helper')
    for (const contentSource of playbook.content.sources) {
      const { url, branches } = contentSource
      if (url.charAt() !== '.') continue
      const absdir = expandPath(url, { dot: playbook.dir })
      const gitfile = ospath.join(absdir, '.git')
      if (await fsp.stat(gitfile).then((stat) => !stat.isDirectory(), () => false)) {
        const worktreeGitdir = await fsp.readFile(gitfile, 'utf8')
          .then((contents) => contents.trimRight().substr(8))
        const worktreeBranch = await fsp.readFile(ospath.join(worktreeGitdir, 'HEAD'), 'utf8')
          .then((contents) => contents.trimRight().replace(/^ref: (?:refs\/heads\/)?/, ''))
        const reldir = ospath.relative(
          playbook.dir,
          await fsp.readFile(ospath.join(worktreeGitdir, 'commondir'), 'utf8')
            .then((contents) => {
              const gitdir = ospath.join(worktreeGitdir, contents.trimRight())
              return ospath.basename(gitdir) === '.git' ? ospath.dirname(gitdir) : gitdir
            })
        )
        contentSource.url = reldir ? `.${ospath.sep}${reldir}` : '.'
        if (!branches) continue
        contentSource.branches = (branches.constructor === Array ? branches : [branches])
          .map((pattern) => pattern.replaceAll('HEAD', worktreeBranch))
      }
    }
  })
}

Save this file next to your playbook file and load it using --extension ./linked-worktree-as-content-source.js when invoking Antora. Once #535 is resolved, this patch will no longer be necessary.

Specify worktrees by keyword

The worktrees key accepts the following keyword values:

true

Use all worktrees (the main worktree and all linked worktrees).

false (or ~)

Do not use any worktrees (not the main worktree and not any linked worktrees).

.

Use only the main worktree. (default)

*

Use only the linked worktrees.

If you want Antora to bypass all worktrees, set the value of the worktrees key to the keyword false.

Example 2. antora-playbook.yml
content:
  sources:
  - url: /path/to/repo-a/main
    branches: [v1.0, v2.0, main]
    worktrees: false

Specify worktrees by glob pattern

If you want more fine-grained control over which worktrees Antora uses, you can specify a list of glob patterns. You refer to worktrees by the branch name to which they are linked. Thus, the glob pattern works the same as described on the Branches page. If you want to refer to the current branch, you do so using the . keyword. If present, that entry must appear first in the list.

Let’s configure Antora to use the main worktree as well as the linked worktree for the v2.0 branch. The files for the v1.0 branch will be read from the git tree, even if there is a linked worktree associated with that branch.

Example 3. antora-playbook.yml
content:
  sources:
  - url: /path/to/repo-a/main
    branches: [v1.0, v2.0, main]
    worktrees: [., v2.0]

Configure multiple worktrees

To learn how to configure multiple worktrees, refer to this guide on the Author Mode page.