通过实现在Github Action中将文件推送到另一个仓库中,实现private文档仓库构建的页面自动部署到public仓库中¶
约 2346 个字 • 140 行代码
因为想要构建的网页包含密码,而我又想使用github action来在main分支推送时自动构建页面,所以存储文档的仓库中就需要包含设置密码的 passwords.yml
,因此仓库的属性就需要设置成private(要不然直接翻仓库就能看到密码了😅)。
而免费的github的组织中,private的仓库不能开启github pages,所以一种办法是(文档存储在private仓库中而)把构建的页面放置在另一个public的仓库中(另一种办法就是直接氪金)。又因为我想要只推送一次文档就可以让github action自动部署好(懒惰是人类进步的阶梯),所以就有了这次的记录。
一开始我的想法是,在部署的仓库中,检测文档仓库的推送,然后克隆文档进行构建,
Google 搜索了 how to github action deploy a public repo and get a private repo
得到了stackoverflow上这个帖子
其中 Nato Boram的最高赞回答 提到了比较关键的一个设置,
原文
Since access tokens are bound to an account and have write access to all its private repos, it's a very bad solution.
Instead, use deploy keys.
Deploy keys are simply SSH keys that you can use to clone a repo.
- Create a new SSH key pair on your computer
- Put the public key in the private dependency repo's Deploy keys
- Put the private key in the app repo's Actions secrets
- Delete the keys from your computer
...
翻译(机翻)
由于访问令牌绑定到账户,并且具有对其所有私有仓库的写访问权限,这是一个非常糟糕的解决方案。
而应使用部署密钥。
部署密钥是你可以用来克隆仓库的 SSH 密钥。
- 在你的电脑上创建一个新的 SSH 密钥对。
- 将公钥放入私有依赖仓库的部署密钥中。
- 将私钥放入应用仓库的Actions secrets中。
- 从你的电脑上删除密钥
...
这样一个仓库就对另一个仓库有了读/写的权限。
这时我想到,那我能不能设置文档仓库对部署的仓库有写入的权限,然后在文档仓库中编写github workflow,最后自动构建并推送到部署的仓库中。
于是询问了一下deepseek
对话记录
You:
在一个github组织下,在一个private仓库main分支推送时会触发github action,这个action会对main分支进行构建并发布到gh-pages分支中,我想在这个github action中添加设置,使得它能够在构建之后一并推送到另一个仓库的gh-pages分支中,这要如何实现呢?
DeepSeek:
已深度思考(用时 15 秒)
嗯,用户的问题是想在现有的GitHub Action工作流中添加一个步骤,将构建后的内容推送到另一个仓库的gh-pages分支。我需要先理解用户当前的工作流程,然后找到如何扩展它来实现这个需求。
首先,用户当前的Action应该是在main分支推送时触发,构建项目并发布到同一仓库的gh-pages分支。现在他们需要将同样的内容推送到另一个仓库的gh-pages分支。
根据我之前看到的搜索结果,比如网页78提到使用cpina/github-action-push-to-another-repository这个Action,用户可以在步骤中添加一个使用该Action的步骤。这个Action专门用于将文件推送到另一个仓库,需要提供目标仓库的信息和权限。
然后需要考虑权限问题。推送另一个仓库需要访问令牌。网页1提到使用GITHUB_TOKEN,但这是当前仓库的权限,可能无法访问其他仓库。所以用户需要在目标仓库创建个人访问令牌(PAT),并将其添加到当前仓库的Secrets中。例如,网页65和78中都有类似的例子,使用secrets.GITEE_TOKEN或者API_TOKEN_GITHUB。
接下来是配置步骤。用户需要指定源目录(构建后的目录,比如dist)、目标仓库的用户名、仓库名、目标分支(gh-pages)以及访问令牌。可能还需要设置用户邮箱和名称,以便提交记录正确显示。
另外,网页68的例子展示了如何从多个分支检出代码并合并,但用户的情况可能只需要推送构建后的文件到另一个仓库。因此,可以跳过多分支检出的步骤,直接使用推送Action。
需要注意的潜在问题包括路径是否正确,令牌权限是否足够(需要repo权限),以及是否需要忽略.git目录。例如,网页68中删除了子目录的.git文件夹,避免嵌套仓库的问题,这可能也需要在用户的步骤中处理。
最后,测试工作流是否成功运行,检查目标仓库的gh-pages分支是否有更新,并处理可能出现的错误,比如权限不足或路径错误。
在现有的GitHub Actions工作流中实现跨仓库推送构建结果到另一个仓库的gh-pages
分支,可以通过以下步骤实现:
一、核心实现方案
-
使用跨仓库推送的GitHub Action
推荐使用第三方Actioncpina/github-action-push-to-another-repository
,它专为跨仓库推送设计,可自动处理文件复制和提交。以下是关键配置示例:需将- name: Push to external repo uses: cpina/github-action-push-to-another-repository@v1 env: SSH_PRIVATE_KEY: ${{ secrets.EXTERNAL_REPO_SSH_KEY }} with: source-directory: 'dist' # 构建输出目录 destination-github-username: '目标仓库所属组织或用户' destination-repository-name: '目标仓库名' target-branch: gh-pages commit-message: "Update from source repo"
EXTERNAL_REPO_SSH_KEY
替换为目标仓库的SSH密钥或访问令牌 -
替代方案:手动Git操作
若需更多控制,可通过脚本直接操作Git:此方式需在Secrets中配置目标仓库的访问令牌(需- name: Configure Git for external repo run: | git config --global user.email "actions@github.com" git config --global user.name "GitHub Actions" cd dist git init git remote add external https://${{ secrets.EXTERNAL_TOKEN }}@github.com/目标组织/目标仓库.git git add . git commit -m "Build: $(date)" git push external HEAD:gh-pages --force
repo
权限)
二、权限配置要点
-
访问令牌类型
- 推荐:在目标仓库生成Fine-grained PAT,仅授予
Contents: Read and write
权限,限制作用范围为特定仓库 - 或使用传统Personal Access Token(需
repo
权限),存储到当前仓库的Secrets中(如EXTERNAL_TOKEN
)
- 推荐:在目标仓库生成Fine-grained PAT,仅授予
-
密钥安全性
- 避免明文存储令牌,必须通过GitHub Secrets注入环境变量
- SSH密钥需将私钥存入Secrets,公钥配置到目标仓库的Deploy Keys中
三、完整工作流示例
name: Build and Cross-Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Deploy to current repo
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
- name: Deploy to external repo
uses: cpina/github-action-push-to-another-repository@v1
env:
API_TOKEN_GITHUB: ${{ secrets.EXTERNAL_TOKEN }}
with:
source-directory: 'dist'
destination-github-username: '目标组织'
destination-repository-name: '目标仓库'
target-branch: gh-pages
user-email: "actions@github.com"
四、常见问题处理
-
路径冲突
- 若目标仓库已有内容,建议添加
clean: true
参数清空目标分支 - 若需保留历史,可先克隆目标仓库再合并更新
- 若目标仓库已有内容,建议添加
-
嵌套.git目录
构建目录若包含.git文件夹,需删除避免冲突: -
触发循环
添加路径过滤,避免外部仓库的推送再次触发当前工作流:
五、验证与调试
-
查看Actions日志
检查步骤输出是否显示成功提交到目标仓库 -
目标仓库验证
访问https://目标组织.github.io/目标仓库/
查看页面是否更新 -
分支保护设置
若目标仓库启用分支保护规则,需在Settings中允许Actions提交到gh-pages
分支
通过上述配置,可实现自动化跨仓库部署,适用于需要同步多个展示环境或分离源码与产物的场景。
deepseek的回复中提到了 cpina/github-action-push-to-another-repository 这个action,于是搜索了它对应的仓库去查看它的用法。
See the extensive documentation in https://cpina.github.io/push-to-another-repository-docs/ (includes examples, FAQ, troubleshooting, etc.).
GitHub repository of the documentation: https://github.com/cpina/push-to-another-repository-docs
于是去查看说明文档的网页,看到有 Example setup
,
Example setup
示例设置This example shows both setup methods. This is part of a GitHub workflow Action, for example, in your repository:
.github/workflow/ci.yml
.
本示例展示了两种设置方法。这是 GitHub 工作流动作的一部分,例如,在你的仓库中:.github/workflow/ci.yml
。Note that only one of the lines,
SSH_DEPLOY_KEY
orAPI_TOKEN_GITHUB
, are needed according to the chosen setup that is being used.
注意,根据所选择的设置,只需要一行,即SSH_DEPLOY_KEY
或API_TOKEN_GITHUB
之一。name: CI on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest container: pandoc/latex # "ubuntu" is a more generic container # using "pandoc/latex" because of dependencies # used in the specific "build.sh" steps: - uses: actions/checkout@v2 - name: creates output run: sh ./build.sh # some command from your repository that creates # output to "source-directory" ("output" in the example) - name: Pushes to another repository uses: cpina/github-action-push-to-another-repository@main env: SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }} API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} with: source-directory: 'output' destination-github-username: 'cpina' destination-repository-name: 'pandoc-test-output' user-email: carles3@pina.cat target-branch: main
然后意识到刚才那个stackoverflow的帖子的最高赞回答提到在private仓库中设置的 PRIVATE_SSH_KEY
就对应这里的 SSH_DEPLOY_KEY
,于是我开始按照那个回答中的步骤进行设置。
类比电脑本地仓库(ssh)推送到github远程仓库,需要在github账户中添加公钥,而私钥留在本地,所以我断定private的文档仓库的 SSH_DEPLOY_KEY
设置的是私钥,而public的部署仓库的部署密钥中设置的是公钥。
但设置过程中,可能是因为我github账户已经设置了ssh key,使用的是 ed25519
的算法生成的,在部署的仓库中尝试给部署密钥添加这个(同一个)ssh key时,显示
Failure
Key is already in use
于是使用了GitHub 文档中提到的另一个方法(换用rsa算法)来生成ssh密钥对
设置好之后,结合github-action-push-to-another-repository的说明文档中的示例和我之前的编写的部署的yaml文件,最后得到
不过由于我一开始只是创建了一个空白的vision-docs-site的仓库,所以在github action在推送时发生了错误
Failure
[+] Action start
[+] Using SSH_DEPLOY_KEY
[+] Git version
git version 2.47.2
[+] Enable git lfs
Git LFS initialized.
[+] Cloning destination git repository vision-docs-site
Cloning into '/tmp/tmp.kGDePD'...
fatal: Remote branch gh-pages not found in upstream origin
Error: Could not clone the destination repository. Command:
Error: git clone --single-branch --branch gh-pages
git@github.com:NPU-Home/vision-docs-site.git /tmp/tmp.kGDePD
Error: (Note that if they exist USER_NAME and API_TOKEN is redacted by GitHub)
Error: Please verify that the target repository exist AND that it contains
the destination branch name, and is accesible by the API_TOKEN_GITHUB OR
SSH_DEPLOY_KEY
最后在vision-docs-site仓库中创建了gh-pages分支之后,再 Re-run all jobs 就能成功推送了😄
创建日期: 2025-03-29