PAYATHON 2026

如何用 Git 管理多个 LaTeX 仓库共同依赖的本地 bib 仓库?

数据小陈

建议使用 git submodule:把 bib 文件放在独立仓库中维护,让每个文章仓库记录所使用的 bib 仓库提交。这样,文章可以继续使用旧版参考文献,升级依赖时也会在文章仓库中留下明确的变更。

submodule 可以使用本地路径,无需连接远程服务器。需要注意,每篇文章通常都有自己的 bib 工作目录;如果多篇文章的符号链接指向同一个可变文件,就无法同时使用不同版本。

为什么 submodule 适合这个需求

文章仓库通过 submodule 记录依赖仓库的具体 commit,不必始终跟随它的最新分支。例如:

paper-a 的某次提交 → bib 仓库的提交 A
paper-b 的某次提交 → bib 仓库的提交 B

之后即使 bib 源仓库继续更新,这两个文章提交记录的依赖版本也不会改变。切换文章版本后,更新 submodule 工作目录,就能取出对应的 bib 文件。

这里的“一个 bib 仓库”指统一维护的源仓库。各篇文章中的 submodule 是它的本地克隆,可以分别检出不同提交。

在本地接入 bib 仓库

假设已有以下目录,并且 bib 仓库已经提交了 refs.bib:

/home/me/bib/                 # 独立的 bib Git 仓库
/home/me/articles/paper-a/    # 已有的文章 Git 仓库

在文章仓库中执行:

cd /home/me/articles/paper-a

git -c protocol.file.allow=always submodule add /home/me/bib bibliography
git commit -m "Add bibliography submodule"

文章中的文件路径可以相应调整为:

% 使用 biblatex 时
\addbibresource{bibliography/refs.bib}

如果使用传统 BibTeX,则通常写成:

\bibliography{bibliography/refs}

两种写法对应不同的参考文献工具链,按现有 LaTeX 配置选择即可。

本地路径涉及 Git 的 file 协议。某些 Git 配置会限制 submodule 使用该协议,因此示例通过 -c protocol.file.allow=always 仅对当前命令放行。只应对可信的本地仓库使用这个设置,无需全局开启。

如何升级某篇文章使用的 bib 版本

可以继续在 /home/me/bib 中集中编辑并提交参考文献。需要让某篇文章采用新版本时,在文章仓库中执行:

cd /home/me/articles/paper-a

git -C bibliography fetch origin
git -C bibliography switch --detach origin/main

# 确认文章能够正常编译后,记录新的依赖提交

git add bibliography
git commit -m "Update bibliography version"

这里假设 bib 仓库的分支名是 main,实际使用时请替换为自己的分支名。在这个本地示例中,origin 指向 /home/me/bib,所以 fetch 不需要网络。

也可以直接选择 submodule 本地对象库中已有的某个提交:

git -C bibliography switch --detach BIB_COMMIT

将 BIB_COMMIT 替换为目标提交 ID,再提交文章仓库中的 bibliography 变更即可。

submodule 处于 detached HEAD 状态是常见情况,适合固定依赖版本。如果要直接在其中编辑并提交 bib 文件,先创建或切换到工作分支,方便后续维护这些提交。

如何恢复文章的历史版本

切换文章提交后,需要同步 submodule 的工作目录:

git checkout ARTICLE_COMMIT
git -c protocol.file.allow=always submodule update --init --recursive

将 ARTICLE_COMMIT 替换为目标文章提交。第二条命令会按照该文章提交记录的依赖版本检出 bib 文件。

离线执行的前提是所需对象已经存在于本地,或者仍能从本地 bib 源仓库取得。Git 无法恢复本地和源仓库中都已丢失的提交。

固定 bib 版本能够解决共享文件变化带来的问题,但完整复现编译还可能依赖 LaTeX 宏包、字体、编译引擎及其他输入文件的版本。

如何与 GitLab 同步

文章仓库可以照常推送,但推送文章仓库不会自动把 bib 仓库的内容包含进去。

如果需要在其他电脑或协作者的环境中使用,通常应当给 bib 仓库也配置一个可访问的 GitLab 地址,再将文章仓库中的 submodule URL 改为该地址。例如:

git submodule set-url bibliography git@gitlab.example.edu:group/bib.git
git add .gitmodules
git commit -m "Use shared bibliography repository URL"

上述地址只是示例,需要替换为实际仓库地址。发布时,应先确保 bib 仓库中被引用的提交已经推送,再推送文章仓库。其他人还需要拥有 bib 仓库的读取权限。

新电脑首次获取项目时,可以执行:

git clone --recurse-submodules ARTICLE_REPO_URL

完成必要的数据获取后,编辑、提交以及切换已经取得的历史版本都可以离线进行。使用本地绝对路径也能工作,但该路径通常无法直接在另一台电脑上使用。

subtree 和符号链接分别适合什么情况

方案对当前需求的影响
submodule文章仓库记录 bib 的具体提交,适合把 bib 作为独立依赖维护;克隆和切换版本时需要处理 submodule
subtreebib 文件进入文章仓库自身的历史,普通克隆即可取得;从独立 bib 仓库导入更新需要额外操作
指向共享文件的符号链接本地编辑方便,但所有文章读取同一个当前文件,不能独立固定依赖版本

如果更重视协作者执行普通 git clone 后就拿到全部源文件,并且可以接受每个文章仓库保存 bib 内容,subtree 也很合适。它可以继续从一个 bib 源仓库导入更新,只是维护方式不同。

如果继续使用符号链接,需要注意 Git 保存的是链接目标路径,提交链接时不会保存目标 bib 文件的内容。切换文章历史版本,也不会自动切换链接所指文件的版本。

对于这个需求,建议先使用 submodule。bib 文件通常不大,每篇文章保留独立工作副本,可以让不同文章同时使用各自需要的版本,也更容易理解和维护。

备注:内容仅供参考。