神觉晓

@shenjuexiao

神觉晓

Gmeek Deploy Another Repo

Gmeek 部署其他仓库

📦 原有: Gmeek.yml

原有 GitHub Actions ,通过 actions/upload-pages-artifact@v3actions/deploy-pages@v4 自动化部署到本仓库的虚拟机上(注:不知这样理解是否正确)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
name: build Gmeek

on:
workflow_dispatch:
issues:
types: [opened, edited]
schedule:
- cron: \"0 16 * * *\"

jobs:
build:
name: Generate blog
runs-on: ubuntu-24.04
if: ${{ github.event.repository.owner.id == github.event.sender.id || github.event_name == 'schedule' }}
permissions: write-all
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Pages
id: pages
uses: actions/configure-pages@v4

- name: Get config.json
run: |
echo \"====== check config.josn file ======\"
cat config.json
echo \"====== check config.josn end ======\"
sudo apt-get install jq

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.8

- name: Clone source code
run: |
GMEEK_VERSION=$(jq -r \".GMEEK_VERSION\" config.json)
git clone https://github.com/Meekdai/Gmeek.git /opt/Gmeek;
cd /opt/Gmeek/
lastTag=$(git describe --tags `git rev-list --tags --max-count=1`)
if [ $GMEEK_VERSION == 'last' ]; then git checkout $lastTag; else git checkout $GMEEK_VERSION; fi;

- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r /opt/Gmeek/requirements.txt

- name: Generate new html
run: |
cp -r ./* /opt/Gmeek/
cd /opt/Gmeek/
python Gmeek.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} --issue_number '${{ github.event.issue.number }}'
cp -a /opt/Gmeek/docs ${{ github.workspace }}
cp -a /opt/Gmeek/backup ${{ github.workspace }}
cp /opt/Gmeek/blogBase.json ${{ github.workspace }}

- name: update html
run: |
git config --local user.email \"$(jq -r \".email\" config.json)\"
git config --local user.name \"${{ github.repository_owner }}\"
git add .
git commit -a -m '🎉auto update by Gmeek action' || echo \"nothing to commit\"
git push || echo \"nothing to push\"
sleep 3

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: 'docs/.'

deploy:
name: Deploy blog
runs-on: ubuntu-24.04
needs: build
permissions:
contents: write
pages: write
id-token: write
concurrency:
group: \"pages\"
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

🔧 .yml 修改需求

源仓库生成相关文件后,将静态页面 ./docs 下的文件推送到博客仓库分支 gh-pages 上,即网站部署在分支。

  • 源仓库: shenjuexiao/gmeek-source
  • 博客仓库: shenjuexiao/gmeek-docs
  • 工作流 Deploy 增加 docs 下静态页面部署到博客仓库 gh-pages 分支
  • 使用 peaceiris/actions-gh-pages
  • 跨仓库使用 token:${{ secrets.GMEEK_DOCS }}

❌ Error: HttpError: Not Found

Gmeek Deploy Setup Pages

注释掉本地的部署

1
2
3
4
# 不需要配置 GitHub Pages
# - name: Setup Pages
# id: pages
# uses: actions/configure-pages@v4
1
2
3
4
5
6
7
# 去掉源仓库的部署
# actions/upload-pages-artifact@v3 是专门为 GitHub Pages 设计的
# 创建特殊的 artifact,只能被 actions/deploy-pages@v4 使用
# - name: Upload artifact
# uses: actions/upload-pages-artifact@v3
# with:
# path: 'docs/.'
1
2
3
4
# 去掉源仓库的部署
# - name: Deploy to GitHub Pages
# id: deployment
# uses: actions/deploy-pages@v4

🔑 Error: Action failed with "not found deploy key for tokens"

Gmeek Deploy docs to

源仓库需要设置 token

  • 创建 GitHub 个人访问令牌 PAT Personal access tokens (classic)
    GitHub 头像,Settings -> Developer settings -> Personal access tokens -> Tokens (classic)
    新建 Token,勾选权限:repo(全部仓库读写权限)。
    复制生成的 Token(仅展示一次,丢失需重建)。
  • 仓库配置 Repository secrets
    仓库首页, Settings -> Secrets and variables -> Actions -> New repository secret
    Name:GH_TOKEN。
    Value:粘贴上面的 PAT。

✅ 修改后 gmeek-docs.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
name: build Gmeek

on:
workflow_dispatch:
issues:
types: [opened, edited]
# schedule:
# - cron: \"0 16 * * *\"

jobs:
build:
name: Generate blog
runs-on: ubuntu-24.04
if: ${{ github.event.repository.owner.id == github.event.sender.id || github.event_name == 'schedule' }}
permissions: write-all
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Get config.json
run: |
echo \"====== check config.josn file ======\"
cat config.json
echo \"====== check config.josn end ======\"
sudo apt-get install jq

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.8

- name: Clone source code
run: |
GMEEK_VERSION=$(jq -r \".GMEEK_VERSION\" config.json)
git clone https://github.com/Meekdai/Gmeek.git /opt/Gmeek;
cd /opt/Gmeek/
lastTag=$(git describe --tags `git rev-list --tags --max-count=1`)
if [ $GMEEK_VERSION == 'last' ]; then git checkout $lastTag; else git checkout $GMEEK_VERSION; fi;

- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r /opt/Gmeek/requirements.txt

- name: Generate new html
run: |
cp -r ./* /opt/Gmeek/
cd /opt/Gmeek/
python Gmeek.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} --issue_number '${{ github.event.issue.number }}'
cp -a /opt/Gmeek/docs ${{ github.workspace }}
cp -a /opt/Gmeek/backup ${{ github.workspace }}
cp /opt/Gmeek/blogBase.json ${{ github.workspace }}

- name: update html
run: |
git config --local user.email \"$(jq -r \".email\" config.json)\"
git config --local user.name \"${{ github.repository_owner }}\"
git add .
git commit -a -m '🎉auto update by Gmeek action' || echo \"nothing to commit\"
git push || echo \"nothing to push\"
sleep 3

# 生成 HTML 后立即将 docs 文件夹上传为 artifact
- name: Upload docs artifact
uses: actions/upload-artifact@v4
with:
name: docs
path: ${{ github.workspace }}/docs
# 设置保留 1 天,节省存储空间
retention-days: 1

deploy:
name: Deploy blog
runs-on: ubuntu-24.04
needs: build
permissions:
contents: write
pages: write
id-token: write
concurrency:
group: \"pages\"
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
# 先下载 build job 上传的 docs artifact,下载到 ./docs 目录
- name: Download docs artifact
uses: actions/download-artifact@v4
with:
name: docs
path: ./docs

# 新增:部署 docs 到博客仓库的gh-pages分支
- name: Deploy docs to gmeek-docs gh-pages
uses: peaceiris/actions-gh-pages@v3
with:
personal_token: ${{ secrets.GMEEK_DOCS }}
external_repository: shenjuexiao/gmeek-docs
publish_branch: gh-pages
publish_dir: ./docs
commit_message: '🚀 Deploy static pages to gh-pages'
user_name: 'github-actions[bot]'
user_email: 'github-actions[bot]@users.noreply.github.com'
keep_files: false
force_orphan: false

GitHub CNAME

GitHub CNAME 的作用

内容来源

GitHub仓库里的CNAME文件,核心作用是告诉GitHub Pages服务器,当用户通过你的自定义域名(比如 www.example.com)访问时,应该展示哪个仓库的网站内容

你可以把它理解为在GitHub内部为你的域名和特定仓库建立的一个“认领”和“关联”关系。它需要在你的域名解析服务商(如阿里云、Cloudflare)设置的DNS解析配合下才能正常工作。

⚙️ 如何工作

当用户在浏览器输入你的自定义域名(如 www.example.com)并访问时,流程如下:

  1. DNS解析:用户的请求首先会去DNS服务器查询www.example.com指向哪里。你需要在DNS服务商那里添加一条 CNAME记录,将 www.example.com 指向 你的用户名.github.io。这一步把域名指向了GitHub的服务器。
  2. 请求到达GitHub:请求到达GitHub的服务器后,服务器需要知道这个请求是给哪个仓库的。
  3. 读取CNAME文件:此时,GitHub会检查所有启用了Pages的仓库,寻找根目录下名为CNAME必须大写)的文件。
  4. 匹配与响应:当GitHub在你的仓库里找到的CNAME文件内容(例如www.example.com),与用户请求的域名完全匹配时,它就知道要把这个仓库的网站内容返回给用户了。

🌐 仓库和服务商 CNAME 比较

两者的关系:分工明确的“钥匙”与“路标”。这两者缺一不可,它们共同完成从“自定义域名”到“具体 GitHub 仓库”的映射。

组成部分 作用概括 配置位置 关键点
仓库 CNAME 文件 “钥匙”:授权并告诉 GitHub,哪个域名可以访问这个仓库 仓库根目录下的 CNAME 文件 内容必须与 DNS 记录的子域名一致,且只能有一个域名
DNS CNAME 记录 “路标”:将互联网流量从你的域名指向 GitHub 服务器 域名注册商/DNS 服务商的管理后台 通常用于 www 子域名,指向<用户名>.github.io

📌 重要补充

  • 安全与唯一性:这个文件也是一种安全机制,确保只有你(仓库所有者)能决定哪个域名可以访问你的网站。如果一个域名已经被某个仓库的CNAME文件“占用”了,其他仓库就无法再使用该域名,除非你将其删除。
  • 避免使用通配符:切记不要在你的DNS服务商处为GitHub Pages设置通配符记录(如 *.example.com)。因为任何GitHub用户都可以在自己的仓库里创建一个指向你任意子域名的CNAME文件,从而可能“劫持”你的子域名来托管他们的内容。
  • 多域名支持:一个CNAME文件中只能包含一个域名。如果你想把多个域名都指向同一个网站,可以通过你的DNS服务商设置URL转发或使用其他DNS记录来实现。
  • 静态站点生成器注意事项:如果你使用Hexo、Hugo等静态站点生成器,建议将CNAME文件放在项目的源文件夹(如source目录)下。这样每次部署时,它就会被自动复制到生成的public文件夹并推送到GitHub,避免每次部署后CNAME文件丢失的问题。
  • Apex 根域名:需要注意,对于 example.com 这样的根域名(也叫 Apex 域),由于 DNS 规范限制,不能使用 CNAME 记录。你需要配置 A 记录,将其指向 GitHub 的固定 IP 地址(185.199.108.153 等四个 IP),才能实现根域名的访问。不过,这并不影响在仓库中依然需要一个内容为 example.com 的 CNAME 文件来完成授权。

Astro GitHub Actions

Astro 安装及 GitHub Actions 自动部署

内容来源

通过 CLI 向导安装

docs.astro.build/zh-cn/install-and-setup/

我选择的是 Astro Use blog template,也可以选择其他的选项,使用模板能快速建立页面。

Astro Use blog template

1
2
# 使用 npm 创建一个新项目
npm create astro@latest

1
2
# 使用 pnpm 创建一个新项目
pnpm create astro@latest

1
2
# 使用 yarn 创建一个新项目
yarn create astro

npm create astro@latest

目录和文件

docs.astro.build/zh-cn/basics/project-structure/

Astro 采用一套约定俗成的文件夹布局来管理项目。每个 Astro 项目的根目录下都应该包括以下目录和文件:

  • src/* - 你的项目源代码(组件、页面、样式、图片等)。
  • public/* - 你的非代码、未处理的资源(字体、图标等)。
  • package.json - 项目清单。
  • astro.config.mjs - Astro 配置文件(推荐)。
  • tsconfig.json - TypeScript 配置文件(推荐)。

启动 Astro 开发服务器

docs.astro.build/zh-cn/develop-and-build/

Astro 自带了一个内置的开发服务器,它包含了项目开发所需的一切。astro dev CLI 命令将启动本地开发服务器,让你第一次看到你的新网站。

每个起始模板都预配置了一个脚本,该脚本将为你运行 astro dev。在进入你的项目目录后,使用你喜欢的包管理器运行此命令并启动 Astro 开发服务器。

1
npm run dev

1
pnpm run dev

1
yarn run dev

部署你的 Astro 站点至 GitHub Pages

docs.astro.build/zh-cn/guides/deploy/github/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
name: Deploy to GitHub Pages

on:
# 每次推送到 `main` 分支时触发这个“工作流程”
# 如果你使用了别的分支名,请按需将 `main` 替换成你的分支名
push:
branches: [ main ]
# 允许你在 GitHub 上的 Actions 标签中手动触发此“工作流程”
workflow_dispatch:

# 允许 job 克隆 repo 并创建一个 page deployment

```yaml
permissions:
contents: read
pages: write
id-token: write

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout your repository using git
uses: actions/checkout@v5
- name: Install, build, and upload your site
uses: withastro/action@v5
# with:
# path: . # 存储库中 Astro 项目的根位置。(可选)
# node-version: 20 # 用于构建站点的特定 Node.js 版本,默认为 20。(可选)
# package-manager: pnpm@latest # 应使用哪个 Node.js 包管理器来安装依赖项和构建站点。会根据存储库中的 lockfile 自动检测。(可选)
# build-cmd: pnpm run build # 用于构建你的网站的命令。默认运行软件包的构建脚本或任务。(可选)
# env:
# PUBLIC_POKEAPI: 'https://pokeapi.co/api/v2' # 对变量值使用单引号。(可选)

deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

Error: Failed to create deployment (status: 404)

Astro Deploy to GitHub Pages

这个错误表明 GitHub Pages 部署失败,主要原因是 GitHub Pages 没有在仓库设置中启用。错误信息明确指出:

Ensure GitHub Pages has been enabled: https://github.com/shenjuexiao/astro/settings/pages

npm vs npx

npm 与 npx 区别

内容来源

简单说明

npmnpxNode.js 生态里两个核心但职责不同的工具,可以用一句话来区分它们:

npm 是“包管理器”,负责安装、管理依赖;而 npx 是“包执行器”,负责运行命令,无需显式安装

表格比较

特性 npm (Node Package Manager) npx (Node Package Execute)
核心职责 管理项目的依赖包,比如安装、卸载、更新、发布包 执行某个 Node.js 包提供的命令
是否需要安装 需要。包会被下载并保存到 node_modules 或全局目录 通常不需要。它会临时下载并执行,用完即走,不污染环境
典型场景 为项目安装核心依赖(如 npm install react
运行 package.json 中定义的脚本(如 npm run build
运行一次性的脚手架工具(如 npx create-react-app my-app
快速测试不同版本的包(如 npx webpack@4.44.1 -v
执行本地包 需要通过 ./node_modules/.bin/ 路径或 npm run 命令间接运行 可以直接运行,它会自动在 node_modules/.bin/ 中查找命令

除了用法上的不同,npx 还有一个非常便利的特性:它可以临时下载并运行一个远程的 npm 包,这在测试新工具或运行一次性脚本时能帮你节省不少时间。

💡 如何选择?

一个很实用的场景是:创建 React 项目时,会先全局安装 create-react-app,再用它生成项目。有了 npx,可以直接 npx create-react-app my-app,不用全局安装,每次用的还都是最新版,非常方便。

一句话总结就是

  • 需要一个包长期使用(比如项目依赖)→ 用 npm install
  • 只是想临时跑一下某个命令或工具 → 用 npx

GitHub raw vs cdn

GitHub 图片加速对比

内容来源

🔍比较图片引用

raw.githubusercontent.comcdn.jsdelivr.net/gh

简单来说,raw.githubusercontent.com 是图片在 GitHub 上的源服务器地址,而 cdn.jsdelivr.net/gh 则是一个免费的 CDN 加速服务,它的核心作用就是为前者"提速"。

下面是它们在几个关键维度上的直接对比:

对比维度 raw.githubusercontent.com (源站) cdn.jsdelivr.net/gh (CDN)
核心作用 直接访问 GitHub 服务器上的原始文件 通过全球 CDN 节点缓存并分发文件,进行加速
访问速度 通常较慢,尤其在中国大陆地区,延迟高,加载不稳定 显著更快,利用全球边缘节点就近响应,可大幅缩短加载时间
稳定性与限制 存在请求频率限制 (Rate Limit),高并发或大量图片时可能返回 HTTP 429 错误,导致图片无法加载 通常无严格的请求限制,但有单文件 50MB 的大小限制,且仅支持公开仓库
缓存机制 缓存策略较弱,重复访问可能仍需重新下载 具备强大的缓存机制(默认缓存24小时或更久),重复访问直接从 CDN 节点读取,速度极快
URL 格式示例 https://raw.githubusercontent.com/用户名/仓库名/分支名/图片路径.png https://cdn.jsdelivr.net/gh/用户名/仓库名@分支名或版本号/图片路径.png

⚠️ 重要的潜在问题与建议

虽然 jsDelivr 优势明显,但在国内使用时需要留意一个已知风险:

国内 DNS 污染问题jsDelivr 的官方域名 cdn.jsdelivr.net 在国内曾因DNS污染导致访问失败。如果你遇到这种情况,可以考虑使用它未被污染的备用域名,例如 fastly.jsdelivr.netgcore.jsdelivr.net 作为替代方案。

💎 总结与选择建议

  • 对于个人项目、博客、官网等公开场景:强烈建议使用 cdn.jsdelivr.net/gh**。它能带来质的飞跃,让图片"秒开"不再困难,综合体验完胜直连源站。
  • raw.githubusercontent.com 的适用场景**:主要用于在 GitHub 页面上直接预览文件内容,或在你需要从服务器后台程序以编程方式获取文件原始内容时使用。

Bing Wallpaper API

必应壁纸每日一图 API

内容来源

获取必应每日一图,主要有官方接口第三方封装接口两种方式,按需选择即可。

官方 API:最直接的数据源

Bing 官方提供了获取每日壁纸元数据的接口,这是最可靠的方式。

接口地址

1
https://cn.bing.com/HPImageArchive.aspx

核心参数说明

参数 说明 可选值示例
format 必填。指定返回的数据格式 js (JSON格式) 或 xml
idx 必填。图片的日期偏移量。0代表今天,1代表昨天,依此类推,最多可获取前16天的图片 0, 1, 2
n 必填。返回的图片数量,最大为8 1, 3, 8
mkt 地区/语言参数,影响图片说明和版权信息的语言 zh-CN (中文), en-US (英文)
uhd 是否请求4K超高清图片。1表示请求 1

请求示例和返回数据

  • 获取今天的图片信息(JSON 格式):
    https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN
  • 返回示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    \"images\": [
    {
    \"startdate\": \"20250105\",
    \"url\": \"/th?id=OHR.RavennaBasilica_ZH-CN1406474730_UHD.jpg\",
    \"copyright\": \"被水淹没的地下室,圣弗朗西斯大教堂,拉文纳,意大利 (© Andrea Pucci/Getty Images)\"
    }
    ]
    }

你需要在url前拼接上Bing的域名 https://cn.bing.com 才能得到完整图片地址。

第三方封装接口:免去解析的麻烦

如果你不想自己处理数据,可以直接使用第三方封装好的接口,它们通常会直接返回图片或更简洁的JSON数据。

bing.biturl.top 功能全面的替代API

这个接口将官方数据封装得很简洁,支持指定分辨率和直接重定向到图片,非常方便。

  • 获取今日4K壁纸的JSON数据
    https://bing.biturl.top/?resolution=UHD&format=json&index=0&mkt=zh-CN
  • 直接获取今日壁纸图片(重定向)
    https://bing.biturl.top/?resolution=1920&format=image
  • 参数说明
    resolution支持UHD(4K)、19201366等;index支持0(今天)、1(昨天)或random(随机)。

npanuhin/Bing-Wallpaper-Archive 强大的历史归档项目

如果你想获取更久远的壁纸,这个项目维护了完整的图片归档。它按国家和语言组织数据,并且可以直接通过日期拼接图片地址,非常实用。

  • 获取归档数据*
    https://bing.npanuhin.me/CN-zh.json

  • 直接获取图片
    https://bing.npanuhin.me/CN/zh/2024-01-16.jpg (替换日期即可)

其他可用API

根据搜索结果,还有一些可用的API服务,如 https://api.1314.cool/bingimghttps://api.sunweihu.com/api/bing1/api.php,使用时请注意其稳定性。

快速上手:JavaScript 示例

1
2
3
4
5
6
7
8
9
10
11
// 使用官方API获取今日壁纸URL并显示
fetch('https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN')
.then(response => response.json())
.then(data => {
// 从返回数据中提取图片相对路径
const imageUrl = data.images[0].url;
// 拼接完整URL
const fullImageUrl = 'https://cn.bing.com' + imageUrl;
console.log('今日壁纸:', fullImageUrl);
// 可以将该URL用于设置背景图片等
});

Will not delete all non-push URLs

Git 远程 URL 修改

问题

1
2
PS D:\\Git\\shenjuexiao> git remote set-url --delete gitee git@gitee.com:shenjuexiao/shenjuexiao.git
fatal: Will not delete all non-push URLs

这个错误是因为你试图删除远程仓库 gitee唯一 URL,Git 不允许这样做——每个远程仓库至少需要保留一个 URL。

解决方案

方案一:先添加新 URL,再删除旧的

1
2
3
4
5
# 先添加一个新的 URL
git remote set-url --add gitee git@gitee.com:new-repo.git

# 然后再删除旧的 URL
git remote set-url --delete gitee git@gitee.com:shenjuexiao/shenjuexiao.git

方案二:直接修改 URL(推荐)

1
2
# 直接替换整个 URL,而不是删除
git remote set-url gitee git@gitee.com:new-repo.git

方案三:删除整个远程仓库再重新添加

1
2
3
4
5
# 删除整个远程仓库
git remote remove gitee

# 重新添加
git remote add gitee git@gitee.com:new-repo.git

方案四:查看当前所有 URL,确认情况

1
2
# 查看 gitee 远程仓库的所有 URL
git remote get-url --all gitee

最常见的使用场景

如果你是想修改远程仓库地址,直接用方案二最简单:

1
git remote set-url gitee git@gitee.com:新的仓库地址.git

如果你是想添加多个推送地址(同时推送到多个仓库),用方案一。

重命名远程仓库

1
git remote rename github origin

这个命令会:

  • 将远程仓库 github 重命名为 origin
  • 保留所有原有的 URL 和配置
  • 更新所有本地跟踪分支(如 github/mainorigin/main

验证是否成功

1
2
# 查看所有远程仓库
git remote -v

你应该能看到类似这样的输出:

1
2
origin  git@github.com:你的用户名/仓库名.git (fetch)
origin git@github.com:你的用户名/仓库名.git (push)

注意事项

  • 如果 origin 已经存在,这个命令会报错。你需要先删除或重命名现有的 origin
  • 如果你的 origin 已经指向其他仓库,可以先确认一下:
1
2
# 查看当前 origin 指向哪里
git remote get-url origin

如果 origin 已经存在且不是你想用的,可以先删除它:

1
2
git remote remove origin
git remote rename github origin

执行后记得检查一下 git remote -v 确认结果正确。

Gitee remote error hook declined

问题

-同时推送到 GitHub 和 Gitee 两个仓库:

基本设置

1
2
git remote set-url origin git@github.com:shenjuexiao/shenjuexiao.git
git remote set-url --add origin git@gitee.com:shenjuexiao/shenjuexiao.git

查看配置

1
2
3
4
git remote -v
origin git@github.com:shenjuexiao/shenjuexiao.git (fetch)
origin git@github.com:shenjuexiao/shenjuexiao.git (push)
origin git@gitee.com:shenjuexiao/shenjuexiao.git (push)

推送文件

1
2
3
4
5
6
git add .
git commit -m \"20260722\"
git push origin main
origin git@github.com:shenjuexiao/shenjuexiao.git (fetch)
origin git@github.com:shenjuexiao/shenjuexiao.git (push)
origin git@gitee.com:shenjuexiao/shenjuexiao.git (push)

返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Everything up-to-date
Enumerating objects: 68, done.
Counting objects: 100% (68/68), done.
Delta compression using up to 16 threads
Compressing objects: 100% (67/67), done.
Writing objects: 100% (68/68), 5.68 MiB | 5.83 MiB/s, done.
Total 68 (delta 21), reused 0 (delta 0)
remote: Powered by GITEE.COM [1.1.23]
remote: Set trace flag b6498f96
remote: Push will publish a hidden email, make email public or abandon related commits
remote: error: hook declined to update refs/heads/main
To gitee.com:shenjuexiao/shenjuexiao.git
! [remote rejected] main -> main (hook declined)
error: failed to push some refs to 'git@gitee.com:shenjuexiao/shenjuexiao.git'

这个错误是 Gitee 服务端的 pre-receive hook(预接收钩子) 拒绝了你的推送。hook declined 表示服务端的自定义检查脚本未通过。

Gitee remote error hook declined

常见原因及解决方案

1. 提交信息不符合规范(最常见)

Gitee 可能要求提交信息符合某种格式(如包含 Issue ID、特定前缀等)。

解决方案:

1
2
3
4
5
6
7
8
# 查看最后一次提交信息
git log -1

# 修改最后一次提交信息
git commit --amend -m \"新的提交信息\"

# 强制推送(注意:如果多人协作需谨慎)
git push -f origin main

2. 邮箱/用户信息未公开

错误信息中提到 "Push will publish a hidden email, make email public or abandon related commits",这说明你的提交中使用了 Gitee 的私有邮箱。

解决方案:

  • 在 Gitee 网页端设置中,将邮箱设置为公开
  • 或者修改本地 Git 配置,使用提交邮箱(gitee.com -> 设置 -> 邮箱设置
1
2
3
git config user.email \"你的真实邮箱@example.com\"
# 然后修改最后一次提交的作者信息
git commit --amend --reset-author

3. 推送了敏感文件或大文件

Gitee 可能限制了文件大小或禁止推送某些类型的文件。

解决方案:

  • 检查是否有超过 100MB 的文件
  • 使用 .gitignore 排除不必要的文件

4. 分支保护规则

main 分支可能设置了保护规则,不允许直接推送。

解决方案:

  • 通过 Pull Request/Merge Request 方式合并
  • 或者联系仓库管理员修改保护规则

快速排查步骤

  1. 查看详细错误信息:
1
GIT_CURL_VERBOSE=1 git push origin main
  1. 检查 Gitee 仓库设置:

    • 进入仓库 → 管理 → 提交信息规范
    • 查看是否有强制要求
  2. 尝试使用 –no-verify 跳过(如果允许):

1
git push --no-verify origin main

git push GitHub + Gitee

同步推送 GitHub 和 Gitee

内容来源

将代码同时推送到 GitHub 和 Gitee,主要有两种方案。你可以根据自己的习惯,选择 Git 原生命令,或使用更自动化的工具。

方案一:使用 Git 原生命令(推荐)

这是最基础和灵活的方式,只需几条命令配置好一个“聚合”的远程仓库,之后一条git push命令就能同时推送到两个平台。

核心原理:给本地的origin(或任意名字)远程仓库设置多个推送(push)URL。这样,当执行git push origin时,Git 会依次向这些 URL 推送代码。

配置步骤

  1. 进入项目目录,并查看当前远程仓库
1
2
cd your-project
git remote -v
  1. 添加两个平台的仓库地址作为推送目标

假设你的 Gitee 仓库地址是 https://gitee.com/你的用户名/项目名.git,GitHub 仓库地址是 https://github.com/你的用户名/项目名.git

首先,将 Gitee 的地址设为 origin 的主要推送地址(如果已有origin,这一步会覆盖它):

1
git remote set-url --push origin https://gitee.com/你的用户名/项目名.git

然后,将 GitHub 的地址添加为 origin额外推送地址:

1
git remote set-url --add --push origin https://github.com/你的用户名/项目名.git

实际上,如果不写 --push ,Git 也会默认只添加 (push) ,即以下的命令效果相当:

1
git remote set-url --add origin https://github.com/你的用户名/项目名.git
  1. 验证配置

再次运行 git remote -v,你会看到 origin 有了两个 (push) 地址,但 (fetch) 仍只指向 Gitee。

1
2
3
origin  https://gitee.com/你的用户名/项目名.git (fetch)
origin https://gitee.com/你的用户名/项目名.git (push)
origin https://github.com/你的用户名/项目名.git (push)
  1. 日常使用
  • 推送:执行 git push origin main(或你的主分支名),代码就会同时推送到 Gitee 和 GitHub。

  • 拉取git pull 默认只会从 (fetch) 指向的 Gitee 拉取更新,避免从多个源拉取可能导致的混乱。

注意:这种方法的一个小缺点是,如果其中一个仓库推送失败(比如网络问题),整个推送操作会报错,需要你根据提示处理。

方案二:使用第三方工具自动化

如果你希望有更丰富的功能,比如一键提交并推送、全量同步所有分支和标签,可以考虑使用现成的工具。

工具名称 安装方式 特点
git-multi-sync-tool npm install -g git-multi-sync-tool 基于文本配置文件管理多个仓库,支持智能推送策略、提交后自动推送等功能。
gtl GitHub Releases 下载 提供一键初始化和推送功能,通过配置文件管理多个远程仓库。
mgit-push npm install -g mgit-push 功能更简洁,专注于一键推送到 GitHub、Gitee 等多个平台

git-multi-sync-tool 为例,使用流程大致如下:

  1. 安装:npm install -g git-multi-sync-tool
  2. 在项目中初始化配置:git-sync init
  3. 编辑生成的 .git-remotes.txt 文件,把 GitHub 和 Gitee 的仓库地址分别写入一行。
  4. 执行 git-sync setup 设置远程仓库。
  5. 之后就可以用 git-sync commit \"你的提交信息\" -p 来完成“提交并一键推送到所有仓库”了。

对于大部分开发者来说,方案一(Git 原生命令)已经足够好用,它不依赖额外工具,配置清晰明了。如果你需要管理多个不同项目,或者需要更复杂的同步策略,可以尝试方案二。

NPM packages not found

内容来源

NPM packages not found

NPM packages not found. Please confirm npm packages which need to build are belong to miniprogramRoot directory. Or you may edit project.config.json’s packNpmManually and packNpmRelationList
appid: wx429151859caeb046
openid: o6zAJsws4oaOjHasDK8qBirpUw8Q
ideVersion: 2.01.2510290
osType: win32-x64

开发者工具找不到需要构建的 npm 包。

微信web开发者工具:wechat_devtools_2.01.2510290_win32_x64.exe

IDE 版本(2.01.2510290),这套新版的配置方式确实需要特别注意。

🎯根本原因

project.config.json 中可能同时存在 miniprogramRoot 配置,而 packNpmRelationList 中的路径没有与之匹配,导致工具找不到 node_modules

##✅ 解决方案(三步走)

第一步:确认项目结构

典型的微信小程序项目结构:

1
2
3
4
5
6
你的项目文件夹/
├── miniprogram/ ← 小程序代码(app.json, pages/ 等)
├── node_modules/ ← npm 包(安装后自动生成)
├── package.json
├── project.config.json
└── ...

如果 miniprogram/ 存在,说明 miniprogramRoot 已经指向了 miniprogram 文件夹。

第二步:修改 project.config.json(关键)

project.config.json 中,按以下方式配置,注意 miniprogramNpmDistDir 的值要根据你的实际 miniprogramRoot 来调整。

1
2
3
4
5
6
7
8
9
10
11
12
13
{
// 假设你的代码在 miniprogram 文件夹
\"miniprogramRoot\": \"miniprogram/\",
\"setting\": {
\"packNpmManually\": true,
\"packNpmRelationList\": [
{
\"packageJsonPath\": \"./package.json\",
\"miniprogramNpmDistDir\": \"./miniprogram/\"
}
]
}
}

关键点说明:

字段 含义
miniprogramRoot "miniprogram/" 小程序代码文件夹
packageJsonPath "./package.json" package.json 在项目根目录
miniprogramNpmDistDir "./miniprogram/" 构建后的 miniprogram_npm 在 miniprogram/ 下面,小程序能引用
💡 如果你的小程序代码直接在根目录(没有 miniprogram/ 文件夹),那么 miniprogramRoot 应该是 "./",miniprogramNpmDistDir 也设为 "./" 即可。

第三步:重新构建

保存 project.config.json 文件。

点击微信开发者工具菜单栏:工具 -> 构建 npm

等待构建完成,项目根目录(或 miniprogram/ 下)会出现 miniprogram_npm 文件夹。

🔧 “杀手锏”

如果还是报错,试试这个“杀手锏”。

有些情况下,开发者工具缓存了旧配置,导致新配置不生效。可以这样做:

完全关闭微信开发者工具。

手动删除项目下的 miniprogram_npm 文件夹(如果有)。

重新打开开发者工具,先不要点击构建 npm

先点击菜单栏 项目 -> 重新打开此项目,让工具重新加载所有配置。

然后再点击 工具 -> 构建 npm

修改后的 project.config.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
{
\"miniprogramRoot\": \"miniprogram/\",
\"cloudfunctionRoot\": \"cloudfunctions/\",
\"setting\": {
\"urlCheck\": true,
\"es6\": true,
\"enhance\": true,
\"postcss\": true,
\"preloadBackgroundData\": false,
\"minified\": true,
\"newFeature\": true,
\"coverView\": true,
\"nodeModules\": false,
\"autoAudits\": false,
\"showShadowRootInWxmlPanel\": true,
\"scopeDataCheck\": false,
\"uglifyFileName\": false,
\"checkInvalidKey\": true,
\"checkSiteMap\": true,
\"uploadWithSourceMap\": true,
\"compileHotReLoad\": false,
\"useMultiFrameRuntime\": true,
\"useApiHook\": true,
\"useApiHostProcess\": true,
\"babelSetting\": {
\"ignore\": [],
\"disablePlugins\": [],
\"outputPath\": \"\"
},
\"enableEngineNative\": false,
\"useIsolateContext\": true,
\"useCompilerModule\": true,
\"userConfirmedUseCompilerModuleSwitch\": false,
\"userConfirmedBundleSwitch\": false,
\"packNpmManually\": true,
\"packNpmRelationList\": [
{
\"packageJsonPath\": \"./package.json\",
\"miniprogramNpmDistDir\": \"./miniprogram/\"
}
],
\"minifyWXSS\": true,
\"compileWorklet\": false,
\"minifyWXML\": true,
\"localPlugins\": false,
\"disableUseStrict\": false,
\"useCompilerPlugins\": false,
\"condition\": false,
\"swc\": false,
\"disableSWC\": true
},
\"appid\": \"wx429151859caeb046\",
\"projectname\": \"quickstart-wx-cloud\",
\"libVersion\": \"3.17.0\",
\"cloudfunctionTemplateRoot\": \"cloudfunctionTemplate/\",
\"condition\": {
\"search\": {
\"list\": []
},
\"conversation\": {
\"list\": []
},
\"plugin\": {
\"list\": []
},
\"game\": {
\"list\": []
},
\"miniprogram\": {
\"list\": [
{
\"id\": -1,
\"name\": \"db guide\",
\"pathName\": \"pages/databaseGuide/databaseGuide\"
}
]
}
},
\"compileType\": \"miniprogram\",
\"srcMiniprogramRoot\": \"miniprogram/\",
\"packOptions\": {
\"ignore\": [],
\"include\": []
},
\"editorSetting\": {
\"tabIndent\": \"insertSpaces\",
\"tabSize\": 2
},
\"simulatorPluginLibVersion\": {}
}
0%