VCS 软件打包准则 - Arch Linux 中文维基

跳转到内容

# VCS 软件打包准则

来自 Arch Linux 中文维基
翻译状态：

- 本文（或部分内容）译自 VCS package guidelines，最近一次同步于 2025-08-31，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

Arch 打包准则

32 位 – 安全 – CLR – CMake – DKMS – Eclipse – Electron – Free Pascal – GNOME – Go – Haskell – Java – 交叉编译工具 – KDE – Lisp – Meson – MinGW – 内核模块 – Node.js – Nonfree – OCaml – Perl – PHP – Python – R – Ruby – Rust – Shell – VCS – Web – Wine – 字体

相关文章

- Arch 用户软件仓库 (AUR)
- AUR 提交准则
- PKGBUILD

版本控制系统可用于获取常规静态版本软件包的源代码，以及开发分支的最新（主干）版本。

提示：使用 pacman包 软件包提供的 `/usr/share/pacman/PKGBUILD-vcs.proto` 原型文件。

## 包名

除非软件包获取的是特定发布版本，否则应添加后缀 `-bzr`、`-cvs`、`-darcs`、`-git`、`-hg` 或 `-svn` 等。

## 版本

若因修改依赖关系、URL 或源代码导致生成的软件包发生变化，请将 `pkgver` 更新至最新版本。若自上次更新 `PKGBUILD` 以来 `pkgver` 未发生变化，则应递增 `pkgrel` 的值。

建议采用以下版本格式：`发行（release）.r修订（revision）`，其中 `修订` 是唯一标识源代码树的单调递增数字（VCS 修订号即符合此特性）。若无公开发行版本且仓库无标签，可用 0 作为发行版本号，或完全省略 `发行` 部分直接使用形如 `r修订` 的版本号。若有公开发行版本但仓库未打标签，开发者需通过解析项目文件等方式获取发行版本号。

修订号分隔符（`修订` 之前的 `r`）至关重要，可避免上游首次发布版本或使用不同组件数量的版本时出现的问题。例如，若在修订版 `455` 时上游决定发布 `0.1` 版本，修订号分隔符能保持版本单调性：`0.1.r456 > r454`。若无分隔符将导致单调性失效：`0.1.456 < 454`。

提示：可使用 `--holdver` 选项阻止 makepkg 更新 `pkgver`，详见 makepkg(8)。

## 冲突、提供与依赖

- 明确声明软件包冲突与提供，例如 fluxbox-gitAUR 应包含：

      conflicts=('fluxbox')
      provides=("fluxbox=${pkgver}")

  注意：关于版本控制的通用建议（尤其适用于 VCS 软件包），请参阅 PKGBUILD#provides。

- `replaces=()` 通常会引起不必要的问题，应避免使用。

- 在 `makedepends=()` 中包含对应的版本控制工具⸺cvs包、subversion包、git包 等。

## 认证与安全

- 使用 cvsroot 时，优先采用 `anonymous:@` 而非 `anonymous@`，以避免输入空密码；若必须提供密码则使用 `anonymous:password@`。
- 由于源代码并非静态文件，需在 `sha256sums=()` 中通过添加 `'SKIP'` 跳过硬校验。

## VCS 源代码

注意：Arch 官方不支持使用稀疏克隆（sparse clone）或浅克隆（shallow clone），相关讨论参见 FS#34677 及邮件列表。

VCS 源代码需在 `source` 数组中指定，其处理方式与其他类型源代码相同。makepkg 会将仓库克隆/检出/分支（clone/checkout/branch）到 `$SRCDEST` 目录（若未在 makepkg.conf(5) 中设置，则默认使用 `$startdir`），然后以特定于各 VCS 的方式将其复制到 `$srcdir`。本地仓库不会被修改，因此无需使用 `-build` 目录。

`source` 数组的通用格式为：

    source=('[folder::][vcs+]url[#fragment]')

- `folder`（可选）——文件夹名称，用于将默认仓库名称更改为更具意义的名称（例如替代 `trunk`），或保留先前源代码路径
- `vcs+`——当 URL 未体现 VCS 类型时需要添加，例如 `git+https://some_repo`
- `url`——远程或本地仓库的 URL
- `#fragment`（可选）——片段，用于拉取特定分支或提交。各 VCS 支持的片段格式请参阅 PKGBUILD(5) § USING VCS SOURCES

使用 Git 时的 `source` 数组示例：

    source=('project_name::git+https://project_url#branch=project_branch')

警告：请勿在 `folder` 字段中使用 `pkgver` 变量，因为该变量可能在 `pkgver()` 函数调用时被修改，导致后续函数无法访问已创建的文件夹。

## pkgver() 函数

通过专用的 `pkgver()` 函数可实现自动版本更新。这种方式能更精细地控制版本号，维护者应尽量采用有意义的版本格式。使用该函数时，仍需预先声明更改 PKGBUILD 时最新的 `pkgver` 变量值，makepkg 工具会自动调用 `pkgver()` 并更新该变量。

### Bazaar

    pkgver() {
      cd "$pkgname"
      printf "r%s" "$(bzr revno)"
    }

    r830

### Git

基于最后提交可达的最近的带注释的标签生成版本号：

    pkgver() {
      cd "$pkgname"
      git describe --long --abbrev=7 | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
    }

    2.0.r6.ga17a017

基于最后提交可达的最近的未注释的标签生成版本号：

    pkgver() {
      cd "$pkgname"
      git describe --long --tags --abbrev=7 | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
    }

    0.71.r115.gd95ee07

若 git-tag(1) 名称不含连字符，可使用简化 sed(1) 表达式 `sed 's/-/.r/;s/-/./'`。

当标签包含前缀（如 `v` 或项目名）时需进行截取：

    pkgver() {
      cd "$pkgname"
      # 移除Git标签中的'foo-'前缀
      git describe --long --abbrev=7 | sed 's/^foo-//;s/\([^-]*-g\)/r\1/;s/-/./g'
    }

    6.1.r3.gd77e105

无可用标签时使用历史提交计数：

    pkgver() {
      cd "$pkgname"
      printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
    }

    r1142.a17a017

省略 SHA-1 哈希，仅保留版本号与修订号（注意此时若版本号混乱，将无法快速定位到具体修订版本）：

    git describe --long --abbrev=7 --tags | sed 's/\([^-]*\)-g.*/r\1/;s/-/./g'

可组合使用两种方法以支持开始无标签、后期添加标签的仓库（使用了 bash 特性）：

    pkgver() {
      cd "$pkgname"
      ( set -o pipefail
        git describe --long --abbrev=7 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
        printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
      )
    }

    0.9.9.r27.g2b039da  # 存在标签时
    r1581.2b039da       # 无标签时回退方案

### Mercurial

    pkgver() {
      cd "$pkgname"
      printf "r%s.%s" "$(hg identify -n)" "$(hg identify -i)"
    }

    r2813.75881cc5391e

### Subversion

    pkgver() {
      cd "$pkgname"
      local ver="$(svnversion)"
      printf "r%s" "${ver//[[:alpha:]]}"
    }

    r8546

注意：应优先采用项目正式发布版本（如果有），而非使用 `0.` 占位符。

### 回退方案

当无法从仓库提取有效版本时，可使用当前日期：

    pkgver() {
      date +%Y%m%d
    }

    20130408

注意：此方法无法唯一标识代码状态，应尽量避免使用。

## 提示与技巧

### Git 子模块

Git 子模块的处理需要特别注意。核心思路是将子模块自身的 URL 直接添加到 `sources` 数组，然后在 `prepare()` 阶段进行引用。

下游项目开发者可能不会使用与上游仓库相同的子模块命名。要查看 Git 子模块名称，需访问项目仓库中的 `.gitmodules` 文件。例如，上游开发者命名为 `lib-dependency` 的仓库，在下游 `.gitmodules` 中可能注册为 `libs/libdep` 子模块。

    [submodule "libs/libdep"]
      path = libs/libdep
      url = https://example.org/lib-dependency/lib-dependency.git

    source=("git+https://example.org/main-project/main-project.git"
            https://example.org/lib-dependency/lib-dependency.git)

    prepare() {
      cd main-project
      git submodule init
      git config submodule.libs/libdep.url "$srcdir/lib-dependency"
      git -c protocol.file.allow=always submodule update
    }

### Git 大文件存储（LFS）

Git 大文件存储（LFS）需要一些额外配置：

    makedepends=(... 'git-lfs')

    prepare() {
      git lfs install --local
      git remote add network-origin https://example.org/upstream/lfs/repo
      git lfs fetch network-origin
      git lfs checkout
    }

这在子模块中使用 LFS 时也可用：

    prepare() {
      git submodule init
      git config submodule.libs/libdep.url "$srcdir/lib-dependency"
      git -c protocol.file.allow=always submodule update

      git -C libs/libdep lfs install --local
      git -C libs/libdep remote add network-origin https://example.org/upstream/lfs/repo
      git -C libs/libdep lfs fetch network-origin
      git -C libs/libdep lfs checkout
    }

### Git 校验和

当通过 `git+https://domain.invalid/repository.git#tag=v1.0.0` 引用稳定的 Git 标签或特定提交作为源时，可以在 `PKGBUILD` 中指定校验和。只需使用 `makepkg -g` 或 `updatepkgsums` 生成校验和，操作方式与其他非 Git 源相同。

分类：​

- Arch 打包准则

VCS 软件打包准则
添加话题