<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Git 与 GitHub on 扎塔-Zata</title><link>https://www.zata.cc/tags/git-%E4%B8%8E-github/</link><description>Recent content in Git 与 GitHub on 扎塔-Zata</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>扎塔-Zata</copyright><lastBuildDate>Thu, 24 Sep 2026 17:09:06 +0800</lastBuildDate><atom:link href="https://www.zata.cc/tags/git-%E4%B8%8E-github/index.xml" rel="self" type="application/rss+xml"/><item><title>gh使用教程</title><link>https://www.zata.cc/p/gh%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><pubDate>Sun, 12 Apr 2026 21:50:00 +0800</pubDate><guid>https://www.zata.cc/p/gh%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>&lt;img src="https://www.zata.cc/p/gh%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/index.png" alt="Featured image of post gh使用教程" />&lt;h2 id="1-常用命令速查">1. 常用命令速查
&lt;/h2>&lt;p>&lt;strong>case&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建私有仓库并推送本地代码&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo create my-project --private --source&lt;span class="o">=&lt;/span>. --push
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查看帮助与版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh --version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh &lt;span class="nb">help&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh &amp;lt;command&amp;gt; --help
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 登录与认证&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh auth login
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh auth status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh auth &lt;span class="nb">logout&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo clone owner/repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo view --web
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo fork
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo sync
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pull Request&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr create --fill
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr view
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr checkout &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr diff
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr review --approve
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr merge
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Issue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue view &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue comment &lt;span class="m">123&lt;/span> --body &lt;span class="s2">&amp;#34;补充说明&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue close &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># GitHub Actions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh workflow list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh run list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh run view &amp;lt;run-id&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh run watch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh run download &amp;lt;run-id&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Release&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh release create v1.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh release list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh release view v1.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh release upload v1.0.0 dist/app.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 浏览器与搜索&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh browse
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh browse &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh search prs --author @me
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh search issues --owner your-org
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># API 与脚本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh api user
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh api repos/OWNER/REPO/pulls
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr list --json number,title,url
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 配置与效率&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh &lt;span class="nb">alias&lt;/span> &lt;span class="nb">set&lt;/span> pv &lt;span class="s2">&amp;#34;pr view&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh config &lt;span class="nb">set&lt;/span> editor vim
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh extension search
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh extension install owner/gh-extension-name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="2-gh-是什么">2. &lt;code>gh&lt;/code> 是什么
&lt;/h2>&lt;p>&lt;code>gh&lt;/code> 是 GitHub 官方命令行工具，核心价值不是替代 &lt;code>git&lt;/code>，而是把原本要在 GitHub 网页上完成的事情搬到终端里。&lt;/p>
&lt;p>适合用 &lt;code>git&lt;/code> 做的事情：&lt;/p>
&lt;ul>
&lt;li>本地提交、分支切换、变基、合并、查看工作区变更&lt;/li>
&lt;li>与任意 Git 远程交互，而不局限于 GitHub&lt;/li>
&lt;/ul>
&lt;p>适合用 &lt;code>gh&lt;/code> 做的事情：&lt;/p>
&lt;ul>
&lt;li>登录 GitHub 账号&lt;/li>
&lt;li>创建和管理 Pull Request、Issue、Release&lt;/li>
&lt;li>查看和触发 GitHub Actions&lt;/li>
&lt;li>直接调用 GitHub API&lt;/li>
&lt;li>安装 GitHub CLI 扩展&lt;/li>
&lt;/ul>
&lt;p>最实用的理解方式是：&lt;code>git&lt;/code> 管仓库历史，&lt;code>gh&lt;/code> 管 GitHub 平台能力。&lt;/p>
&lt;h2 id="3-安装与初始化">3. 安装与初始化
&lt;/h2>&lt;h3 id="安装">安装
&lt;/h3>&lt;p>常见安装方式如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># macOS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">brew install gh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Windows&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">winget install --id GitHub.cli
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ubuntu / Debian&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">type&lt;/span> -p curl &amp;gt;/dev/null &lt;span class="o">||&lt;/span> sudo apt install curl -y
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg &lt;span class="p">|&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> sudo dd &lt;span class="nv">of&lt;/span>&lt;span class="o">=&lt;/span>/usr/share/keyrings/githubcli-archive-keyring.gpg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;deb [arch=&lt;/span>&lt;span class="k">$(&lt;/span>dpkg --print-architecture&lt;span class="k">)&lt;/span>&lt;span class="s2"> signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> sudo tee /etc/apt/sources.list.d/github-cli.list &amp;gt; /dev/null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install gh -y
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>安装后先确认版本：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh --version
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="登录">登录
&lt;/h3>&lt;p>最常用的是交互式登录：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh auth login
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>执行后通常会依次选择：&lt;/p>
&lt;ul>
&lt;li>登录 &lt;code>GitHub.com&lt;/code> 还是企业版 GitHub&lt;/li>
&lt;li>使用 &lt;code>HTTPS&lt;/code> 还是 &lt;code>SSH&lt;/code>&lt;/li>
&lt;li>通过浏览器登录还是输入令牌&lt;/li>
&lt;/ul>
&lt;p>登录完成后可以检查状态：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh auth status
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果你已经有环境变量令牌，也可以让 &lt;code>gh&lt;/code> 直接使用：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">GITHUB_TOKEN&lt;/span>&lt;span class="o">=&lt;/span>your_token
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh auth status
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>说明：&lt;/p>
&lt;ul>
&lt;li>日常个人开发，交互式 &lt;code>gh auth login&lt;/code> 最省事&lt;/li>
&lt;li>在 CI、脚本、自动化环境里，更常见的是 &lt;code>GITHUB_TOKEN&lt;/code>&lt;/li>
&lt;li>如果你使用 GitHub Enterprise，可以用 &lt;code>gh auth login --hostname &amp;lt;hostname&amp;gt;&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="4-仓库操作">4. 仓库操作
&lt;/h2>&lt;h3 id="克隆仓库">克隆仓库
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh repo clone owner/repo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>它本质上还是帮你完成 GitHub 仓库级别的克隆，但写法更统一，也方便后续继续使用 &lt;code>gh&lt;/code>。&lt;/p>
&lt;h3 id="创建仓库">创建仓库
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh repo create
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个命令会进入交互流程，通常会问你：&lt;/p>
&lt;ul>
&lt;li>仓库名称&lt;/li>
&lt;li>是否公开&lt;/li>
&lt;li>是否添加 README&lt;/li>
&lt;li>是否推送当前目录&lt;/li>
&lt;/ul>
&lt;p>如果你想快速把当前项目推到 GitHub，经常很好用。&lt;/p>
&lt;h3 id="查看仓库信息">查看仓库信息
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh repo view
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo view --web
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo view owner/repo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>常见用途：&lt;/p>
&lt;ul>
&lt;li>在终端查看仓库概要&lt;/li>
&lt;li>直接在浏览器打开仓库页面&lt;/li>
&lt;li>脱离当前目录查看别的仓库&lt;/li>
&lt;/ul>
&lt;h3 id="fork-与同步">Fork 与同步
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh repo fork
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh repo sync
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>典型场景：&lt;/p>
&lt;ol>
&lt;li>&lt;code>fork&lt;/code> 别人的仓库到自己账号下&lt;/li>
&lt;li>在自己的 fork 上开发&lt;/li>
&lt;li>上游仓库更新后，用 &lt;code>gh repo sync&lt;/code> 同步&lt;/li>
&lt;/ol>
&lt;p>如果你平时经常参与开源项目，这两个命令非常顺手。&lt;/p>
&lt;h2 id="5-pull-request-工作流">5. Pull Request 工作流
&lt;/h2>&lt;p>&lt;code>gh&lt;/code> 最有价值的部分之一，就是把 PR 的完整链路搬到命令行里。&lt;/p>
&lt;h3 id="创建-pr">创建 PR
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh pr create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr create --fill
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>--fill&lt;/code> 会自动用当前分支的提交信息帮你生成标题和描述，适合已经写好了比较规范 commit message 的情况。&lt;/p>
&lt;p>常见流程：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout -b feature/login
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;feat: add login page&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push -u origin feature/login
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr create --fill
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="查看-pr">查看 PR
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh pr list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr view
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr view &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr view --web
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>适合查看：&lt;/p>
&lt;ul>
&lt;li>当前仓库有哪些 PR&lt;/li>
&lt;li>某个 PR 的详情&lt;/li>
&lt;li>直接跳转浏览器继续看评论和检查项&lt;/li>
&lt;/ul>
&lt;h3 id="切换到某个-pr">切换到某个 PR
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh pr checkout &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个命令很适合代码评审场景。你不用先找分支名，直接通过 PR 编号就能把代码拉到本地。&lt;/p>
&lt;h3 id="查看差异检查评审合并">查看差异、检查、评审、合并
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh pr diff &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr checks &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr review &lt;span class="m">123&lt;/span> --approve
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr review &lt;span class="m">123&lt;/span> --comment -b &lt;span class="s2">&amp;#34;建议补一个测试&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pr merge &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这一组命令基本覆盖了 PR 审查最常见的动作：&lt;/p>
&lt;ul>
&lt;li>看 diff&lt;/li>
&lt;li>看 CI 是否通过&lt;/li>
&lt;li>approve / comment / request changes&lt;/li>
&lt;li>合并 PR&lt;/li>
&lt;/ul>
&lt;p>如果团队流程比较规范，&lt;code>gh&lt;/code> 能明显减少频繁切浏览器的次数。&lt;/p>
&lt;h2 id="6-issue-管理">6. Issue 管理
&lt;/h2>&lt;h3 id="创建与查看">创建与查看
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh issue create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue view &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue view &lt;span class="m">123&lt;/span> --web
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>适合用来做：&lt;/p>
&lt;ul>
&lt;li>快速提 bug&lt;/li>
&lt;li>记录待办事项&lt;/li>
&lt;li>查看当前仓库未关闭的问题&lt;/li>
&lt;/ul>
&lt;h3 id="评论编辑关闭">评论、编辑、关闭
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh issue comment &lt;span class="m">123&lt;/span> --body &lt;span class="s2">&amp;#34;我来处理这个问题&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue edit &lt;span class="m">123&lt;/span> --add-label bug
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue close &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue reopen &lt;span class="m">123&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果你把 GitHub Issues 当轻量项目管理工具，这一组命令会非常高频。&lt;/p>
&lt;h2 id="7-github-actions-与-cicd">7. GitHub Actions 与 CI/CD
&lt;/h2>&lt;p>&lt;code>gh&lt;/code> 对 Actions 的支持很实用，尤其适合你在终端里排查 CI。&lt;/p>
&lt;h3 id="查看工作流和运行记录">查看工作流和运行记录
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh workflow list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh run list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh run view &amp;lt;run-id&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="观察运行状态">观察运行状态
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh run watch
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个命令适合在你刚 push 代码后盯 CI 结果，不用一直刷新网页。&lt;/p>
&lt;h3 id="下载产物与重新运行">下载产物与重新运行
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh run download &amp;lt;run-id&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh run rerun &amp;lt;run-id&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>常见场景：&lt;/p>
&lt;ul>
&lt;li>下载构建产物&lt;/li>
&lt;li>CI 因偶发网络问题失败时重跑&lt;/li>
&lt;li>快速定位是哪一步报错&lt;/li>
&lt;/ul>
&lt;h2 id="8-release-管理">8. Release 管理
&lt;/h2>&lt;p>如果你的项目通过 GitHub Release 发版本，&lt;code>gh&lt;/code> 可以把整个流程命令化。&lt;/p>
&lt;h3 id="创建与查看-release">创建与查看 Release
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh release create v1.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh release list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh release view v1.0.0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="上传构建产物">上传构建产物
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh release upload v1.0.0 dist/app.tar.gz
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这在发布二进制、压缩包、安装包时很方便，尤其适合配合脚本或 CI 自动化。&lt;/p>
&lt;h2 id="9-gh-api把-github-api-直接带进终端">9. &lt;code>gh api&lt;/code>：把 GitHub API 直接带进终端
&lt;/h2>&lt;p>很多人低估了 &lt;code>gh api&lt;/code>，但它其实是 &lt;code>gh&lt;/code> 最强的能力之一。&lt;/p>
&lt;h3 id="基本调用">基本调用
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh api user
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh api repos/OWNER/REPO
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh api repos/OWNER/REPO/issues
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果某个能力暂时没有现成的 &lt;code>gh &amp;lt;group&amp;gt; &amp;lt;subcommand&amp;gt;&lt;/code>，往往可以直接退回到 &lt;code>gh api&lt;/code>。&lt;/p>
&lt;h3 id="搭配-json-输出">搭配 JSON 输出
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh pr list --json number,title,url
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh issue list --json number,title,labels
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh workflow list --json id,name,path,state
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这类写法很适合：&lt;/p>
&lt;ul>
&lt;li>给 shell 脚本喂数据&lt;/li>
&lt;li>做自动化统计&lt;/li>
&lt;li>和 &lt;code>jq&lt;/code> 配合筛选字段&lt;/li>
&lt;/ul>
&lt;p>例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh pr list --json number,title,author --jq &lt;span class="s1">&amp;#39;.[] | {number, title, author: .author.login}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果你经常写脚本，建议尽快把 &lt;code>--json&lt;/code>、&lt;code>--jq&lt;/code> 这套用起来。&lt;/p>
&lt;h2 id="10-提效能力别名配置扩展">10. 提效能力：别名、配置、扩展
&lt;/h2>&lt;h3 id="alias">alias
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh &lt;span class="nb">alias&lt;/span> &lt;span class="nb">set&lt;/span> pv &lt;span class="s2">&amp;#34;pr view&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh &lt;span class="nb">alias&lt;/span> &lt;span class="nb">set&lt;/span> pc &lt;span class="s2">&amp;#34;pr create --fill&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh pc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>适合把高频长命令压缩成自己熟悉的缩写。&lt;/p>
&lt;h3 id="config">config
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh config &lt;span class="nb">set&lt;/span> editor vim
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh config get editor
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>最常见的是设置默认编辑器，避免某些命令唤起你不想用的编辑器。&lt;/p>
&lt;h3 id="extension">extension
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh extension search
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh extension install owner/gh-extension-name
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh extension list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh extension upgrade --all
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>扩展机制可以理解为给 &lt;code>gh&lt;/code> 加外挂命令。对于一些官方没内置、但社区已经做好了的能力，扩展通常是最快方案。&lt;/p>
&lt;h2 id="11-推荐的实际使用方式">11. 推荐的实际使用方式
&lt;/h2>&lt;p>如果你是个人开发者，可以先掌握这条最实用链路：&lt;/p>
&lt;ol>
&lt;li>&lt;code>gh auth login&lt;/code>&lt;/li>
&lt;li>&lt;code>gh repo clone owner/repo&lt;/code>&lt;/li>
&lt;li>&lt;code>git checkout -b feature/xxx&lt;/code>&lt;/li>
&lt;li>本地开发并提交&lt;/li>
&lt;li>&lt;code>git push -u origin feature/xxx&lt;/code>&lt;/li>
&lt;li>&lt;code>gh pr create --fill&lt;/code>&lt;/li>
&lt;li>&lt;code>gh pr checks&lt;/code>&lt;/li>
&lt;li>&lt;code>gh pr merge&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>如果你负责 CI/CD 或平台维护，再补上这些：&lt;/p>
&lt;ul>
&lt;li>&lt;code>gh workflow list&lt;/code>&lt;/li>
&lt;li>&lt;code>gh run list&lt;/code>&lt;/li>
&lt;li>&lt;code>gh run watch&lt;/code>&lt;/li>
&lt;li>&lt;code>gh release create&lt;/code>&lt;/li>
&lt;li>&lt;code>gh api&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>如果你经常参与开源协作，再补上这些：&lt;/p>
&lt;ul>
&lt;li>&lt;code>gh repo fork&lt;/code>&lt;/li>
&lt;li>&lt;code>gh repo sync&lt;/code>&lt;/li>
&lt;li>&lt;code>gh issue list&lt;/code>&lt;/li>
&lt;li>&lt;code>gh pr checkout&lt;/code>&lt;/li>
&lt;li>&lt;code>gh pr review&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="12-常见问题">12. 常见问题
&lt;/h2>&lt;h3 id="gh-和-git-到底怎么分工">&lt;code>gh&lt;/code> 和 &lt;code>git&lt;/code> 到底怎么分工？
&lt;/h3>&lt;p>一句话：&lt;/p>
&lt;ul>
&lt;li>&lt;code>git&lt;/code> 负责版本控制&lt;/li>
&lt;li>&lt;code>gh&lt;/code> 负责 GitHub 平台交互&lt;/li>
&lt;/ul>
&lt;p>最合理的方式不是二选一，而是组合使用。&lt;/p>
&lt;h3 id="为什么有些仓库命令要加--r">为什么有些仓库命令要加 &lt;code>-R&lt;/code>？
&lt;/h3>&lt;p>因为 &lt;code>gh&lt;/code> 默认优先使用当前目录对应的仓库上下文。如果你不在仓库目录里，或者你想操作别的仓库，就显式指定：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh pr list -R OWNER/REPO
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="命令太多记不住怎么办">命令太多记不住怎么办？
&lt;/h3>&lt;p>先记住三件事：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh &amp;lt;command&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gh &amp;lt;command&amp;gt; --help
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>gh&lt;/code> 的帮助系统本身就做得很好，遇到不熟悉的子命令时直接查帮助通常最快。&lt;/p>
&lt;h2 id="13-参考资料">13. 参考资料
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="https://cli.github.com/manual/index" target="_blank" rel="noopener"
>GitHub CLI manual&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.github.com/en/enterprise-cloud@latest/github-cli/github-cli/quickstart" target="_blank" rel="noopener"
>GitHub CLI quickstart&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.github.com/en/github-cli/github-cli/about-github-cli" target="_blank" rel="noopener"
>About GitHub CLI&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Self-hosted Runner</title><link>https://www.zata.cc/p/self-hosted-runner/</link><pubDate>Tue, 24 Feb 2026 09:22:30 +0800</pubDate><guid>https://www.zata.cc/p/self-hosted-runner/</guid><description>&lt;img src="https://www.zata.cc/p/self-hosted-runner/images/index/index.png" alt="Featured image of post Self-hosted Runner" />&lt;h1 id="实现从-windows-开发机通过-cicd-部署到另一台-windows-机器的方法">实现从 Windows 开发机通过 CI/CD 部署到另一台 Windows 机器的方法
&lt;/h1>&lt;p>要实现从一台 Windows 开发机通过 CI/CD 直接部署到另一台 Windows 机器，最主流且最稳定的做法是：在目标 Windows 机器上安装一个“自托管运行器 (Self-hosted Runner 或 Agent)”。&lt;/p>
&lt;p>这样一来，CI/CD 平台就可以直接向你的目标机器发送指令，让它自动拉取最新代码（或构建好的程序包）、替换旧文件并重启软件。&lt;/p>
&lt;p>以下是实现这一目标的标准流程，以目前最常用的 &lt;strong>GitHub Actions&lt;/strong> 为例（GitLab CI/CD 或 Azure DevOps 的原理几乎完全相同）：&lt;/p>
&lt;p>开发机上，你编写代码，然后执行 &lt;code>git push&lt;/code> 命令将代码推送到云端仓库（如 GitHub）。&lt;/p>
&lt;p>云端代码仓库（如 GitHub）检测到代码更新后，会触发 CI/CD 流程。此时，目标机器上运行的后台程序（Runner）接收到来自云端的指令，会自动在本地执行编译、覆盖文件和重启软件的脚本。&lt;/p>
&lt;p>在你的目标机器上配置 Runner 是最关键的一步。你需要让目标机器和云端仓库建立连接。具体步骤如下：&lt;/p>
&lt;p>在 GitHub 上，进入你的代码仓库，点击 &lt;strong>Settings&lt;/strong>，然后选择 &lt;strong>Actions&lt;/strong>，再进入 &lt;strong>Runners&lt;/strong> 页面。点击 &lt;strong>New self-hosted runner&lt;/strong>，选择 &lt;strong>Windows&lt;/strong> 操作系统及对应的架构（通常是 x64）。&lt;/p>
&lt;p>随后，在你的目标 Windows 机器上打开 PowerShell，按照 GitHub 页面上提供的步骤逐行复制并运行命令。这些命令会下载 Runner 程序、进行身份验证并将其注册到你的仓库中。&lt;/p>
&lt;p>在配置的最后一步，建议将 Runner 安装为 &lt;strong>Windows 服务 (Windows Service)&lt;/strong>，这样目标机器每次开机都会自动启动 Runner，随时准备接收部署任务。&lt;/p>
&lt;p>在目标机器上更新软件时，通常会遇到“文件被占用”的问题。因此，你需要写一个简单的 PowerShell 脚本来处理部署逻辑。例如，你的软件运行在 &lt;code>C:\MyApp&lt;/code>：&lt;/p>
&lt;ol>
&lt;li>停止正在运行的软件进程（或 Windows 服务）。&lt;/li>
&lt;li>将新编译好的文件复制到 &lt;code>C:\MyApp&lt;/code> 并覆盖。&lt;/li>
&lt;li>重新启动软件。&lt;/li>
&lt;/ol>
&lt;p>在你的开发机上，在项目根目录下创建一个文件夹 &lt;code>.github/workflows/&lt;/code>，并在其中新建一个文件（例如 &lt;code>deploy.yml&lt;/code>），填入以下内容：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Windows Auto Deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 当推送到 main 分支时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build-and-deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># 这里的 self-hosted 是关键，它告诉 GitHub 在你的目标机器上运行这些步骤&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">self-hosted &lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="l">. 获取最新代码&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="l">. 编译项目 (根据你的语言修改)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> echo &amp;#34;开始编译...&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 例如 C# 项目: dotnet build -c Release
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 例如 Node 项目: npm install &amp;amp;&amp;amp; npm run build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="l">. 停止当前运行的程序&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 假设你的程序叫 MyApp.exe
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> Stop-Process -Name &amp;#34;MyApp&amp;#34; -ErrorAction SilentlyContinue
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 如果是 Windows 服务，使用: Stop-Service -Name &amp;#34;MyService&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">4&lt;/span>&lt;span class="l">. 部署/覆盖文件&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> echo &amp;#34;复制文件到运行目录...&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 将编译好的产物复制到目标文件夹 (根据实际路径修改)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> Copy-Item -Path &amp;#34;.\bin\Release\net8.0\*&amp;#34; -Destination &amp;#34;C:\Deployments\MyApp&amp;#34; -Recurse -Force&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">5&lt;/span>&lt;span class="l">. 重启程序&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> echo &amp;#34;启动程序...&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 启动进程或重启服务
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> Start-Process -FilePath &amp;#34;C:\Deployments\MyApp\MyApp.exe&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 如果是 Windows 服务，使用: Start-Service -Name &amp;#34;MyService&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在配置 Runner 时，需要注意权限问题。Runner 默认以配置它的用户身份运行。如果你需要操作 C 盘敏感目录或管理 Windows 服务，确保 Runner 对应的用户（或服务账号）具有&lt;strong>管理员权限&lt;/strong>。&lt;/p>
&lt;p>此外，如果你的目标机器性能较弱，或者不想安装编译工具链，可以将 CI/CD 拆分为两个 Job：第一个 Job 使用 GitHub 官方的云端 Windows 服务器进行编译并上传产物 (Artifacts)；第二个 Job 运行在 &lt;code>self-hosted&lt;/code> 的目标机器上，只负责下载产物并覆盖文件。&lt;/p>
&lt;h2 id="self-hosted-runner-搭建教程">Self-hosted Runner 搭建教程
&lt;/h2>&lt;p>当 GitHub Actions 的免费额度用完，或者需要在特定硬件/内网环境上执行构建时，可以将自己的机器注册为 &lt;strong>Self-hosted Runner&lt;/strong>。它不消耗 GitHub Actions 分钟数，job 会直接运行在你的机器上。&lt;/p>
&lt;h3 id="注册-runner">注册 Runner
&lt;/h3>&lt;p>进入仓库 &lt;strong>Settings → Actions → Runners → New self-hosted runner&lt;/strong>（组织级别则在组织 Settings 中），选择对应的操作系统和架构，页面会生成一段包含一次性 registration token 的命令，照着执行即可。&lt;/p>
&lt;h3 id="linux-安装示例">Linux 安装示例
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir actions-runner &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> actions-runner
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 版本号以 GitHub 页面给出的为准&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl -o actions-runner-linux-x64-2.325.0.tar.gz -L &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> https://github.com/actions/runner/releases/download/v2.325.0/actions-runner-linux-x64-2.325.0.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">tar xzf actions-runner-linux-x64-*.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">./config.sh --url https://github.com/&amp;lt;用户名&amp;gt;/&amp;lt;仓库&amp;gt; --token &amp;lt;页面生成的token&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 前台测试运行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">./run.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 生产环境建议注册为系统服务&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo ./svc.sh install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo ./svc.sh start
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="windows-安装示例">Windows 安装示例
&lt;/h3>&lt;p>在 PowerShell 中执行（建议在 &lt;code>C:\actions-runner&lt;/code> 这类位于驱动器根目录下的短路径中安装；注册为服务时需要在管理员权限下执行）：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/self-hosted-runner/images/index/new-runner-setup.png"
width="1072"
height="1085"
srcset="https://www.zata.cc/p/self-hosted-runner/images/index/new-runner-setup_hu3330039181884697727.png 480w, https://www.zata.cc/p/self-hosted-runner/images/index/new-runner-setup_hu17718820863316748869.png 1024w"
loading="lazy"
alt="GitHub 生成的 Windows Self-hosted Runner 配置页面"
class="gallery-image"
data-flex-grow="98"
data-flex-basis="237px"
>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 在驱动器根目录下创建安装目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">mkdir&lt;/span> &lt;span class="nb">actions-runner&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nb">cd actions-runner&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 下载最新 Runner 包；版本号以 GitHub 页面给出的为准&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Invoke-WebRequest&lt;/span> &lt;span class="n">-Uri&lt;/span> &lt;span class="n">https&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="p">//&lt;/span>&lt;span class="n">github&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">actions&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">runner&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">releases&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">download&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">v2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">337&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mf">0&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="nb">actions-runner&lt;/span>&lt;span class="n">-win-x64&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">2.337&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">zip&lt;/span> &lt;span class="n">-OutFile&lt;/span> &lt;span class="nb">actions-runner&lt;/span>&lt;span class="n">-win-x64&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">2.337&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">zip&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 可选：校验 SHA256 哈希，避免下载包损坏&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nb">Get-FileHash&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nb">actions-runner&lt;/span>&lt;span class="n">-win-x64&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">2.337&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">zip&lt;/span> &lt;span class="n">-Algorithm&lt;/span> &lt;span class="n">SHA256&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">Hash&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUpper&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-ne&lt;/span> &lt;span class="s1">&amp;#39;1150692afa94e71f872017e254ea55b6eece1eece3fe7e3a6d4c93d0a1b85cfc&amp;#39;&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUpper&lt;/span>&lt;span class="p">()){&lt;/span> &lt;span class="k">throw&lt;/span> &lt;span class="s1">&amp;#39;Computed checksum did not match&amp;#39;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 解压到当前目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Add-Type&lt;/span> &lt;span class="n">-AssemblyName&lt;/span> &lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">IO&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Compression&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">FileSystem&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="no">System.IO.Compression.ZipFile&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">ExtractToDirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$PWD&lt;/span>&lt;span class="s2">/actions-runner-win-x64-2.337.0.zip&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$PWD&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">./&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">cmd&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-url&lt;/span> &lt;span class="n">https&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="p">//&lt;/span>&lt;span class="n">github&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">/&amp;lt;&lt;/span>&lt;span class="n">用户名&lt;/span>&lt;span class="p">&amp;gt;/&amp;lt;&lt;/span>&lt;span class="n">仓库&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-token&lt;/span> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">页面生成的token&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 前台测试运行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">./&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">cmd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 注册为 Windows 服务并启动&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">./&lt;/span>&lt;span class="n">svc&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">cmd&lt;/span> &lt;span class="n">install&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">./&lt;/span>&lt;span class="n">svc&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">cmd&lt;/span> &lt;span class="nb">start
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>按页面给出的命令完成下载、校验、解压和 &lt;code>config.cmd&lt;/code> 配置后，Runner 就会注册到仓库的 &lt;strong>Runners&lt;/strong> 列表中。只要状态显示为 &lt;strong>Idle&lt;/strong>，说明它已经在线并等待接收任务：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/self-hosted-runner/images/index/runners-idle.png"
width="754"
height="239"
srcset="https://www.zata.cc/p/self-hosted-runner/images/index/runners-idle_hu8511784814163634307.png 480w, https://www.zata.cc/p/self-hosted-runner/images/index/runners-idle_hu15969862009530225096.png 1024w"
loading="lazy"
alt="Runners 列表中显示注册完成的 Windows Runner"
class="gallery-image"
data-flex-grow="315"
data-flex-basis="757px"
>&lt;/p>
&lt;p>配置过程中会给 Runner 起名并选择 label（默认 &lt;code>self-hosted&lt;/code>、&lt;code>linux&lt;/code> 或 &lt;code>windows&lt;/code> 等）。注册为服务后，即使关闭终端或注销用户，Runner 也会在后台常驻。&lt;/p>
&lt;h3 id="在-workflow-中使用">在 Workflow 中使用
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">self-hosted &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 或 [self-hosted, linux] / [self-hosted, windows] 指定更细的 label&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">echo &amp;#34;running on my own machine&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="注意事项">注意事项
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>安全&lt;/strong>：公开仓库不要随意接入 self-hosted runner，任何 fork 的 PR 都可能执行代码。建议仅用于私有仓库，或在仓库设置中严格限制 workflow 权限。&lt;/li>
&lt;li>&lt;strong>环境隔离&lt;/strong>：job 直接运行在宿主机上，会留下缓存和文件。建议用 Docker 容器或一次性虚拟机运行 Runner，或在每次 job 前后做清理。&lt;/li>
&lt;li>&lt;strong>服务账户权限&lt;/strong>：Windows 下 Runner 默认以 &lt;code>NETWORK SERVICE&lt;/code> 运行，如果 job 需要 Docker、文件系统或网络共享权限，需在安装服务时指定有权限的账户，或在 &lt;code>services.msc&lt;/code> 中修改服务登录账户。&lt;/li>
&lt;li>&lt;strong>环境依赖&lt;/strong>：确保 Runner 所在机器已安装构建所需的工具链（Node、Python、Docker 等），且服务账户的 PATH 中可访问。&lt;/li>
&lt;li>&lt;strong>在线要求&lt;/strong>：Runner 需要保持在线才能接收任务，建议通过 &lt;code>systemd&lt;/code>（Linux）或 Windows 服务常驻运行。&lt;/li>
&lt;/ul></description></item><item><title>github release</title><link>https://www.zata.cc/p/github-release/</link><pubDate>Thu, 01 May 2025 01:28:06 +0800</pubDate><guid>https://www.zata.cc/p/github-release/</guid><description>&lt;img src="https://www.zata.cc/p/github-release/images/index/index.png" alt="Featured image of post github release" />&lt;p>关于版本的管理可以参考：
&lt;a class="link" href="https://www.bilibili.com/video/BV1Ee411W79K" target="_blank" rel="noopener"
>https://www.bilibili.com/video/BV1Ee411W79K&lt;/a>&lt;/p>
&lt;hr>
&lt;p>GitHub Release 是 GitHub 上用来标记项目可发布版本的一种方式。它可以包含该版本的源代码快照、编译好的二进制文件以及相关的发行说明。创建 Release 有助于用户清晰地了解项目的版本历史和获取特定版本的可执行文件或库。&lt;/p>
&lt;p>&lt;strong>为什么使用 GitHub Release？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>版本管理：&lt;/strong> 清晰地标记项目的不同版本，方便追溯和管理。&lt;/li>
&lt;li>&lt;strong>软件分发：&lt;/strong> 提供稳定版本的下载链接，方便用户获取和使用。&lt;/li>
&lt;li>&lt;strong>发行说明：&lt;/strong> 在 Release 中包含详细的说明，介绍该版本的特性、改进、Bug 修复等。&lt;/li>
&lt;li>&lt;strong>自动化：&lt;/strong> 可以结合 CI/CD 工具实现自动化 Release 发布。&lt;/li>
&lt;/ul>
&lt;p>在创建 GitHub Release 之前，你需要满足以下条件：&lt;/p>
&lt;ol>
&lt;li>拥有一个 GitHub 账号。&lt;/li>
&lt;li>拥有一个 GitHub 仓库。&lt;/li>
&lt;li>对该仓库有写入权限。&lt;/li>
&lt;li>通常情况下，你需要有一个 Git Tag 与 Release 关联。Tag 用于标记代码库中的某个特定的提交（commit），代表着该版本代码的状态。&lt;/li>
&lt;/ol>
&lt;p>有两种主要的方式来创建 GitHub Release：通过 GitHub 网页界面和通过 Git 命令行工具（结合 GitHub CLI）。&lt;/p>
&lt;h3 id="方法一通过-github-网页界面创建-release">方法一：通过 GitHub 网页界面创建 Release
&lt;/h3>&lt;p>这是最直观和常用的方法。&lt;/p>
&lt;p>&lt;strong>步骤 1：进入你的仓库页面&lt;/strong>&lt;/p>
&lt;p>在浏览器中打开你的 GitHub 仓库主页。&lt;/p>
&lt;p>&lt;strong>步骤 2：创建新的 Release&lt;/strong>&lt;/p>
&lt;p>&amp;ldquo;&lt;strong>Create a new release&lt;/strong>&amp;quot;（创建新 Release），点击这个按钮。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-1.png"
width="1275"
height="642"
srcset="https://www.zata.cc/p/github-release/images/index/index-1_hu14233999473419316545.png 480w, https://www.zata.cc/p/github-release/images/index/index-1_hu15510812016515103560.png 1024w"
loading="lazy"
alt="Create a new release"
class="gallery-image"
data-flex-grow="198"
data-flex-basis="476px"
>&lt;/p>
&lt;p>&lt;strong>步骤 3：选择或创建 Tag&lt;/strong>&lt;/p>
&lt;p>在新 Release 页面，你需要关联一个 Git Tag。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>选择现有 Tag：&lt;/strong> 点击 &amp;ldquo;Choose a tag&amp;rdquo;（选择一个标签）下拉菜单，选择一个已经存在的 Tag。&lt;/li>
&lt;li>&lt;strong>创建新 Tag：&lt;/strong> 在输入框中直接输入你想要创建的新 Tag 名称（例如 &lt;code>v1.0.0&lt;/code>）。输入后，会显示 &amp;ldquo;&lt;strong>Create new tag on publish&lt;/strong>&amp;quot;（发布时创建新标签）。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-2.png"
width="1270"
height="790"
srcset="https://www.zata.cc/p/github-release/images/index/index-2_hu12721207652665031077.png 480w, https://www.zata.cc/p/github-release/images/index/index-2_hu14229868557218555738.png 1024w"
loading="lazy"
alt="创建新tag"
class="gallery-image"
data-flex-grow="160"
data-flex-basis="385px"
>&lt;/p>
&lt;p>&lt;strong>重要提示：&lt;/strong> Tag 的命名通常遵循 &lt;a class="link" href="https://semver.org/" target="_blank" rel="noopener"
>Semantic Versioning&lt;/a> 规范，格式通常是 &lt;code>MAJOR.MINOR.PATCH&lt;/code>（大版本，小版本，bug修复版本），例如 &lt;code>v1.0.0&lt;/code>、&lt;code>v1.2.3&lt;/code> 等。建议在 Tag 前加上 &lt;code>v&lt;/code>。&lt;/p>
&lt;p>&lt;strong>步骤 4：选择目标分支 (如果创建新 Tag)&lt;/strong>&lt;/p>
&lt;p>如果你在步骤 4 中创建了一个新的 Tag，你需要选择这个 Tag 将关联到哪个分支上的最新提交。通常情况下，你会选择你的主分支（如 &lt;code>main&lt;/code> 或 &lt;code>master&lt;/code>）。点击 &amp;ldquo;Target&amp;rdquo;（目标）下拉菜单进行选择。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-4.png"
width="1268"
height="847"
srcset="https://www.zata.cc/p/github-release/images/index/index-4_hu6627979451046457891.png 480w, https://www.zata.cc/p/github-release/images/index/index-4_hu12306340666082991369.png 1024w"
loading="lazy"
alt="选择分支"
class="gallery-image"
data-flex-grow="149"
data-flex-basis="359px"
>&lt;/p>
&lt;p>&lt;strong>步骤 5：填写 Release 标题和描述&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Release title (发行标题):&lt;/strong> 输入你的 Release 的标题，通常与 Tag 名称相同或稍作描述（例如 &amp;ldquo;Version 1.0.0 Release&amp;rdquo;）。&lt;/li>
&lt;li>&lt;strong>Describe this release (描述此发行版):&lt;/strong> 在这里填写详细的发行说明（Release Notes）。你可以使用 Markdown 格式来美化你的说明。发行说明通常包括：
&lt;ul>
&lt;li>新功能 (New Features)&lt;/li>
&lt;li>改进 (Improvements)&lt;/li>
&lt;li>Bug 修复 (Bug Fixes)&lt;/li>
&lt;li>已知问题 (Known Issues)&lt;/li>
&lt;li>重大变化 (Breaking Changes) (如果适用)&lt;/li>
&lt;li>致谢 (Acknowledgements) (如果适用)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-5.png"
width="1274"
height="848"
srcset="https://www.zata.cc/p/github-release/images/index/index-5_hu13660114728688346705.png 480w, https://www.zata.cc/p/github-release/images/index/index-5_hu15621805022908629753.png 1024w"
loading="lazy"
alt="标题和描述"
class="gallery-image"
data-flex-grow="150"
data-flex-basis="360px"
>&lt;/p>
&lt;p>&lt;strong>步骤 6：自动生成 Release Notes (可选)&lt;/strong>&lt;/p>
&lt;p>GitHub 可以根据最近的提交历史自动生成 Release Notes。在描述框上方，点击 &amp;ldquo;&lt;strong>Generate release notes&lt;/strong>&amp;quot;（生成发行说明）按钮。你可以基于生成的笔记进行修改和完善。&lt;/p>
&lt;p>&lt;strong>步骤 7：上传二进制文件 (可选)&lt;/strong> 这只能上传25M，Github CLi可以2G&lt;/p>
&lt;p>如果你的 Release 包含编译好的可执行文件、安装包或其他二进制文件，可以在 &amp;ldquo;&lt;strong>Attach binaries by dropping them here or selecting them&lt;/strong>&amp;quot;（通过将二进制文件拖放到此处或选择它们来附加）区域上传。直接将文件拖放到该区域，或者点击选择文件。&lt;/p>
&lt;p>&lt;strong>步骤 8：选择 Release 类型 (可选)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>This is a pre-release (这是一个预发行版):&lt;/strong> 如果这个 Release 是一个测试版本、Beta 版本或 RC (Release Candidate) 版本，勾选此选项。预发行版会在 Release 列表中有特殊的标记。&lt;/li>
&lt;li>&lt;strong>Set as the latest release (设置为最新发行版):&lt;/strong> 默认情况下，新发布的 Release 会被标记为最新发行版。如果你发布的是一个旧版本或一个特殊的 Release，可以取消勾选此选项。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>步骤 9：创建讨论 (可选)&lt;/strong>&lt;/p>
&lt;p>如果你的仓库开启了 GitHub Discussions 功能，你可以选择为这个 Release 创建一个讨论。勾选 &amp;ldquo;&lt;strong>Create a discussion for this release&lt;/strong>&amp;quot;（为此发行版创建讨论），并选择一个讨论分类。&lt;/p>
&lt;p>&lt;strong>步骤 10：发布 Release&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Publish release (发布发行版):&lt;/strong> 如果你准备好将 Release 公开，点击此按钮。&lt;/li>
&lt;li>&lt;strong>Save draft (保存草稿):&lt;/strong> 如果你还没有准备好发布，想稍后再完善，点击此按钮将 Release 保存为草稿。草稿状态的 Release 只有仓库的协作者可见。&lt;/li>
&lt;/ul>
&lt;p>发布后，你的 Release 将会在仓库的 Releases 页面列出，并且与你关联的 Tag 也会被创建（如果你创建了新 Tag）。&lt;/p>
&lt;h3 id="方法二通过-git-命令行和-github-cli-创建-release">方法二：通过 Git 命令行和 GitHub CLI 创建 Release
&lt;/h3>&lt;p>对于习惯使用命令行或需要自动化发布流程的用户，可以使用 Git 命令创建 Tag，然后结合 GitHub CLI 来创建 Release。&lt;/p>
&lt;p>&lt;strong>前提条件：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>安装并配置好 Git。&lt;/li>
&lt;li>安装并认证 GitHub CLI (&lt;a class="link" href="https://cli.github.com/" target="_blank" rel="noopener"
>https://cli.github.com/&lt;/a>)。&lt;/li>
&lt;/ul>
&lt;p>CLI可以看：&lt;a class="link" href="https://zhuanlan.zhihu.com/p/601200139" target="_blank" rel="noopener"
>GitHub CLI 命令行工具（gh)&lt;/a>&lt;/p>
&lt;p>&lt;strong>步骤 1：在本地仓库创建并推送 Tag&lt;/strong>&lt;/p>
&lt;p>首先，在你的本地 Git 仓库中创建并推送一个 Tag。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 切换到你想要打 Tag 的 commit (可选，如果不是最新的 commit)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git checkout &amp;lt;commit_hash&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个轻量级 Tag (不推荐用于 Release)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git tag &amp;lt;tag_name&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个附注 Tag (推荐用于 Release，可以包含说明信息)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git tag -a &amp;lt;tag_name&amp;gt; -m &lt;span class="s2">&amp;#34;发行说明&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 推送 Tag 到远程仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin &amp;lt;tag_name&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git tag -a v1.0.0 -m &lt;span class="s2">&amp;#34;Initial release&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin v1.0.0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-6.png"
width="831"
height="414"
srcset="https://www.zata.cc/p/github-release/images/index/index-6_hu9834238509754044153.png 480w, https://www.zata.cc/p/github-release/images/index/index-6_hu8984073741517947065.png 1024w"
loading="lazy"
alt="设置tag"
class="gallery-image"
data-flex-grow="200"
data-flex-basis="481px"
>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-7.png"
width="505"
height="137"
srcset="https://www.zata.cc/p/github-release/images/index/index-7_hu15857070982743059655.png 480w, https://www.zata.cc/p/github-release/images/index/index-7_hu11037699988295714117.png 1024w"
loading="lazy"
alt="推送tag到远程"
class="gallery-image"
data-flex-grow="368"
data-flex-basis="884px"
>&lt;/p>
&lt;p>如果想要删除tag，使用下面的命令&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 删除本地tag&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git tag -d v1.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 删除远程tag&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin --delete v1.0.0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>步骤 2：使用 GitHub CLI 创建 Release&lt;/strong>&lt;/p>
&lt;p>在 Tag 推送到 GitHub 后，你可以使用 GitHub CLI 命令来创建 Release。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-8.png"
width="1113"
height="439"
srcset="https://www.zata.cc/p/github-release/images/index/index-8_hu12451502603745015809.png 480w, https://www.zata.cc/p/github-release/images/index/index-8_hu1769589692897246825.png 1024w"
loading="lazy"
alt="登录和推送"
class="gallery-image"
data-flex-grow="253"
data-flex-basis="608px"
>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh release create &amp;lt;tag_name&amp;gt; &lt;span class="o">[&lt;/span>flags&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>一些常用的 flag：&lt;/p>
&lt;ul>
&lt;li>&lt;code>-t, --title &amp;lt;string&amp;gt;&lt;/code>: 设置 Release 的标题。&lt;/li>
&lt;li>&lt;code>-n, --notes &amp;lt;string&amp;gt;&lt;/code>: 设置 Release 的描述/发行说明。&lt;/li>
&lt;li>&lt;code>-F, --notes-file &amp;lt;file&amp;gt;&lt;/code>: 从文件中读取 Release 的描述/发行说明。&lt;/li>
&lt;li>&lt;code>-d, --draft&lt;/code>: 将 Release 创建为草稿。&lt;/li>
&lt;li>&lt;code>-p, --prerelease&lt;/code>: 将 Release 标记为预发行版。&lt;/li>
&lt;li>&lt;code>--latest=false&lt;/code>: 不将此 Release 设置为最新发行版。&lt;/li>
&lt;li>&lt;code>&amp;lt;filename&amp;gt; | &amp;lt;pattern&amp;gt;...&lt;/code>: 指定要上传到 Release 的资产文件。&lt;/li>
&lt;/ul>
&lt;p>例如，创建一个包含描述并上传一个文件的 Release：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh release create v1.0.0 --title &lt;span class="s2">&amp;#34;Version 1.0.0&amp;#34;&lt;/span> --notes &lt;span class="s2">&amp;#34;This is the first release.&amp;#34;&lt;/span> my_app.zip
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果你的发行说明比较长，可以将其写入一个文件（例如 &lt;code>release_notes.md&lt;/code>），然后使用 &lt;code>-F&lt;/code> 参数：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">gh release create v1.0.0 --title &lt;span class="s2">&amp;#34;Version 1.0.0&amp;#34;&lt;/span> -F release_notes.md my_app.zip
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/github-release/images/index/index-9.png"
width="1113"
height="116"
srcset="https://www.zata.cc/p/github-release/images/index/index-9_hu8529872772572740933.png 480w, https://www.zata.cc/p/github-release/images/index/index-9_hu5092180901456231452.png 1024w"
loading="lazy"
alt="推送"
class="gallery-image"
data-flex-grow="959"
data-flex-basis="2302px"
>&lt;/p>
&lt;p>如果你只创建 Tag，然后想基于该 Tag 在 GitHub 上起草 Release，也可以直接去网页界面操作，选择刚刚推送的 Tag。但是网页只能上传25MB的附件&lt;/p>
&lt;p>&lt;strong>通过命令行编辑和删除 Release：&lt;/strong>&lt;/p>
&lt;p>GitHub CLI 也提供了编辑和删除 Release 的命令：&lt;/p>
&lt;ul>
&lt;li>编辑 Release：&lt;code>gh release edit &amp;lt;tag_name&amp;gt; [flags]&lt;/code>&lt;/li>
&lt;li>删除 Release：&lt;code>gh release delete &amp;lt;tag_name&amp;gt;&lt;/code>&lt;/li>
&lt;/ul>
&lt;h3 id="总结">总结
&lt;/h3>&lt;p>创建 GitHub Release 是项目版本管理和软件分发的重要环节。你可以选择使用直观的网页界面进行操作，也可以通过命令行工具实现更灵活和自动化的流程。无论哪种方式，核心都是为代码库的特定状态（通过 Git Tag 标记）创建一个带有详细说明和可选附件的版本发布。&lt;/p>
&lt;p>希望这个详细教程对你有帮助！&lt;/p></description></item><item><title>git-submodule-子模块</title><link>https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/</link><pubDate>Tue, 29 Apr 2025 11:10:22 +0800</pubDate><guid>https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/</guid><description>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/index.png" alt="Featured image of post git-submodule-子模块" />&lt;p>这是一份关于 Git Submodule（子模块）的详细教程，包括概念、使用场景、常用命令以及详细的可执行代码示例。&lt;/p>
&lt;p>Git Submodule 允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。这在你有一个主项目依赖于其他独立开发的库或项目时非常有用。子模块会固定在你指定的一个特定的提交（commit）上，而不是分支的最新状态。&lt;/p>
&lt;h2 id="知识点总结">知识点总结
&lt;/h2>&lt;h3 id="git-submodule-记录的是子模块仓库中一个特定的提交">Git Submodule 记录的是子模块仓库中一个特定的提交
&lt;/h3>&lt;p>Git Submodule 的一个核心概念是：主仓库记录的是子模块仓库中一个特定的提交（commit），而不是跟踪子模块的某个分支的最新状态。&lt;/p>
&lt;p>这意味着当你使用 git submodule add &amp;lt;远程仓库URL&amp;gt; &lt;path> 命令时：&lt;/p>
&lt;p>Git 会克隆远程子模块仓库到指定的路径。
默认情况下，Git 会检出子模块仓库的 默认分支（通常是 main 或 master）。
最重要的一点： 主仓库会记录下子模块仓库在 那个默认分支上当前的最新提交的 SHA-1 值。&lt;/p>
&lt;p>为什么是这样？&lt;/p>
&lt;p>这种设计是为了保证主项目的稳定性。主项目依赖于子模块的一个确定版本。如果主项目仅仅跟踪子模块的某个分支（比如 main），那么子模块的任何新提交都可能在你不经意间破坏主项目的功能。通过锁定到特定的提交，你可以精确控制主项目使用的子模块代码版本，确保每次克隆或更新主项目时，子模块都处于预期的状态。&lt;/p>
&lt;h3 id="如何指定添加子模块时使用的分支或标签">如何指定添加子模块时使用的分支或标签？
&lt;/h3>&lt;p>如果你不想使用子模块仓库的默认分支，可以在 git submodule add 命令中使用 -b 选项指定一个特定的分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Bash" data-lang="Bash">&lt;span class="line">&lt;span class="cl">git submodule add -b &amp;lt;分支名&amp;gt; &amp;lt;远程仓库URL&amp;gt; &amp;lt;子模块在主仓库中的路径&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>示例：指定 develop 分支&lt;/p>
&lt;p>假设你想添加子模块，并使用其 develop 分支的当前提交：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Bash" data-lang="Bash">&lt;span class="line">&lt;span class="cl">git submodule add -b develop https://github.com/your-username/your-submodule-repo.git submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样，Git 会克隆子模块仓库，检出 develop 分支，然后主仓库记录 develop 分支当前的最新提交。&lt;/p>
&lt;p>你也可以指定一个标签（tag）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Bash" data-lang="Bash">&lt;span class="line">&lt;span class="cl">git submodule add -b &amp;lt;标签名&amp;gt; &amp;lt;远程仓库URL&amp;gt; &amp;lt;子模块在主仓库中的路径&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="更新子模块时如何处理分支">更新子模块时如何处理分支？
&lt;/h3>&lt;p>当你运行 git submodule update &amp;ndash;remote 命令来更新子模块时：&lt;/p>
&lt;p>Git 会进入子模块目录。&lt;/p>
&lt;p>它会拉取子模块远程仓库的最新提交。&lt;/p>
&lt;p>默认情况下，它会根据 .gitmodules 文件中记录的信息（如果添加时指定了 -b 分支，则使用该分支；否则使用远程仓库的默认分支）找到该分支的最新提交。&lt;/p>
&lt;p>然后，它会将子模块的工作树更新到该分支的最新提交，并更新主仓库对子模块的引用到这个新的提交。&lt;/p>
&lt;h3 id="为什么使用-git-submodule">&lt;strong>为什么使用 Git Submodule？&lt;/strong>
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>管理外部依赖：&lt;/strong> 当你的项目依赖于第三方库或其他内部独立项目时，可以使用子模块来包含它们，而不是直接复制代码。&lt;/li>
&lt;li>&lt;strong>分离关注点：&lt;/strong> 将大型项目拆分成更小的、可管理的独立仓库。&lt;/li>
&lt;li>&lt;strong>版本控制依赖：&lt;/strong> 精确控制主项目使用的外部依赖的版本（通过指定特定的提交）。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Git Submodule 的一些注意事项：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>复杂性增加：&lt;/strong> 使用子模块会增加工作流程的复杂性，特别是对于不熟悉子模块的团队成员。&lt;/li>
&lt;li>&lt;strong>更新子模块：&lt;/strong> 子模块不会随主项目自动更新到最新版本，需要手动更新。&lt;/li>
&lt;li>&lt;strong>克隆的特殊性：&lt;/strong> 克隆包含子模块的项目需要额外的步骤。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="具体教程">具体教程
&lt;/h2>&lt;h3 id="准备工作创建示例仓库">&lt;strong>准备工作：创建示例仓库&lt;/strong>
&lt;/h3>&lt;p>为了演示，我们需要创建两个 Git 仓库：一个作为主仓库（parent），另一个作为子模块仓库（submodule）。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>创建子模块仓库 (submodule_repo):&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个目录作为子模块仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir submodule_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> submodule_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 初始化 Git 仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个示例文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;This is the submodule content.&amp;#34;&lt;/span> &amp;gt; submodule_file.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 添加并提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Initial commit for submodule&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (可选) 如果你使用 GitHub 或 Gitee，可以创建一个远程仓库并关联&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git remote add origin &amp;lt;你的远程仓库地址&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git push -u origin master&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>创建主仓库 (parent_repo):&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 回到上一级目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个目录作为主仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir parent_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> parent_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 初始化 Git 仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个示例文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;This is the parent content.&amp;#34;&lt;/span> &amp;gt; parent_file.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 添加并提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Initial commit for parent&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (可选) 如果你使用 GitHub 或 Gitee，可以创建一个远程仓库并关联&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git remote add origin &amp;lt;你的远程仓库地址&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git push -u origin master&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>现在我们有了两个本地 Git 仓库：&lt;code>parent_repo&lt;/code> 和 &lt;code>submodule_repo&lt;/code>。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-1.png"
width="1024"
height="768"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-1_hu13857130514537436686.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-1_hu11638244521051072211.png 1024w"
loading="lazy"
alt="项目结构"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-2.png"
width="1024"
height="768"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-2_hu6489308407506496138.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-2_hu17428376519034220305.png 1024w"
loading="lazy"
alt="两个子模块在vscode中显示"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;hr>
&lt;h3 id="1-添加子模块">&lt;strong>1. 添加子模块&lt;/strong>
&lt;/h3>&lt;p>在主仓库 &lt;code>parent_repo&lt;/code> 中，我们将 &lt;code>submodule_repo&lt;/code> 添加为一个子模块。&lt;/p>
&lt;p>打开终端，进入 &lt;code>parent_repo&lt;/code> 目录：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> parent_repo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用 &lt;code>git submodule add&lt;/code> 命令添加子模块。语法是：&lt;code>git submodule add &amp;lt;子模块仓库地址&amp;gt; &amp;lt;子模块在主仓库中的路径&amp;gt;&lt;/code>&lt;/p>
&lt;p>如果你的子模块仓库是本地的，可以使用相对或绝对路径。如果是远程仓库（如 GitHub），使用其 URL。&lt;/p>
&lt;p>&lt;strong>示例：添加本地子模块&lt;/strong>&lt;/p>
&lt;p>因为 Git 的安全设置默认禁止通过 file:// 协议（也就是直接的本地文件路径）进行克隆，这包括添加本地子模块。&lt;/p>
&lt;p>这是 Git 为了防止某些安全风险而设置的。当你使用相对路径 ../submodule_repo 时，Git 内部会将其解析为 file:// 协议来尝试克隆。&lt;/p>
&lt;p>因此可以通过配置全局允许file协议解决&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 任何目录下执行，写入配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global protocol.file.allow always
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">## 如果想取消&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --unset protocol.file.allow
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>假设 &lt;code>submodule_repo&lt;/code> 目录与 &lt;code>parent_repo&lt;/code> 目录在同一级。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 在主仓库目录，添加子模块&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git submodule add ../submodule_repo submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>../submodule_repo&lt;/code>: 子模块仓库的路径。&lt;/li>
&lt;li>&lt;code>submodule_directory&lt;/code>: 子模块在 &lt;code>parent_repo&lt;/code> 中的存放路径。&lt;/li>
&lt;/ul>
&lt;p>执行此命令后，你会看到类似以下的输出：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">Cloning into &amp;#39;submodule_directory&amp;#39;...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">done.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-3.png"
width="595"
height="289"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-3_hu15841329082808505276.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-3_hu12847708670293884494.png 1024w"
loading="lazy"
alt="配置全局允许 file 协议 并添加子模块："
class="gallery-image"
data-flex-grow="205"
data-flex-basis="494px"
>&lt;/p>
&lt;p>&lt;strong>查看变化：&lt;/strong>&lt;/p>
&lt;p>运行 &lt;code>git status&lt;/code>，你会发现有两项变化：&lt;/p>
&lt;ul>
&lt;li>&lt;code>.gitmodules&lt;/code> 文件被创建。&lt;/li>
&lt;li>&lt;code>submodule_directory&lt;/code> 目录被添加。&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出会显示：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">On branch master
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes to be committed:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> (use &amp;#34;git reset HEAD &amp;lt;file&amp;gt;...&amp;#34; to unstage)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new file: .gitmodules
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> new file: submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-4.png"
width="496"
height="122"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-4_hu1604706381832271288.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-4_hu2890236446369376098.png 1024w"
loading="lazy"
alt="status"
class="gallery-image"
data-flex-grow="406"
data-flex-basis="975px"
>&lt;/p>
&lt;p>&lt;code>.gitmodules&lt;/code> 文件记录了子模块的信息，包括路径和 URL。查看其内容：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">cat .gitmodules
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出类似：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">[submodule &amp;#34;submodule_directory&amp;#34;]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> path = submodule_directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> url = ../submodule_repo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>submodule_directory&lt;/code> 目录现在是 &lt;code>submodule_repo&lt;/code> 的一个工作副本，但它处于一个特殊的“游离 HEAD”（detached HEAD）状态，指向添加子模块时 &lt;code>submodule_repo&lt;/code> 的最新提交。&lt;/p>
&lt;p>&lt;strong>提交子模块的添加：&lt;/strong>&lt;/p>
&lt;p>将 &lt;code>.gitmodules&lt;/code> 文件和子模块目录的添加提交到主仓库：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add .gitmodules submodule_directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Add submodule_repo as a submodule&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>现在，主仓库已经记录了子模块的存在以及它指向的特定提交。&lt;/p>
&lt;hr>
&lt;h3 id="2-克隆包含子模块的仓库">&lt;strong>2. 克隆包含子模块的仓库&lt;/strong>
&lt;/h3>&lt;p>当其他人克隆包含子模块的仓库时，默认情况下子模块目录是空的。需要额外的步骤来初始化和更新子模块。&lt;/p>
&lt;p>假设你要克隆上面创建的 &lt;code>parent_repo&lt;/code>。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>正常克隆主仓库：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 回到上一级目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 克隆主仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone parent_repo cloned_parent_repo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>进入克隆后的 &lt;code>cloned_parent_repo&lt;/code> 目录，你会发现 &lt;code>submodule_directory&lt;/code> 目录存在，但里面是空的：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> cloned_parent_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ls submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>（没有输出或显示目录为空）&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-5.png"
width="1024"
height="768"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-5_hu2194991093576667738.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-5_hu2370671528723505282.png 1024w"
loading="lazy"
alt="克隆主仓库后"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;ol start="2">
&lt;li>
&lt;p>&lt;strong>初始化并更新子模块：&lt;/strong>&lt;/p>
&lt;p>需要运行以下命令来初始化子模块配置并拉取子模块的代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git submodule init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git submodule update
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-6.png"
width="1024"
height="768"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-6_hu6123268521155332540.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-6_hu2777898186863299044.png 1024w"
loading="lazy"
alt="更新子模块"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;ul>
&lt;li>&lt;code>git submodule init&lt;/code>: 这个命令会读取 &lt;code>.gitmodules&lt;/code> 文件，并将子模块的信息添加到主仓库的 &lt;code>.git/config&lt;/code> 文件中。&lt;/li>
&lt;li>&lt;code>git submodule update&lt;/code>: 这个命令会克隆子模块仓库到指定的路径，并检出 &lt;code>.gitmodules&lt;/code> 文件中记录的特定提交。&lt;/li>
&lt;/ul>
&lt;p>运行 &lt;code>git submodule update&lt;/code> 后，&lt;code>submodule_directory&lt;/code> 目录就会包含子模块的代码了：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ls submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">submodule_file.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>更便捷的克隆方式：&lt;/strong>&lt;/p>
&lt;p>可以在克隆主仓库时直接使用 &lt;code>--recurse-submodules&lt;/code> 选项，一步完成克隆、初始化和更新子模块：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 回到上一级目录并删除之前克隆的仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -rf cloned_parent_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 --recurse-submodules 选项克隆&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone --recurse-submodules parent_repo cloned_parent_repo_recursive
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 进入目录并查看子模块内容&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> cloned_parent_repo_recursive
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ls submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">submodule_file.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-7.png"
width="1024"
height="768"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-7_hu13062220883314404303.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-7_hu1665260754452644913.png 1024w"
loading="lazy"
alt="更便捷的克隆"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;p>这种方式更推荐，因为它简化了克隆包含子模块的项目流程。&lt;/p>
&lt;hr>
&lt;h3 id="3-更新子模块">&lt;strong>3. 更新子模块&lt;/strong>
&lt;/h3>&lt;p>子模块固定在主仓库记录的特定提交上。如果子模块仓库有了新的提交，你需要手动更新主仓库中对子模块的引用。&lt;/p>
&lt;p>假设 &lt;code>submodule_repo&lt;/code> 有了新的提交。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>在子模块仓库中进行新的提交：&lt;/strong>&lt;/p>
&lt;p>进入 &lt;code>submodule_repo&lt;/code> 目录（或者克隆后的 &lt;code>cloned_parent_repo/submodule_directory&lt;/code> 目录），进行修改并提交：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 进入子模块目录 (如果你还在 parent_repo 或其克隆目录中)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> submodule_directory &lt;span class="c1"># 或者 cd ../submodule_repo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建或修改文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Adding new content to submodule.&amp;#34;&lt;/span> &amp;gt;&amp;gt; submodule_file.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 添加并提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Add new content to submodule&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (如果子模块有远程仓库) 推送到子模块的远程仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git push origin master&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>在主仓库中更新子模块引用：&lt;/strong>&lt;/p>
&lt;p>回到主仓库（&lt;code>parent_repo&lt;/code> 或其克隆目录）。此时，主仓库仍然指向子模块的旧提交。进入子模块目录之后运行 &lt;code>git status&lt;/code> 会显示子模块目录已被修改：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> .. &lt;span class="c1"># 回到主仓库目录 (parent_repo 或 cloned_parent_repo)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> parent_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> submodule_directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出类似：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">On branch master
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes not staged for commit:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> (use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to update what will be committed)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> (use &amp;#34;git checkout -- &amp;lt;file&amp;gt;...&amp;#34; to discard changes in working directory)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> modified: submodule_directory (new commits)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">no changes added to commit (use &amp;#34;git add&amp;#34; and/or &amp;#34;git commit -a&amp;#34;)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-8.png"
width="594"
height="273"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-8_hu3725513492893021617.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-8_hu8899786905777909923.png 1024w"
loading="lazy"
alt="只在子模块中显示更新"
class="gallery-image"
data-flex-grow="217"
data-flex-basis="522px"
>&lt;/p>
&lt;p>要将主仓库更新到子模块的最新提交，可以使用 &lt;code>git submodule update --remote&lt;/code> 命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git submodule update --remote
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-9.png"
width="589"
height="251"
srcset="https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-9_hu11465150142233467127.png 480w, https://www.zata.cc/p/git-submodule-%E5%AD%90%E6%A8%A1%E5%9D%97/images/index/image-9_hu14689825837717233839.png 1024w"
loading="lazy"
alt="拉取子模块"
class="gallery-image"
data-flex-grow="234"
data-flex-basis="563px"
>&lt;/p>
&lt;p>这个命令会进入每个子模块目录，拉取最新的代码，并更新主仓库中子模块的引用到最新的提交。&lt;/p>
&lt;p>&lt;strong>注意：&lt;/strong> &lt;code>git submodule update --remote&lt;/code> 默认会更新到子模块仓库当前分支的最新提交。如果你希望更新到特定分支，可以使用 &lt;code>--remote --merge &amp;lt;分支名&amp;gt;&lt;/code> 或 &lt;code>--remote --rebase &amp;lt;分支名&amp;gt;&lt;/code>。&lt;/p>
&lt;p>更新后，再次运行 &lt;code>git status&lt;/code>，你会看到子模块目录再次被标记为已修改，但这次是因为它的引用指向了新的提交：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出类似：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">On branch master
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes to be committed:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> (use &amp;#34;git reset HEAD &amp;lt;file&amp;gt;...&amp;#34; to unstage)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> modified: submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>提交主仓库的更新：&lt;/strong>&lt;/p>
&lt;p>将主仓库中对子模块引用的更新进行提交：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add submodule_directory &lt;span class="c1"># 当然直接git add . 也可以&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Update submodule_directory to latest commit&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (如果主仓库有远程仓库) 推送到主仓库的远程仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git push origin master&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样，主仓库就记录了子模块的最新状态。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="4-在子模块中工作">&lt;strong>4. 在子模块中工作&lt;/strong>
&lt;/h3>&lt;p>在子模块目录中，你可以像在任何独立的 Git 仓库中一样进行操作：切换分支、创建提交、推拉代码等。&lt;/p>
&lt;p>进入子模块目录：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>现在你就在 &lt;code>submodule_repo&lt;/code> 的工作目录中了。你可以进行正常的 Git 操作：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查看当前分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git branch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 切换分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git checkout &amp;lt;分支名&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建新的提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (修改文件，git add，git commit)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 推送到子模块的远程仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git push origin &amp;lt;分支名&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>完成在子模块中的工作后，回到主仓库目录：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ..
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果子模块中有了新的提交，主仓库会检测到变化（如上面更新子模块的步骤所示），你需要再次在主仓库中提交对子模块引用的更新。&lt;/p>
&lt;hr>
&lt;h3 id="5-切换分支包含子模块">&lt;strong>5. 切换分支（包含子模块）&lt;/strong>
&lt;/h3>&lt;p>在包含子模块的主仓库中切换分支可能会有些复杂，因为不同分支可能引用子模块的不同提交，甚至在某些分支上没有子模块。&lt;/p>
&lt;p>当切换到一个新分支时，Git 会尝试根据新分支的 &lt;code>.gitmodules&lt;/code> 文件和主仓库记录的子模块提交信息，自动更新子模块。&lt;/p>
&lt;p>&lt;strong>示例：切换到新分支&lt;/strong>&lt;/p>
&lt;p>假设在 &lt;code>parent_repo&lt;/code> 中创建一个新分支 &lt;code>feature_branch&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout -b feature_branch
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果在 &lt;code>feature_branch&lt;/code> 上对子模块进行了修改（例如，更新到新的提交），然后切换回 &lt;code>master&lt;/code> 分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout master
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Git 会尽力将子模块恢复到 &lt;code>master&lt;/code> 分支所指向的提交。如果出现问题（例如，子模块目录有未提交的修改），Git 可能会报错或将子模块目录标记为未追踪。&lt;/p>
&lt;p>为了避免潜在的问题，建议在切换主仓库分支之前，确保子模块目录是干净的（没有未提交的修改）。如果子模块中有修改需要保留，先在子模块内部进行提交。&lt;/p>
&lt;hr>
&lt;h3 id="6-删除子模块">&lt;strong>6. 删除子模块&lt;/strong>
&lt;/h3>&lt;p>删除子模块比添加子模块要麻烦一些，需要执行几个步骤来彻底移除子模块的记录和文件。&lt;/p>
&lt;p>假设我们要从 &lt;code>parent_repo&lt;/code> 中删除 &lt;code>submodule_directory&lt;/code> 子模块。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>取消初始化子模块：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git submodule deinit submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个命令会移除 &lt;code>.git/config&lt;/code> 文件中关于该子模块的配置。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>移除 &lt;code>.gitmodules&lt;/code> 文件中的对应条目：&lt;/strong>&lt;/p>
&lt;p>使用文本编辑器打开 &lt;code>.gitmodules&lt;/code> 文件，删除对应子模块的配置段落（例如，&lt;code>[submodule &amp;quot;submodule_directory&amp;quot;]&lt;/code> 开始的部分）。&lt;/p>
&lt;p>或者使用命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config -f .gitmodules --remove-section submodule.submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>从暂存区移除子模块：&lt;/strong>&lt;/p>
&lt;p>子模块在 Git 中被记录为一个特殊的工作树条目。需要将其从暂存区移除：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rm --cached submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>手动删除子模块的工作目录和 &lt;code>.git/modules&lt;/code> 中的相关文件：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">rm -rf submodule_directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -rf .git/modules/submodule_directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>rm -rf submodule_directory&lt;/code>: 删除子模块在主仓库中的工作目录。&lt;/li>
&lt;li>&lt;code>rm -rf .git/modules/submodule_directory&lt;/code>: 删除 Git 在主仓库内部为该子模块存储的元数据和对象。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>提交删除操作：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add .gitmodules
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Remove submodule_directory submodule&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>现在，子模块就彻底从主仓库中删除了。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="总结常用命令">&lt;strong>总结常用命令&lt;/strong>
&lt;/h3>&lt;ul>
&lt;li>&lt;code>git submodule add &amp;lt;url&amp;gt; &amp;lt;path&amp;gt;&lt;/code>: 添加子模块。&lt;/li>
&lt;li>&lt;code>git submodule init&lt;/code>: 初始化本地的子模块配置。&lt;/li>
&lt;li>&lt;code>git submodule update&lt;/code>: 克隆子模块仓库并检出主仓库指定的提交。&lt;/li>
&lt;li>&lt;code>git clone --recurse-submodules &amp;lt;url&amp;gt;&lt;/code>: 克隆主仓库并递归地初始化和更新子模块。&lt;/li>
&lt;li>&lt;code>git submodule update --remote&lt;/code>: 将子模块更新到其远程仓库的最新提交，并更新主仓库的引用。&lt;/li>
&lt;li>&lt;code>git submodule deinit &amp;lt;path&amp;gt;&lt;/code>: 取消初始化子模块。&lt;/li>
&lt;li>&lt;code>git rm --cached &amp;lt;path&amp;gt;&lt;/code>: 从暂存区移除子模块。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="更高级的用法和注意事项">&lt;strong>更高级的用法和注意事项&lt;/strong>
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>指定分支或标签：&lt;/strong> 添加子模块时，可以使用 &lt;code>-b &amp;lt;分支名&amp;gt;&lt;/code> 或指定一个特定的提交 SHA1 来控制子模块的初始状态。&lt;/li>
&lt;li>&lt;strong>子模块的子模块：&lt;/strong> 如果子模块本身也包含子模块，在克隆和更新时需要使用 &lt;code>--recursive&lt;/code> 选项，例如 &lt;code>git clone --recursive&lt;/code> 和 &lt;code>git submodule update --recursive&lt;/code>。&lt;/li>
&lt;li>&lt;strong>游离 HEAD 状态：&lt;/strong> 在子模块目录中进行修改并提交后，子模块会处于游离 HEAD 状态。如果你想在子模块中固定跟踪某个分支，需要在子模块目录中 &lt;code>git checkout &amp;lt;分支名&amp;gt;&lt;/code>，然后在主仓库中提交对子模块引用的更新。&lt;/li>
&lt;li>&lt;strong>使用 .gitattributes 忽略子模块的某些文件：&lt;/strong> 可以在主仓库的 &lt;code>.gitattributes&lt;/code> 文件中配置，以便 Git 在某些操作（如 &lt;code>git status&lt;/code>）中忽略子模块目录中的未追踪或已修改文件。&lt;/li>
&lt;li>&lt;strong>替代方案：&lt;/strong> 对于简单的依赖管理，考虑使用包管理器（如 npm, yarn, pip, Composer, Maven, Gradle 等），它们通常比 Git Submodule 更易于管理依赖版本和更新。Git Submodule 更适合于包含独立的、需要独立开发和版本控制的子项目或库。&lt;/li>
&lt;/ul>
&lt;p>希望这份详细的教程能帮助你理解和使用 Git Submodule！如果在实践中遇到问题，可以根据具体的错误信息进行搜索或提问。&lt;/p></description></item><item><title>2-github action 使用</title><link>https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/</link><pubDate>Mon, 03 Mar 2025 00:00:00 +0800</pubDate><guid>https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/</guid><description>&lt;img src="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/images/index/index.png" alt="Featured image of post 2-github action 使用" />&lt;p>参考：&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/tech-shrimp/GithubActionSample" target="_blank" rel="noopener"
>https://github.com/tech-shrimp/GithubActionSample&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html" target="_blank" rel="noopener"
>https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html&lt;/a> [LXF,挺有用]&lt;/li>
&lt;/ul>
&lt;h3 id="常用知识">常用知识
&lt;/h3>&lt;h3 id="基础概念">&lt;strong>基础概念&lt;/strong>
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Workflow（工作流）&lt;/strong>&lt;br>
工作流是一个自动化过程，定义在一或多个 YAML 文件中，存放在 &lt;code>.github/workflows&lt;/code> 目录下。一个项目可以有多个工作流，他们顺序执行，你也可以在一个工作流里面引用执行另一个工作流&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Event（事件）&lt;/strong>&lt;br>
触发工作流的事件，例如 &lt;code>push&lt;/code>（推送代码）、&lt;code>pull_request&lt;/code>（拉取请求）或定时触发。也可以手动执行，&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Job（任务）&lt;/strong>&lt;br>
工作流中的一组步骤（Steps），运行在同一个虚拟机上。多个 Job 可以并行或按顺序执行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Step（步骤）&lt;/strong>&lt;br>
Job 中的单个操作，例如运行命令或调用一个 Action。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Action（动作）&lt;/strong>&lt;br>
可重用的代码单元，通常由社区或官方提供，简化常见任务。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Runner（运行器）&lt;/strong>&lt;br>
执行工作流的服务器，GitHub 提供托管的 Runner，也支持自托管。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>共享的action&lt;/strong>
很多操作在不同项目里面是类似的，完全可以共享。GitHub 注意到了这一点，想出了一个很妙的点子，允许开发者把每个操作写成独立的脚本文件，存放到代码仓库，使得其他开发者可以引用。&lt;/p>
&lt;p>如果你需要某个 action，不必自己写复杂的脚本，直接引用他人写好的 action 即可，整个持续集成过程，就变成了一个 actions 的组合。这就是 GitHub Actions 最特别的地方。&lt;/p>
&lt;p>GitHub 做了一个官方市场 &lt;a class="link" href="https://github.com/marketplace?type=actions" target="_blank" rel="noopener"
>https://github.com/marketplace?type=actions&lt;/a> ，可以搜索到他人提交的 actions。另外，还有一个 awesome actions 的仓库 &lt;a class="link" href="https://github.com/sdras/awesome-actions" target="_blank" rel="noopener"
>https://github.com/sdras/awesome-actions&lt;/a> ，也可以找到不少 action。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index.jpg"
width="1912"
height="990"
srcset="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index_hu1281008539772498063.jpg 480w, https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index_hu4829532998228493744.jpg 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="193"
data-flex-basis="463px"
>
每个 action 就是一个独立脚本，因此可以做成代码仓库，使用userName/repoName的语法引用 action。比如，actions/setup-node就表示github.com/actions/setup-node这个仓库，它代表一个 action，作用是安装 Node.js。事实上，GitHub 官方的 actions 都放在 github.com/actions 里面。
既然 actions 是代码仓库，当然就有版本的概念，用户可以引用某个具体版本的 action。下面都是合法的 action 引用，用的就是 Git 的指针概念，详见官方文档。https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions#versioning-your-action&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">actions/setup-node@74bc508 # 指向一个 commit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">actions/setup-node@v1.0 # 指向一个标签
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">actions/setup-node@master # 指向一个分支
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>仓库密钥和环境密钥的区别，以及组织密钥&lt;/p>
&lt;p>参考：&lt;/p>
&lt;p>&lt;a class="link" href="https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions" target="_blank" rel="noopener"
>https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index-1.jpg"
width="1912"
height="954"
srcset="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index-1_hu4397505417618076307.jpg 480w, https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index-1_hu8228239392819969285.jpg 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="200"
data-flex-basis="481px"
>&lt;/p>
&lt;p>仓库密钥：（仓库下面的所有分支和标签可用）&lt;/p>
&lt;ul>
&lt;li>仓库密钥是在 GitHub 仓库级别设置的，用于保护仓库的访问权限和敏感信息。&lt;/li>
&lt;li>仓库密钥可以在仓库的“Settings” &amp;gt; “Secrets” &amp;gt; “Actions”中设置。&lt;/li>
&lt;li>仓库密钥只能在仓库内使用，不能跨仓库共享。&lt;/li>
&lt;/ul>
&lt;p>环境密钥：（可设置哪些分支可用）&lt;/p>
&lt;ul>
&lt;li>环境密钥是在 GitHub 分支级别设置的，可以通过设置去设置哪些分支可用&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index-2.jpg"
width="1912"
height="954"
srcset="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index-2_hu14917312720165822342.jpg 480w, https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index-2_hu11430220340789479472.jpg 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="200"
data-flex-basis="481px"
>&lt;/p>
&lt;p>组织密钥：（可以设置哪些仓库可用）&lt;/p>
&lt;p>&lt;code>另外，在工作流里面是打印不出来密钥的&lt;/code>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="构建画爱心为可执行程序">构建画爱心为可执行程序
&lt;/h3>&lt;p>原始代码效果：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index.gif"
width="646"
height="516"
srcset="https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index_hu11815783179957955532.gif 480w, https://www.zata.cc/p/2-github-action-%E4%BD%BF%E7%94%A8/image/index/index_hu12728063288137864306.gif 1024w"
loading="lazy"
alt="画爱心效果"
class="gallery-image"
data-flex-grow="125"
data-flex-basis="300px"
>&lt;/p>
&lt;p>代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 版权https://github.com/royalneverwin/beating-heart&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">tkinter&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="c1"># 导入tkinter库，用于创建GUI界面&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">math&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">sin&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cos&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">log&lt;/span> &lt;span class="c1"># 导入数学函数，用于心形计算&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span> &lt;span class="c1"># 导入随机数模块，用于生成随机点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span> &lt;span class="c1"># 导入时间模块（当前代码未使用，但保留）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 定义画布的宽度和高度&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CANVAS_WIDTH&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">640&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CANVAS_HEIGHT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">480&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 计算画布中心坐标&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CANVAS_CENTER_X&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">CANVAS_WIDTH&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CANVAS_CENTER_Y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">CANVAS_HEIGHT&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 心形放大倍数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">IMAGE_ENLARGE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">11&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">scatter_inside&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">beta&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.15&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 在心形内部生成散点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;使用对数分布在给定点附近生成内部散点&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ratiox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">beta&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="c1"># 对数分布计算x方向偏移量，可调整beta值改变分布&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ratioy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">beta&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="c1"># 对数分布计算y方向偏移量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ratiox&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_X&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 计算x方向的实际偏移&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ratioy&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_Y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 计算y方向的实际偏移&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">dx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">dy&lt;/span> &lt;span class="c1"># 返回散点的新坐标&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">heart_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">enlarge_ratio&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">IMAGE_ENLARGE&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 定义心形曲线方程&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;根据参数t生成心形曲线的x,y坐标&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 心形曲线参数方程&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">16&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">sin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">13&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">cos&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">5&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">cos&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">cos&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">cos&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 放大心形&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">*=&lt;/span> &lt;span class="n">enlarge_ratio&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y&lt;/span> &lt;span class="o">*=&lt;/span> &lt;span class="n">enlarge_ratio&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 将心形移动到画布中心&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">CANVAS_CENTER_X&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">CANVAS_CENTER_Y&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 返回整数坐标&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">shrink&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ratio&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 向心形中心收缩点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;根据距离中心点的平方反比计算收缩量&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sk_range&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_X&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_Y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 平方反比因子&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ratio&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">sk_range&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_X&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># x方向收缩量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ratio&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">sk_range&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_Y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># y方向收缩量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">dx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">dy&lt;/span> &lt;span class="c1"># 返回收缩后的坐标&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Heart&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">frame&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 初始化心形类&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">points&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">set&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 存储心形曲线上的点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">edge_points&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">set&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 存储边缘散点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">inside_points&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">set&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 存储内部散点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">all_points&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span> &lt;span class="c1"># 存储每一帧的所有点坐标&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 构建初始点集，可调整点的数量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">frame&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">frame&lt;/span> &lt;span class="c1"># 动画的总帧数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">f&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frame&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 预计算每一帧的点位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">calc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random_halo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000&lt;/span> &lt;span class="c1"># 用于光晕效果的随机点数量（未直接使用）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">number&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 生成初始点集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;在心形上生成随机点及其边缘和内部散点&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 在心形曲线上随机生成number个点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">number&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">uniform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 随机生成角度t&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">heart_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 计算心形上的点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">shrink&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 向中心收缩点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">points&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)))&lt;/span> &lt;span class="c1"># 添加到点集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 生成边缘散点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">px&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">py&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">points&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 每个点生成3个边缘散点，可调整数量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scatter_inside&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">px&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">py&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.05&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 在点附近生成散点，可调整beta值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">edge_points&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="c1"># 添加到边缘点集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 生成内部散点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pt_ls&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">points&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 将点集转为列表以便随机选择&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4000&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 生成4000个内部散点，可调整数量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pt_ls&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 随机选择一个基础点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scatter_inside&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 在其附近生成散点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">inside_points&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="c1"># 添加到内部点集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">cal_position&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ratio&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 计算点在跳动时的位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;根据距离中心的平方反比计算跳动幅度&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bt_range&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_X&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_Y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 跳动因子&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ratio&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">bt_range&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_X&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># x方向位移&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ratio&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">bt_range&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">CANVAS_CENTER_Y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># y方向位移&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">dx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">dy&lt;/span> &lt;span class="c1"># 返回跳动后的位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">calc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">frame&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 计算每一帧的点位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;预计算每帧中所有点的动态位置&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ratio&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">800&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">sin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frame&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 跳动幅度随正弦变化，30fps，可调整&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_pts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span> &lt;span class="c1"># 存储当前帧所有点的列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 生成光晕效果&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">halo_radius&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">6&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">sin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">frame&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">)))&lt;/span> &lt;span class="c1"># 光晕半径随时间变化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">halo_number&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3000&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="nb">abs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">frame&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="c1"># 光晕点数量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">heart_halo_point&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">set&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 存储光晕点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">halo_number&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">uniform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 随机角度&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">heart_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">enlarge_ratio&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">11.6&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 生成光晕基础点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">shrink&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">halo_radius&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 向中心收缩&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">heart_halo_point&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 避免重复&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">heart_halo_point&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">14&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">14&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 添加随机偏移&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">14&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">14&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choice&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="c1"># 随机选择点大小&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_pts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="c1"># 添加到点列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 计算心形曲线上的点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">points&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cal_position&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ratio&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 计算跳动位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 随机点大小，可调整&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_pts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 计算边缘点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">edge_points&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cal_position&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ratio&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 随机点大小，可调整&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_pts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 计算内部点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">inside_points&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cal_position&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ratio&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 随机点大小，可调整&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_pts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">all_points&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">frame&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">all_pts&lt;/span> &lt;span class="c1"># 保存当前帧的点数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">render&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">canvas&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">frame&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 渲染点到画布上&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;在画布上绘制当前帧的所有点&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">all_points&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">frame&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">frame&lt;/span>&lt;span class="p">]:&lt;/span> &lt;span class="c1"># 循环取帧数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 绘制矩形点，颜色为粉红色&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">canvas&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_rectangle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">width&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">fill&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;#ff7171&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">draw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">root&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Tk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">canvas&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Canvas&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">heart&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Heart&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">frame&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 动画绘制函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;递归调用实现心形跳动动画&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">canvas&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;all&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 清空画布&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">heart&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">render&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">canvas&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">frame&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 绘制当前帧&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 每30毫秒刷新一次，相当于约33fps&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">root&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">after&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">30&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">draw&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">root&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">canvas&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">heart&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">frame&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 主程序入口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">root&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Tk&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 创建主窗口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">root&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;漂亮宝贝一周年快乐&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 设置窗口标题&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 创建画布，背景黑色&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">canvas&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Canvas&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">root&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bg&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;black&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">height&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">CANVAS_HEIGHT&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">width&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">CANVAS_WIDTH&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">canvas&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pack&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 将画布添加到窗口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">heart&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Heart&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">20&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 创建心形对象，帧数设为20&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">draw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">root&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">canvas&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">heart&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 开始动画&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">root&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mainloop&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 进入主循环，显示窗口&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后创建一个.github/workflows文件夹，并在其中创建一个love_heart.yml文件。文件内容如下填写,功能是创建一个windows的可执行程序&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># This workflow will install Python dependencies, run tests and lint with a single version of Python&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 这是一个 GitHub Actions 工作流，用于安装 Python 依赖、运行测试和代码检查，使用单一 Python 版本&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 更多信息请参考上述 GitHub 文档链接&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">画爱心Windows版 &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 工作流名称，显示在 GitHub Actions 界面上，表示这是一个在 Windows 上构建“画爱心”程序的工作流&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 定义触发工作流的事件&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 手动触发事件，允许用户通过 GitHub 界面手动运行此工作流&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">permissions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 设置工作流的权限&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">contents&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">read &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 授予读取仓库内容的权限，确保工作流可以访问代码&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 定义工作流中的任务&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pyinstaller-build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 任务名称，表示使用 PyInstaller 构建可执行文件&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">windows-latest &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 指定运行环境为最新的 Windows 系统&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 定义任务的具体步骤&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Create Executable &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 步骤名称，表示创建可执行文件&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">sayyid5416/pyinstaller@v1 &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 使用社区提供的 PyInstaller Action，版本为 v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 配置 Action 的参数&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python_ver&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.12&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 指定使用的 Python 版本为 3.12&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;love_heart.py&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 指定 PyInstaller 的构建配置文件或主 Python 文件为 love_heart.py&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">upload_exe_with_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;love_heart&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 指定上传的可执行文件名称为 love_heart&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">options&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>--&lt;span class="l">onefile, --name &amp;#34;love_heart&amp;#34;, --windowed, &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># PyInstaller 的构建选项&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># --onefile: 将所有内容打包为单个可执行文件（生成 .exe 文件）&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># --name &amp;#34;love_heart&amp;#34;: 设置输出可执行文件的名称为 love_heart（最终为 love_heart.exe）&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># --windowed: 生成无控制台窗口的 GUI 应用程序，适合 Windows 上的图形界面程序&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># 注意：选项之间用逗号分隔，最后一个选项后不需要逗号，但此处保留原始格式&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="快速入门教程">&lt;strong>快速入门教程&lt;/strong>
&lt;/h3>&lt;h4 id="目标">&lt;strong>目标&lt;/strong>
&lt;/h4>&lt;p>创建一个简单的 GitHub Actions 工作流，在每次推送代码时运行一个脚本，输出 &amp;ldquo;Hello, GitHub Actions!&amp;quot;。&lt;/p>
&lt;h4 id="步骤">&lt;strong>步骤&lt;/strong>
&lt;/h4>&lt;ol>
&lt;li>
&lt;p>&lt;strong>创建仓库&lt;/strong>&lt;br>
在 GitHub 上创建一个新仓库（或使用现有仓库）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>添加工作流文件&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>在仓库根目录下创建文件夹 &lt;code>.github/workflows&lt;/code>。&lt;/li>
&lt;li>在该文件夹中创建一个文件，例如 &lt;code>hello.yml&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>编写工作流文件&lt;/strong>&lt;br>
将以下内容写入 &lt;code>hello.yml&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Hello World Workflow&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 触发条件：在推送代码到 main 分支时运行&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># 定义任务&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">say-hello&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 使用 GitHub 提供的最新 Ubuntu 虚拟机&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Checkout code&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 检出代码到虚拟机&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Say Hello&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">echo &amp;#34;Hello, GitHub Actions!&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 运行简单的 shell 命令&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>提交文件&lt;/strong>&lt;br>
将 &lt;code>hello.yml&lt;/code> 提交到仓库的 &lt;code>main&lt;/code> 分支。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>查看运行结果&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>转到仓库的 &lt;strong>Actions&lt;/strong> 标签页。&lt;/li>
&lt;li>你会看到名为 &amp;ldquo;Hello World Workflow&amp;rdquo; 的工作流正在运行。&lt;/li>
&lt;li>点击工作流名称，查看日志，确认 &amp;ldquo;Hello, GitHub Actions!&amp;rdquo; 已输出。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="进阶示例">&lt;strong>进阶示例&lt;/strong>
&lt;/h3>&lt;h4 id="运行测试并部署">&lt;strong>运行测试并部署&lt;/strong>
&lt;/h4>&lt;p>假设你有一个 Node.js 项目，想在推送代码时运行测试并部署到服务器。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>工作流文件示例&lt;/strong>&lt;br>
创建 &lt;code>.github/workflows/test-and-deploy.yml&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Test and Deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Checkout code&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Setup Node.js&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/setup-node@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">node-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;16&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install dependencies&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">npm install&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Run tests&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">npm test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">needs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">test&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 在 test 任务成功后运行&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Checkout code&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy to server&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> echo &amp;#34;Deploying to server...&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> # 这里可以添加实际部署命令，例如通过 SSH&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>添加秘密（Secrets）&lt;/strong>&lt;br>
如果部署需要敏感信息（如 SSH 密钥）：&lt;/p>
&lt;ul>
&lt;li>转到仓库的 &lt;strong>Settings &amp;gt; Secrets and variables &amp;gt; Actions&lt;/strong>。&lt;/li>
&lt;li>点击 &lt;strong>New repository secret&lt;/strong>，添加密钥（如 &lt;code>SSH_KEY&lt;/code>）。&lt;/li>
&lt;li>在工作流中通过 &lt;code>secrets.SSH_KEY&lt;/code> 使用它。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="常用配置">&lt;strong>常用配置&lt;/strong>
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>触发事件&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 推送时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pull_request&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 拉取请求时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedule&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 定时触发（每天凌晨0点）&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">cron&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;0 0 * * *&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>设置环境变量&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MY_VAR&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Hello&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">example&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">echo $MY_VAR&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 输出 &amp;#34;Hello&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>使用社区 Action&lt;/strong>&lt;br>
示例：使用 &lt;code>actions/cache&lt;/code> 缓存依赖：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Cache node modules&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/cache@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">~/.npm&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ runner.os }}-node-${{ hashFiles(&amp;#39;**/package-lock.json&amp;#39;) }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="调试技巧">&lt;strong>调试技巧&lt;/strong>
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>查看日志&lt;/strong>：在 Actions 标签页点击工作流，展开每个 Job 和 Step 查看详细输出。&lt;/li>
&lt;li>&lt;strong>添加调试步骤&lt;/strong>：在步骤中运行 &lt;code>ls -la&lt;/code>（Linux）或 &lt;code>dir&lt;/code>（Windows）检查文件。&lt;/li>
&lt;li>&lt;strong>使用 GitHub 提供的测试工具&lt;/strong>：在本地安装 &lt;code>act&lt;/code>（需要 Docker）模拟运行工作流。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="常见问题">&lt;strong>常见问题&lt;/strong>
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>工作流没触发？&lt;/strong>&lt;br>
检查 &lt;code>on&lt;/code> 配置是否匹配事件和分支。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>权限不足？&lt;/strong>&lt;br>
在仓库设置中确认 Actions 已启用（Settings &amp;gt; Actions &amp;gt; General）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>需要更多计算资源？&lt;/strong>&lt;br>
考虑使用自托管 Runner。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h3 id="扩展阅读">&lt;strong>扩展阅读&lt;/strong>
&lt;/h3>&lt;ul>
&lt;li>官方文档：https://docs.github.com/en/actions&lt;/li>
&lt;li>社区 Actions：https://github.com/marketplace?type=actions&lt;/li>
&lt;/ul>
&lt;h3 id="on字段">on字段
&lt;/h3>&lt;p>在 GitHub Actions 的 &lt;code>on&lt;/code> 字段中，你可以定义触发工作流的事件。&lt;code>workflow_dispatch&lt;/code> 是其中一种触发方式，表示手动触发。除了 &lt;code>workflow_dispatch&lt;/code>，还有许多其他触发事件可以选择，具体取决于你的需求。以下是 &lt;code>on&lt;/code> 可以填写的参数（触发事件类型），以及它们的用途和可能配置项：&lt;/p>
&lt;hr>
&lt;h3 id="on-可填写的触发事件类型">&lt;code>on&lt;/code> 可填写的触发事件类型
&lt;/h3>&lt;h4 id="1-workflow_dispatch手动触发">1. &lt;code>workflow_dispatch&lt;/code>（手动触发）
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>：允许用户通过 GitHub 界面手动触发工作流。&lt;/li>
&lt;li>&lt;strong>可选配置&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>inputs&lt;/code>：定义手动触发时可以输入的参数。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">inputs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;输入你的名字&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">required&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 是否必填&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">default&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;Anonymous&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 默认值&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;选择版本&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">choice &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 类型可以是 string, boolean, choice 等&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">options&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;v1&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;v2&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">required&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>用途&lt;/strong>：适合需要用户干预或自定义参数的场景，例如手动选择构建版本。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="2-push推送事件">2. &lt;code>push&lt;/code>（推送事件）
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>：当代码被推送到指定分支或路径时触发。&lt;/li>
&lt;li>&lt;strong>可选配置&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>branches&lt;/code>：指定触发分支。&lt;/li>
&lt;li>&lt;code>branches-ignore&lt;/code>：忽略特定分支。&lt;/li>
&lt;li>&lt;code>paths&lt;/code>：指定触发文件路径。&lt;/li>
&lt;li>&lt;code>paths-ignore&lt;/code>：忽略特定文件路径。&lt;/li>
&lt;li>&lt;code>tags&lt;/code>：指定触发标签。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;feature/*&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 支持通配符&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">paths&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;src/**&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 只在 src 目录下文件变更时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tags&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;v*&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>用途&lt;/strong>：适合每次代码提交时自动构建或测试。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="3-pull_request拉取请求事件">3. &lt;code>pull_request&lt;/code>（拉取请求事件）
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>：当拉取请求（PR）被创建、更新或合并时触发。&lt;/li>
&lt;li>&lt;strong>可选配置&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>branches&lt;/code>：目标分支。&lt;/li>
&lt;li>&lt;code>types&lt;/code>：触发的事件类型（如 &lt;code>opened&lt;/code>, &lt;code>synchronize&lt;/code>, &lt;code>closed&lt;/code>）。&lt;/li>
&lt;li>&lt;code>paths&lt;/code>：触发文件路径。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pull_request&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">types&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">opened &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># PR 创建时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">synchronize &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># PR 更新时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">paths&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;*.py&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 只在 Python 文件变更时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>用途&lt;/strong>：用于 PR 的自动化检查或构建。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="4-schedule定时触发">4. &lt;code>schedule&lt;/code>（定时触发）
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>：按计划时间触发，使用 cron 表达式。&lt;/li>
&lt;li>&lt;strong>可选配置&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>cron&lt;/code>：定义运行时间（UTC）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedule&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">cron&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;0 0 * * *&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 每天 UTC 00:00 触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">cron&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;*/15 * * * *&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 每 15 分钟触发一次&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>用途&lt;/strong>：适合定时任务，例如每天构建或检查。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="5-release发布事件">5. &lt;code>release&lt;/code>（发布事件）
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>：当 GitHub 发布（release）相关操作发生时触发。&lt;/li>
&lt;li>&lt;strong>可选配置&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>types&lt;/code>：触发类型（如 &lt;code>published&lt;/code>, &lt;code>created&lt;/code>, &lt;code>edited&lt;/code>）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">release&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">types&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">published &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 发布时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">prereleased &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 预发布时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>用途&lt;/strong>：用于发布版本时的自动化构建或部署。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="6-issues问题事件">6. &lt;code>issues&lt;/code>（问题事件）
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>：当 GitHub Issues 相关操作发生时触发。&lt;/li>
&lt;li>&lt;strong>可选配置&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>types&lt;/code>：触发类型（如 &lt;code>opened&lt;/code>, &lt;code>closed&lt;/code>, &lt;code>labeled&lt;/code>）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">issues&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">types&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">opened &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 新建 issue 时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">labeled &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 添加标签时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>用途&lt;/strong>：适合与问题管理相关的自动化任务。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="7-workflow_run工作流运行事件">7. &lt;code>workflow_run&lt;/code>（工作流运行事件）
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>：当另一个工作流完成时触发当前工作流。&lt;/li>
&lt;li>&lt;strong>可选配置&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>workflows&lt;/code>：指定监听的工作流名称。&lt;/li>
&lt;li>&lt;code>types&lt;/code>：触发类型（如 &lt;code>completed&lt;/code>）。&lt;/li>
&lt;li>&lt;code>branches&lt;/code>：触发分支。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflows&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;Build&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 监听名为 Build 的工作流&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">types&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">completed &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Build 完成后触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>用途&lt;/strong>：用于工作流间的依赖关系，例如先构建再部署。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="8-其他事件">8. 其他事件
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>&lt;code>create&lt;/code>&lt;/strong>：当创建分支或标签时触发。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">create&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s1">&amp;#39;feature/*&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>&lt;code>delete&lt;/code>&lt;/strong>：当删除分支或标签时触发。&lt;/li>
&lt;li>&lt;strong>&lt;code>fork&lt;/code>&lt;/strong>：当仓库被 fork 时触发。&lt;/li>
&lt;li>&lt;strong>&lt;code>watch&lt;/code>&lt;/strong>：当用户点击“Star”时触发。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">watch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">types&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">started &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># 用户 star 仓库时触发&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="组合使用">组合使用
&lt;/h4>&lt;p>你可以组合多个事件类型。例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pull_request&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样，工作流会在推送、拉取请求或手动触发时运行。&lt;/p>
&lt;hr>
&lt;h4 id="参数总结表">参数总结表
&lt;/h4>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>触发事件&lt;/th>
&lt;th>主要配置项&lt;/th>
&lt;th>示例用途&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>workflow_dispatch&lt;/code>&lt;/td>
&lt;td>&lt;code>inputs&lt;/code>&lt;/td>
&lt;td>手动构建，带自定义参数&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>push&lt;/code>&lt;/td>
&lt;td>&lt;code>branches&lt;/code>, &lt;code>paths&lt;/code>, &lt;code>tags&lt;/code>&lt;/td>
&lt;td>代码提交时构建&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>pull_request&lt;/code>&lt;/td>
&lt;td>&lt;code>branches&lt;/code>, &lt;code>types&lt;/code>, &lt;code>paths&lt;/code>&lt;/td>
&lt;td>PR 检查&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>schedule&lt;/code>&lt;/td>
&lt;td>&lt;code>cron&lt;/code>&lt;/td>
&lt;td>定时任务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>release&lt;/code>&lt;/td>
&lt;td>&lt;code>types&lt;/code>&lt;/td>
&lt;td>发布版本&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>issues&lt;/code>&lt;/td>
&lt;td>&lt;code>types&lt;/code>&lt;/td>
&lt;td>Issue 管理&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>workflow_run&lt;/code>&lt;/td>
&lt;td>&lt;code>workflows&lt;/code>, &lt;code>types&lt;/code>, &lt;code>branches&lt;/code>&lt;/td>
&lt;td>工作流依赖&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>create&lt;/code>&lt;/td>
&lt;td>&lt;code>branches&lt;/code>&lt;/td>
&lt;td>创建分支或标签&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h4 id="针对你的需求">针对你的需求
&lt;/h4>&lt;p>你的工作流目前使用 &lt;code>workflow_dispatch&lt;/code>，适合手动触发构建“画爱心”程序。如果需要其他触发方式：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>自动构建&lt;/strong>：用 &lt;code>push&lt;/code> 或 &lt;code>pull_request&lt;/code>，在代码变更时触发。&lt;/li>
&lt;li>&lt;strong>定时构建&lt;/strong>：用 &lt;code>schedule&lt;/code>，每天生成新版本。&lt;/li>
&lt;li>&lt;strong>发布版本&lt;/strong>：用 &lt;code>release&lt;/code>，在发布时生成可执行文件。&lt;/li>
&lt;/ul>
&lt;p>如果你想具体调整（例如添加 &lt;code>push&lt;/code> 或 &lt;code>schedule&lt;/code>），可以告诉我，我帮你写出对应配置！&lt;/p></description></item><item><title>git&amp;github_tutorial</title><link>https://www.zata.cc/p/gitgithub/</link><pubDate>Fri, 28 Feb 2025 00:00:00 +0000</pubDate><guid>https://www.zata.cc/p/gitgithub/</guid><description>&lt;img src="https://www.zata.cc/p/gitgithub/image/index/index.png" alt="Featured image of post git&amp;github_tutorial" />&lt;h2 id="目录">目录
&lt;/h2>&lt;ul>
&lt;li>
&lt;p>&lt;strong>Git 基础操作&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#git%e5%9f%ba%e6%9c%ac%e4%bd%bf%e7%94%a8" >git基本使用&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e5%a6%82%e6%9e%9c%e6%83%b3%e8%a6%81%e4%b8%b4%e6%97%b6%e6%9f%a5%e7%9c%8b%e6%9f%90%e6%ac%a1commit%e6%97%b6%e9%a1%b9%e7%9b%ae%e7%9a%84%e5%85%a8%e9%83%a8%e4%bb%a3%e7%a0%81" >如果想要临时查看某次commit时项目的全部代码&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e5%9c%a8%e6%9c%ac%e5%9c%b0%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83%e6%a3%80%e6%9f%a5%e8%bf%9c%e7%a8%8b%e6%98%af%e5%90%a6%e6%9b%b4%e6%96%b0" >在本地开发环境检查远程是否更新&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>远程仓库操作&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#git-clone-%e8%bf%9c%e7%a8%8b%e9%a1%b9%e7%9b%ae%e5%90%8c%e6%ad%a5%e8%bf%9c%e7%a8%8b%e9%a1%b9%e7%9b%ae%e6%9b%b4%e6%96%b0" >git clone 远程项目,同步远程项目更新&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#git-%e7%89%88%e6%9c%ac%e6%a0%87%e7%ad%be" >git 版本标签&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>分支与合并&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#git-merge%e8%af%a6%e8%a7%a3" >git merge详解&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#git-pullmerge-git-%e5%a4%9a%e4%ba%ba%e5%8d%8f%e4%bd%9c%e7%9a%84%e6%97%b6%e5%80%99%e6%80%8e%e4%b9%88%e8%a7%a3%e5%86%b3%e5%86%b2%e7%aa%81" >git pull merge git 多人协作的时候怎么解决冲突？&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e4%bd%bf%e7%94%a8rebase%e8%b0%83%e6%8d%a2%e6%9c%80%e5%90%8e%e4%b8%a4%e4%b8%aaCommit%e7%9a%84%e9%a1%ba%e5%ba%8f" >使用rebase调换最后两个Commit的顺序&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e8%bd%af%e4%bb%b6%e7%89%88%e6%9c%ac%e7%ae%a1%e7%90%86%e4%b8%8e%e7%83%ad%e4%bf%ae%e5%a4%8d%e6%b5%81%e7%a8%8b" >软件版本管理与热修复流程&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>版本回退与撤销&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#git-reset---hard-head-%e8%af%a6%e8%a7%a3andgit-reset---soft-head-%e8%af%a6%e8%a7%a3" >git reset &amp;ndash;hard HEAD^ 详解&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e6%81%a2%e5%a4%8d%e8%a2%ab-git-%e5%90%88%e5%b9%b6%e8%a6%86%e7%9b%96%e7%9a%84%e6%8f%90%e4%ba%a4%e5%b9%b6%e9%98%b2%e6%ad%a2%e6%9c%aa%e6%9d%a5%e8%a6%86%e7%9b%96" >恢复被 Git 合并覆盖的提交并防止未来覆盖&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e5%bd%93%e5%89%8d%e6%ad%a3%e5%9c%a8%e8%bf%9b%e8%a1%8c%e4%bb%a3%e7%a0%81%e7%9a%84%e5%bc%80%e5%8f%91%e4%bd%86%e6%98%af%e6%83%b3%e8%a6%81%e7%9c%8b%e5%8e%86%e5%8f%b2commit%e7%9a%84%e9%a1%b9%e7%9b%ae%e5%ae%8c%e6%95%b4%e4%bb%a3%e7%a0%81%e8%80%8c%e5%bd%93%e5%89%8d%e7%9a%84%e5%b7%a5%e4%bd%9c%e5%8c%ba%e4%bf%9d%e8%af%81%e5%8e%9f%e6%a0%b7" >当前正在进行代码的开发，但是想要看历史commit的项目完整代码，而当前的工作区保证原样&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e5%9c%a8-git-%e4%b8%ad%e5%a6%82%e6%9e%9c%e4%bd%a0%e6%83%b3%e5%9b%9e%e9%80%80%e5%88%b0%e4%b8%8a%e4%b8%80%e4%b8%aa%e7%89%88%e6%9c%ac%e7%bb%a7%e7%bb%ad%e5%bc%80%e5%8f%91%e5%90%8c%e6%97%b6%e4%bf%9d%e7%95%99%e5%b7%b2%e7%bb%8f%e6%8f%90%e4%ba%a4%e5%88%b0-main-%e5%88%86%e6%94%af%e7%9a%84%e6%9c%80%e6%96%b0%e6%8f%90%e4%ba%a4%e5%8f%af%e4%bb%a5%e9%80%9a%e8%bf%87%e5%88%9b%e5%bb%ba%e6%96%b0%e5%88%86%e6%94%af%e5%b9%b6%e5%9b%9e%e9%80%80%e7%9a%84%e6%96%b9%e5%bc%8f%e5%ae%9e%e7%8e%b0" >回退到上一个版本继续开发的方案&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e5%a4%9a%e8%bd%ae%e4%bb%a3%e7%a0%81%e6%8f%90%e4%ba%a4%e5%90%8e%e6%89%8d%e5%8f%91%e7%8e%b0%e9%87%8d%e5%a4%a7Bug%e5%a6%82%e4%bd%95%e4%bc%98%e9%9b%85%e5%9c%b0%e4%bf%ae%e6%94%b9%e4%b8%8a%e4%b8%8a%e4%b8%aa-Commit" >多轮代码提交后才发现重大Bug？如何优雅地修改“上上个” Commit&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>GitHub 相关&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#%e5%85%ac%e5%bc%8f-github-github%e4%b8%8d%e6%98%be%e7%a4%bamd%e6%96%87%e4%bb%b6%e4%b8%ad%e7%9a%84%e5%85%ac%e5%bc%8f" >公式 github github不显示md文件中的公式&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#github-%e5%88%86%e6%94%af%e4%bf%9d%e6%8a%a4%e8%a7%84%e5%88%99rulesets%e9%85%8d%e7%bd%ae" >GitHub 分支保护规则（Rulesets）配置&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://mp.weixin.qq.com/s/TEjkisB-s2p-KD_OHS-fnQ" target="_blank" rel="noopener"
>Git 进阶教程(git lfs)：从“版本控制”到“内容追踪”&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>身份验证&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#git-%e4%bd%bf%e7%94%a8ssh%e5%af%86%e9%92%a5%e7%99%bb%e5%bd%95github" >git 使用ssh密钥登录github&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#git-%e4%bd%bf%e7%94%a8token%e7%99%bb%e5%bd%95github-%e5%b9%b6%e6%8b%89%e5%8f%96%e9%a1%b9%e7%9b%ae%e5%a6%82%e6%9e%9c%e7%94%b5%e8%84%91%e4%b8%8a%e5%b7%b2%e7%bb%8f%e7%99%bb%e5%bd%95%e8%bf%87%e4%ba%86%e9%9c%80%e8%a6%81%e6%8a%8a%e8%b4%a6%e6%88%b7%e4%bf%a1%e6%81%af%e6%b8%85%e9%99%a4%e6%8e%89%e5%a6%82%e6%9e%9c%e6%98%af%e7%94%a8ssh%e5%af%86%e9%92%a5%e7%99%bb%e5%bd%95%e7%9a%84%e4%b9%9f%e4%b8%8d%e8%a1%8c%e6%b8%85%e9%99%a4token%e8%b4%a6%e6%88%b7%e4%bf%a1%e6%81%af%e8%af%b7%e7%9c%8b%e4%b8%8b%e9%9d%a2%e6%b8%85%e9%99%a4%e7%94%b5%e8%84%91%e4%b8%8a%e5%b7%b2%e7%bb%8f%e7%99%bb%e5%bd%95%e7%9a%84github%e8%b4%a6%e6%88%b7%e4%bf%a1%e6%81%af" >git 使用token登录github 并拉取项目&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#github-%e8%a6%81%e6%b1%822fa%e8%ae%a4%e8%af%81" >github 要求2FA认证&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#github-%e6%b8%85%e9%99%a4%e7%94%b5%e8%84%91%e4%b8%8a%e5%b7%b2%e7%bb%8f%e7%99%bb%e5%bd%95%e7%9a%84github%e8%b4%a6%e6%88%b7%e4%bf%a1%e6%81%af" >github 清除电脑上已经登录的github账户信息&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#git-config---global---add-safe-directory-%e8%ae%be%e7%bd%ae%e5%ae%89%e5%85%a8%e7%9b%ae%e5%bd%95" >git config &amp;ndash;global &amp;ndash;add safe.directory 设置安全目录&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>问题解决&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#%e8%a7%a3%e5%86%b3mac%e3%80%81linux%e4%b8%8b%e4%bd%bf%e7%94%a8git%e5%91%bd%e4%bb%a4%e6%97%b6%e4%b8%ad%e6%96%87%e4%b9%b1%e7%a0%81%e7%9a%84%e5%8a%9e%e6%b3%95" >解决Mac、linux下使用git命令时中文乱码的办法&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e8%a6%81%e5%b0%86%e8%bf%9c%e7%a8%8b%e4%bb%93%e5%ba%93%e7%9a%84-other-%e5%88%86%e6%94%af%e8%ae%be%e7%bd%ae%e4%b8%ba-main-%e5%88%86%e6%94%af%e5%b9%b6%e5%88%a0%e9%99%a4%e5%8e%9f%e6%9d%a5%e7%9a%84-main-%e5%88%86%e6%94%af%e5%8f%af%e4%bb%a5%e6%8c%89%e7%85%a7%e4%bb%a5%e4%b8%8b%e6%ad%a5%e9%aa%a4%e6%93%8d%e4%bd%9c" >要将远程仓库的 other 分支设置为 main 分支&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e4%bd%bf%e7%94%a8windows%e7%b3%bb%e7%bb%9f%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%81%9a%e8%bf%9c%e7%a8%8b%e5%bc%80%e5%8f%91%e7%a2%b0%e5%88%b0%e7%9a%84%e9%97%ae%e9%a2%98" >使用windows系统服务器做远程开发碰到的问题&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#git-clone-%e5%87%ba%e7%8e%b0%e4%bb%a5%e4%b8%8b%e9%97%ae%e9%a2%98fatal-unable-to-access-xxx-gnutls_handshake-failed-the-tls-connection-was-non-properly-terminated" >git clone 出现TLS连接错误&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#git-push-ssh-connect-to-host-githubcom-port-22-connection-timed-out-fatal-could-not" >git push ssh连接超时问题&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e8%bf%9c%e7%a8%8b%e5%88%86%e6%94%af%e6%98%afv3%e7%89%88%e6%9c%ac%e6%9c%ac%e5%9c%b0%e7%9a%84v2%e7%89%88%e6%9c%ac%e4%bd%86%e6%98%af%e6%9c%ac%e5%9c%b0%e4%bf%ae%e6%94%b9%e4%ba%86%e6%96%87%e4%bb%b6%e8%bf%98%e6%b2%a1%e6%9c%89add%e4%b9%9f%e6%b2%a1%e6%9c%89commit%e5%ba%94%e8%af%a5%e6%80%8e%e4%b9%88%e6%9b%b4%e6%96%b0%e6%9c%ac%e5%9c%b0" >远程分支版本冲突问题&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e7%94%a8git-hooks%e8%a7%a3%e5%86%b3github%e5%a4%a7%e6%96%87%e4%bb%b6%e6%8a%a5%e9%94%99100m%e9%99%90%e5%88%b6%e6%88%9650m%e9%99%90%e5%88%b6%e5%a4%a7%e6%96%87%e4%bb%b650mgit-hooksgit" >用git hooks解决github大文件报错&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e4%ba%91%e6%9c%8d%e5%8a%a1%e5%99%a8%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%aegithub%e5%af%bc%e8%87%b4git%e5%a4%b1%e8%b4%a5%e6%96%b9%e6%a1%88" >云服务器无法访问Github导致git失败方案&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#git-pull-%e6%97%b6%e5%87%ba%e7%8e%b0-cannot-lock-ref-%e9%94%99%e8%af%af%e7%9a%84%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" >git pull 时出现 &amp;ldquo;cannot lock ref&amp;rdquo; 错误的解决方案&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#Git-%e6%97%a0%e6%b3%95%e8%af%86%e5%88%ab%e6%96%87%e4%bb%b6%e5%90%8d%e5%a4%a7%e5%b0%8f%e5%86%99%e6%9b%b4%e6%94%b9%e4%b8%80%e6%96%87%e5%bd%bb%e5%ba%95%e8%a7%a3%e5%86%b3%e9%87%8d%e5%91%bd%e5%90%8d%e9%9a%be%e9%a2%98" >解决 Git 未检测文件名大小写变化的问题&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#githook%e8%84%9a%e6%9c%ac%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6%e7%ae%a1%e7%90%86" >githook脚本版本控制管理&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e7%94%a8githooks%e8%a7%a3%e5%86%b3github%e5%a4%a7%e6%96%87%e4%bb%b6%e6%8a%a5%e9%94%99100M%e9%99%90%e5%88%b6%e6%88%9650M%e9%99%90%e5%88%b6-%e5%a4%a7%e6%96%87%e4%bb%b6-50M-githooks-git" >用git hooks解决github大文件报错，100M限制或50M限制|大文件|50M|git hooks|git&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#cannot_lock_ref_error" >error: cannot lock ref &amp;lsquo;refs/remotes/XXX/main&amp;rsquo;: is at XXX&amp;hellip;XXX but expected YYY&amp;hellip;YYY 解决&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e4%b8%80%e4%b8%aa%e7%94%b5%e8%84%91%e6%83%b3%e8%a6%81%e5%90%8c%e6%97%b6%e4%bd%bf%e7%94%a8%e4%b8%a4%e4%b8%aagithub%e8%b4%a6%e5%8f%b7ssh%e7%99%bb%e5%bd%95" >一个电脑想要同时使用两个github账号ssh登录&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>实战&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="#Git%e9%a1%b9%e7%9b%ae%e4%be%9d%e8%b5%96%e7%ae%a1%e7%90%86-Submodule%e4%b8%8eSubtree%e5%ae%9e%e6%88%98%e6%95%99%e7%a8%8b" >Git 项目依赖管理：Submodule 与 Subtree 实战教程&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="#%e5%a6%82%e4%bd%95%e5%b0%86clone%e4%b8%8b%e6%9d%a5%e7%9a%84%e9%a1%b9%e7%9b%ae%e6%8e%a8%e9%80%81%e5%88%b0%e8%87%aa%e5%b7%b1%e7%9a%84%e6%96%b0%e4%bb%93%e5%ba%93%e5%b9%b6%e5%90%8c%e6%ad%a5%e5%8e%9f%e5%a7%8b%e4%bb%93%e5%ba%93%e6%9b%b4%e6%96%b0" >如何将 clone 下来的项目推送到自己的新仓库并同步原始仓库更新&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="git基本使用">git基本使用
&lt;/h2>&lt;p>安装&lt;/p>
&lt;ol>
&lt;li>windows 安装&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-30.png"
width="870"
height="680"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-30_hu10250126752463687867.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-30_hu4927639420476342210.png 1024w"
loading="lazy"
alt="推荐使用便携版"
class="gallery-image"
data-flex-grow="127"
data-flex-basis="307px"
>
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-31.png"
width="1019"
height="575"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-31_hu16225620278392027579.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-31_hu1081102384893208144.png 1024w"
loading="lazy"
alt="bin目录添加到环境变量"
class="gallery-image"
data-flex-grow="177"
data-flex-basis="425px"
>&lt;/p>
&lt;ol start="2">
&lt;li>简单常用命令&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%设置用户签名%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global user.name &lt;span class="o">[&lt;/span>username&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global user.email &lt;span class="o">[&lt;/span>useremail&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%设置对于非ASCII字符的显示方式%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config--global core.quotepath &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%设置init分支名%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global init.defaultBranch main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git branch --set-upstream-to&lt;span class="o">=&lt;/span>origin/&amp;lt;远程分支&amp;gt; &amp;lt;本地分支&amp;gt; &lt;span class="c1"># 绑定本地分支和远程分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 设置 HTTP/HTTPS 代理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global http.proxy http://127.0.0.1:7890
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global https.proxy http://127.0.0.1:7890
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 或者设置 SOCKS5 代理（更稳定）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global http.proxy socks5://127.0.0.1:7890
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull --rebase &lt;span class="c1"># 变基拉取&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git stash push --keep-index &lt;span class="c1">#只 stash 未暂存但已跟踪的修改 加-u 参数同时 stash 未跟踪文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git stash pop &lt;span class="c1"># 恢复被 stash 的未暂存部分&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 或&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git stash apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote prune &amp;lt;remote-name&amp;gt; &lt;span class="c1"># 清理本地仓库中对远程仓库 zata 已删除分支的过时跟踪引用。 并不是删除分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git gc --prune&lt;span class="o">=&lt;/span>now &lt;span class="c1">#清理不必要的文件并优化本地仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%% 设置远端库别名
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote add &amp;lt;别名&amp;gt; &amp;lt;网址&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%% 查看远端库
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote -v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%获取远程仓库的所有更新，并删除本地已经不存在的远程分支的跟踪引用，以保持本地仓库与远程仓库的同步
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch --prune
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%查看本地库状态%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%追踪文件，放入暂存区%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add &lt;span class="o">[&lt;/span>filename&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add . &lt;span class="c1">#所有文件放入暂存区&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%撤销追踪%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git restore 【file】
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%删除暂存区的文件%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rm --cache 【filename】
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%提交本地库%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;[提交信息]&amp;#34;&lt;/span> 【文件名（可以不加）】
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%撤销commit提交%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git reset --soft HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%推送远程库
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push &lt;span class="o">[&lt;/span>&amp;lt;远程主机名&amp;gt;&lt;span class="o">]&lt;/span> &lt;span class="o">[&lt;/span>&amp;lt;本地分支&amp;gt;:&amp;lt;远程分支&amp;gt;&lt;span class="o">]&lt;/span> &lt;span class="c1">#如果不加分支对应信息就默认上次记录的全部分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin &lt;span class="k">$(&lt;/span>git branch --show-current&lt;span class="k">)&lt;/span> &lt;span class="c1"># 将当前分支推送到远程仓库（通常是 `origin`），并保持相同的分支名&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%拉取远程库%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull &lt;span class="o">[&lt;/span>&amp;lt;远程主机名&amp;gt;&lt;span class="o">]&lt;/span> &lt;span class="o">[&lt;/span>&amp;lt;远程分支&amp;gt;:&amp;lt;本地分支&amp;gt;&lt;span class="o">]&lt;/span> &lt;span class="c1"># 从远程仓库（名为 origin）的 main 分支拉取代码并自动与本地的 main 分支合并 ,如果方括号里面的不加就默认拉去上一次的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull &lt;span class="o">[&lt;/span>&amp;lt;远程主机名&amp;gt;&lt;span class="o">]&lt;/span> --depth &amp;lt;分支深度&amp;gt; &lt;span class="o">[&lt;/span>&amp;lt;远程分支&amp;gt;:&amp;lt;本地分支&amp;gt;&lt;span class="o">]&lt;/span> &lt;span class="c1"># 例如git pull zata --depth 1 hugo:hugo ，用于历史内容过多，只拉取少量历史记录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%查看引用日志版本信息%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git reflog
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%查看详细日志%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git log
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%以图形化方式查看本地和远程分支的结构%%
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git log --graph --oneline --all --remotes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">%%版本穿梭%% 一般用soft多一点
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git reset --hard 【版本号】
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git log --oneline --graph --all &lt;span class="c1"># 显示所有分支的提交记录建议直接使用gitG&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">--.gitignore--------------------
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">test* 忽略以test开头的文件
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="一些问题解决">一些问题解决
&lt;/h2>&lt;h3 id="git-rebase-冲突解决vs-code-----20260308">Git Rebase 冲突解决（VS Code） &amp;mdash; 20260308
&lt;/h3>&lt;p>当你执行 &lt;code>git rebase &amp;lt;目标分支&amp;gt;&lt;/code> 开始变基后，Git 会尝试将你的提交依次应用到目标分支上。如果在这个过程中发生代码冲突，Git 会自动暂停变基操作，等待你解决冲突。&lt;/p>
&lt;p>此时，VS Code 会清晰地提示你当前状态：&lt;/p>
&lt;ul>
&lt;li>文件列表中被检测到冲突的文件旁边会出现警告标记（⚠️）。&lt;/li>
&lt;li>编辑器底部状态栏会显示“合并冲突”的提示。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>解决冲突的核心步骤分为以下环节：&lt;/strong>&lt;/p>
&lt;p>&lt;strong>第一步：打开并处理冲突文件&lt;/strong>
在编辑器中打开有冲突标记的文件，你会看到类似以下结构的代码块：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">这是你当前分支（正在变基的提交）的代码
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">=======
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">这是来自目标分支（或历史提交中）的代码
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; commit-hash
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你需要决定如何整合这些代码。你有两种主要方式来完成这一步：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>使用 VS Code 内置工具&lt;/strong>：直接点击冲突标记区域上方出现的选项按钮。你可以选择“接受当前更改”、“接受传入更改”或“保留双方更改”。如果内置选项不能满足需求，你也可以手动删除所有的 &lt;code>&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/code>、&lt;code>=======&lt;/code> 和 &lt;code>&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code> 标记，并编辑成你最终想要的代码。&lt;/li>
&lt;li>&lt;strong>使用 GitLens 扩展&lt;/strong>：如果你安装了 GitLens 扩展，它会提供更加强大和直观的并排对比视图，方便你逐块检查和解决冲突。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>第二步：标记冲突文件为已解决&lt;/strong>
在完成一个文件的所有冲突编辑后，你需要告诉 Git 这个文件的冲突已经处理完毕。&lt;/p>
&lt;ul>
&lt;li>你可以在 VS Code 的源代码管理侧边栏（√图标）中，找到该文件，点击旁边的“+”号或右键选择“暂存更改”。&lt;/li>
&lt;li>或者在终端中执行命令 &lt;code>git add &amp;lt;文件名&amp;gt;&lt;/code>。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>第三步：继续变基过程&lt;/strong>
标记完所有已解决的冲突文件后，你需要让 Git 继续执行变基操作。&lt;/p>
&lt;ul>
&lt;li>在 VS Code 中，你可以点击底部状态栏的“继续变基”按钮。&lt;/li>
&lt;li>或者在终端中执行命令 &lt;code>git rebase --continue&lt;/code>。&lt;/li>
&lt;/ul>
&lt;p>随后，Git 会尝试应用下一个提交，你可能需要重复上述步骤来解决后续可能出现的冲突，直到所有提交都应用完成。&lt;/p>
&lt;p>&lt;strong>其他有用的命令&lt;/strong>
在变基过程中，你还可以使用以下命令：&lt;/p>
&lt;ul>
&lt;li>&lt;code>git rebase --skip&lt;/code>：跳过当前正在应用的提交（请谨慎使用，这意味着完全丢弃这个提交的更改）。&lt;/li>
&lt;li>&lt;code>git rebase --abort&lt;/code>：完全终止本次变基操作，分支将回退到执行 &lt;code>git rebase&lt;/code> 之前的状态。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>快速流程总结&lt;/strong>
一个典型的 rebase 解决冲突流程可以简化为：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">git rebase main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 发生冲突
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 使用 VS Code 编辑文件解决冲突
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase --continue
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 可能重复“编辑-&amp;gt;add-&amp;gt;continue”直到完成
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>最后的重要提示&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>变基过程可能需要解决多个提交引发的冲突，请耐心处理完一个后继续下一个。&lt;/li>
&lt;li>随时可以使用 &lt;code>git status&lt;/code> 命令来查看当前的变基进度和状态。&lt;/li>
&lt;li>在进行变基等重写历史的操作前，创建一个备份分支是一个好习惯：&lt;code>git checkout -b backup-branch&lt;/code>。&lt;/li>
&lt;/ul>
&lt;h3 id="解决maclinux下使用git命令时中文乱码的办法">解决Mac、linux下使用git命令时中文乱码的办法
&lt;/h3>&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-22.png"
width="966"
height="706"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-22_hu7184100398968431327.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-22_hu327649835395407819.png 1024w"
loading="lazy"
alt="中文乱码"
class="gallery-image"
data-flex-grow="136"
data-flex-basis="328px"
>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config --global core.quotepath &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="要将远程仓库的-other-分支设置为-main-分支并删除原来的-main-分支可以按照以下步骤操作">要将远程仓库的 &lt;code>other&lt;/code> 分支设置为 &lt;code>main&lt;/code> 分支，并删除原来的 &lt;code>main&lt;/code> 分支，可以按照以下步骤操作：
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>确保本地仓库是最新的&lt;/strong>
首先，确保你的本地仓库与远程仓库同步，并切换到 &lt;code>other&lt;/code> 分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout other
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull origin other
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>将 &lt;code>other&lt;/code> 分支推送到远程的 &lt;code>main&lt;/code> 分支&lt;/strong>
使用 &lt;code>git push&lt;/code> 的 &lt;code>--force&lt;/code> 选项，将 &lt;code>other&lt;/code> 分支的内容强制覆盖远程的 &lt;code>main&lt;/code> 分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push origin other:main --force
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这会将 &lt;code>other&lt;/code> 分支的内容直接推送到远程的 &lt;code>main&lt;/code> 分支，覆盖原有的 &lt;code>main&lt;/code> 分支。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>更新本地仓库&lt;/strong>
在本地仓库中，确保你的 &lt;code>main&lt;/code> 分支与远程的 &lt;code>main&lt;/code> 分支同步：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>删除本地的 &lt;code>other&lt;/code> 分支（可选）&lt;/strong>
如果你不再需要本地的 &lt;code>other&lt;/code> 分支，可以删除它：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git branch -d other
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>验证操作&lt;/strong>
确认远程仓库的分支状态：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git branch -r
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你应该看到 &lt;code>origin/main&lt;/code> 包含了 &lt;code>other&lt;/code> 分支的内容，且 &lt;code>origin/other&lt;/code> 仍然存在（除非你也想删除它）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>（可选）删除远程的 &lt;code>other&lt;/code> 分支&lt;/strong>
如果 &lt;code>other&lt;/code> 分支不再需要，可以删除远程的 &lt;code>other&lt;/code> 分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push origin --delete other
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;h3 id="使用windows系统服务器做远程开发碰到的问题">使用windows系统服务器做远程开发碰到的问题
&lt;/h3>&lt;ul>
&lt;li>
&lt;p>使用哪个版本的git&lt;/p>
&lt;p>感觉这个没有太大关系，不过后面发现便携版本的git也是可用的，感觉以后可以就使用便携版的，毕竟不需要界面&lt;/p>
&lt;/li>
&lt;li>
&lt;p>使用windows远程服务器进行git pull总是卡死&lt;/p>
&lt;p>2025年0617，买了一个腾讯云到2h2G服务器，想用来写hugo博客， 但是在pull代码的时候总是卡死，试了很多次，我以为是服务器性能太烂了，最后发现，如果使用http地址pull的话就没有问题。但是后面又发现使用github的http地址的话会存在无法push的情况，所以我最终给出的解决方案就是：使用github的http地址拉取项目，然后使用ssh地址同步
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-18.png"
width="2576"
height="560"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-18_hu14672072072689613467.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-18_hu17718580601840178516.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="460"
data-flex-basis="1104px"
>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="如果想要临时查看某次commit时项目的全部代码">如果想要临时查看某次commit时项目的全部代码
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git log --oneline
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout &amp;lt;commit哈希值&amp;gt; &lt;span class="c1"># 查看代码&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout main &lt;span class="c1"># 返回主分支&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="在本地开发环境检查远程是否更新">在本地开发环境检查远程是否更新
&lt;/h3>&lt;p>第一种方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">git log --oneline --graph --all
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第二种方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 设置跟踪远程分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git branch --set-upstream-to&lt;span class="o">=&lt;/span>origin/&amp;lt;branch&amp;gt; &amp;lt;branch&amp;gt; &lt;span class="c1"># git branch --set-upstream-to=origin/main main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查看是否跟踪&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git branch -vv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 下载数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查看是否有更新&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>是否跟踪对比&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-14.png"
width="644"
height="49"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-14_hu3664483552206992883.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-14_hu2295860765431715334.png 1024w"
loading="lazy"
alt="未跟踪"
class="gallery-image"
data-flex-grow="1314"
data-flex-basis="3154px"
>
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-13.png"
width="706"
height="110"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-13_hu4425906168980590616.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-13_hu7726638049079455134.png 1024w"
loading="lazy"
alt="已经跟踪"
class="gallery-image"
data-flex-grow="641"
data-flex-basis="1540px"
>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-15.png"
width="435"
height="96"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-15_hu14661769001706881027.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-15_hu10722412028536629420.png 1024w"
loading="lazy"
alt="可以看见本地和远程分支状态"
class="gallery-image"
data-flex-grow="453"
data-flex-basis="1087px"
>&lt;/p>
&lt;h3 id="git-clone-远程项目同步远程项目更新">git clone 远程项目,同步远程项目更新
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">git fetch origin &lt;span class="c1">#查看远程项目更新&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull origin 远程分支：本地分支
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="git-版本标签">git 版本标签
&lt;/h3>&lt;ol>
&lt;li>什么是版本标签？
标签（Tag） 是 Git 中的一个引用（reference），指向某个特定的提交。
它通常用于标记一个稳定的发布版本，比如 v1 表示第一个正式版本。
在 GitHub 上，标签还会显示在 Releases 页面，便于用户下载或查看。
两种标签类型
轻量标签（Lightweight Tag）：只是一个简单的指针，指向某个提交，不包含额外信息。
附注标签（Annotated Tag）：包含额外元数据（如创建者、日期、描述），更常用于正式发布。&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 假设你已经完成代码更改并提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Finalize version 1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建一个轻量标签（简单标记当前提交）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git tag v1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 或者创建一个附注标签（带描述信息，推荐用于正式发布）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git tag -a v1 -m &lt;span class="s2">&amp;#34;Release version 1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查看所有本地标签&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git tag
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 推送单个标签到远程仓库（如 GitHub）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin v1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 或者推送所有标签到远程仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin --tags
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># （可选）如果需要删除本地标签&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git tag -d v1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># （可选）如果需要删除远程标签&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin --delete v1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="git-merge详解">git merge详解
&lt;/h3>&lt;p>如果没有冲突，Git 会自动完成合并，并创建一个合并提交（merge commit，如果需要的话）。如果有冲突，Git 会暂停合并，提示你解决冲突（后面会讲怎么处理）。&lt;/p>
&lt;ol>
&lt;li>无冲突的合并（Fast-forward）&lt;/li>
&lt;/ol>
&lt;p>如果 main 分支没有额外改动，而 feature 分支只是基于 main 增加了提交，Git 会执行&amp;quot;快进合并&amp;quot;（fast-forward）。这时候历史记录会变成一条直线，看起来像是直接在 main 上开发了一样。&lt;/p>
&lt;ol start="2">
&lt;li>有额外提交的合并（Merge Commit）&lt;/li>
&lt;/ol>
&lt;p>如果 main 和 feature 都有各自的提交，Git 会创建一个新的合并提交，保留两个分支的历史。
命令一样：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git merge &amp;lt;分支名&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>但是，合并后，Git 会自动生成一个 Merge commit，这样，从历史上看，分支信息就非常清楚。&lt;/p>
&lt;ol start="3">
&lt;li>冲突的合并
当两个分支修改了同一文件的同一部分，Git 无法自动决定用哪个版本，就会报冲突。这时你需要手动解决：&lt;/li>
&lt;/ol>
&lt;p>运行 git merge feature 后，Git 会提示冲突文件。
打开这些文件，冲突部分会被标记为：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">（main 分支的内容）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">=======
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">（feature 分支的内容）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; feature
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>编辑文件，保留你想要的部分，删除标记。
解决完后，标记文件为已解决：&amp;ldquo;git add &lt;filename>&amp;quot;，然后提交：&amp;ldquo;git commit -m &amp;lsquo;解决冲突&amp;rsquo;&lt;/p>
&lt;ul>
&lt;li>实用技巧
查看合并状态：用 git status 检查当前是否在合并过程中。
中止合并：如果合并出了问题，想放弃，可以用：&lt;/li>
&lt;/ul>
&lt;p>git merge &amp;ndash;abort&lt;/p>
&lt;ul>
&lt;li>指定合并策略：默认情况下 Git 会自动选择合并方式，但你可以用选项调整，比如强制非快进合并：&lt;/li>
&lt;/ul>
&lt;p>git merge &amp;ndash;no-ff feature&lt;/p>
&lt;h3 id="如何解决-fatal-need-to-specify-how-to-reconcile-divergent-branches-错误">如何解决 &amp;ldquo;fatal: Need to specify how to reconcile divergent branches&amp;rdquo; 错误
&lt;/h3>&lt;p>问题根源：什么是“分支分叉”？&lt;/p>
&lt;p>这个错误的核心原因是：&lt;strong>您的本地分支和它所跟踪的远程分支，各自都有了新的、对方不知道的提交。&lt;/strong>&lt;/p>
&lt;p>让我们用一个形象的例子来说明：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>您和您的同事都在 &lt;code>main&lt;/code> 分支上工作。你们最后一次同步时的代码状态是 &lt;code>Commit O&lt;/code>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>之后，您在本地写了新功能，并创建了两个提交 &lt;code>A&lt;/code> 和 &lt;code>B&lt;/code>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>在您提交的这段时间里，您的同事完成了另一个任务，并将他的提交 &lt;code>C&lt;/code> 和 &lt;code>D&lt;/code> 推送（push）到了远程仓库。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>这时，Git 的历史记录就变成了两条独立的路径，即“分叉”了：&lt;/p>
&lt;p>A&amp;mdash;B &amp;lt;&amp;ndash; 您的本地 &lt;code>main&lt;/code> 分支&lt;/p>
&lt;p>/&lt;/p>
&lt;p>&amp;mdash;O&amp;mdash;C&amp;mdash;D &amp;lt;&amp;ndash; 远程 origin/main 分支&lt;/p>
&lt;p>当您执行 &lt;code>git pull&lt;/code> 时，Git 发现它无法简单地“快进”（Fast-forward）来更新您的代码，因为它不知道应该如何处理这两条分叉的路径。为了避免自动操作可能带来的混乱，新版 Git 强制要求您必须明确告诉它您的合并策略。&lt;/p>
&lt;p>二、 核心概念：两种合并策略 Merge vs. Rebase&lt;/p>
&lt;p>要解决分叉问题，您有两种主要的方法：&lt;code>Merge&lt;/code> (合并) 和 &lt;code>Rebase&lt;/code> (变基)。&lt;/p>
&lt;p>方案 A：临时解决本次问题&lt;/p>
&lt;p>您可以只在本次 &lt;code>pull&lt;/code> 命令中指定策略。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>使用 Rebase (推荐)：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull --rebase
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这会用变基的方式拉取并应用远程更新。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>使用 Merge：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull --no-rebase &lt;span class="c1"># 或者 git pull --merge&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这会用传统合并的方式，并生成一个合并提交。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>方案 B：永久配置默认行为 (一劳永逸)&lt;/p>
&lt;p>为了避免每次都输入额外参数，您可以为 Git 设置一个全局的默认 &lt;code>pull&lt;/code> 行为。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>将 Rebase 设置为默认 (推荐)：&lt;/strong>&lt;/p>
&lt;p>如果您喜欢干净的线性历史，这是大多数现代开发者的首选。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global pull.rebase &lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>将 Merge 设置为默认：&lt;/strong>&lt;/p>
&lt;p>如果您偏爱保留所有合并痕迹的传统方式。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global pull.rebase &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>更严格的 &lt;code>ff-only&lt;/code> 策略：&lt;/strong>&lt;/p>
&lt;p>还有一个选项是 &lt;code>fast-forward only&lt;/code>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global pull.ff only
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个设置意味着，只有当您的本地分支没有任何新提交时（即可以“快进”时），&lt;code>git pull&lt;/code> 才能成功。如果分支出现分叉，&lt;code>pull&lt;/code> 会直接失败，强制您手动执行 &lt;code>git rebase&lt;/code> 或 &lt;code>git merge&lt;/code>，让您对每一次合并操作都更加谨慎。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="git-pullmerge-git-多人协作的时候怎么解决冲突">|git pull|merge| git 多人协作的时候怎么解决冲突？
&lt;/h3>&lt;p>使用git-pull 然后git-commit 最后git-push&lt;/p>
&lt;p>如果有冲突可以看&lt;a class="link" href="#git-merge%e8%af%a6%e8%a7%a3" >get merge使用&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/image/git@github/git@github.jpg"
width="1316"
height="1301"
srcset="https://www.zata.cc/p/gitgithub/image/git@github/git@github_hu2912269543672264858.jpg 480w, https://www.zata.cc/p/gitgithub/image/git@github/git@github_hu5581466344476847627.jpg 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="101"
data-flex-basis="242px"
>&lt;/p>
&lt;h3 id="使用rebase调换最后两个commit的顺序">使用rebase调换最后两个Commit的顺序
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Markdown" data-lang="Markdown">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh"># Git 教程：使用 rebase 调换最后两个 Commit 的顺序
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">本教程将指导你如何使用 &lt;span class="sb">`git rebase -i`&lt;/span>（交互式 rebase）来调换你本地最后两个 commit 的顺序。## 场景
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">你通过 &lt;span class="sb">`rebase`&lt;/span> 将你的本地修改放在了远程分支的最新 commit 之上，但你现在希望反过来，让你自己的修改在前面，让远程的 commit 成为最后一个。**你当前的状态 (HEAD 指向你的修改):**
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">... -&amp;gt; 远程的最后一个commit -&amp;gt; 你的本地修改 (HEAD)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gs">**你希望达到的状态 (HEAD 指向远程的 commit):**&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">... -&amp;gt; 你的本地修改 -&amp;gt; 远程的最后一个commit (HEAD)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">---
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">## ⚠️ 重要警告
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">此操作会**重写 Git 历史**。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gs">**请只在尚未将这些 commit 推送（push）到远程仓库时执行此操作。**&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">如果你已经推送了 &lt;span class="sb">`你的本地修改`&lt;/span>，强行修改历史（&lt;span class="sb">`git push --force`&lt;/span>）会给你的协作者带来严重问题。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">---
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">## 操作步骤
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">### 步骤 1: 启动交互式 Rebase
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">你需要编辑最后两个 commit。运行以下命令来启动交互式 rebase，&lt;span class="sb">`HEAD~2`&lt;/span> 表示“从 HEAD 开始往前数 2 个 commit”。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">```bash
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase -i HEAD~2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">步骤 2: 在编辑器中编辑 Rebase 列表
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">运行上述命令后，Git 会打开你的默认文本编辑器，显示一个列表。这个列表的顺序是从旧到新（从上到下）。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">它看起来会是这样：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hash_A&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> 远程的最后一个commit 的消息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hash_B&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> 你的本地修改 的消息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh"># Rebase ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh"># Commands:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh"># p, pick &amp;lt;commit&amp;gt; = use commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh"># ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hash_A&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> 是那个较旧的 commit（远程的 commit）。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hash_B&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> 是那个较新的 commit（你的本地修改）。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">步骤 3: 调换 Commit 顺序
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">你只需要在编辑器中交换这两行的文本顺序，把你的本地修改放到上面（即让它更早发生）：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">修改为：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hash_B&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> 你的本地修改 的消息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hash_A&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> 远程的最后一个commit 的消息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">步骤 4: 保存并退出编辑器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">保存文件并关闭编辑器。Git 会立即按照你指定的新顺序重新应用这两个 commit。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">步骤 5: 验证结果
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">操作完成后，你可以使用 git log 来检查历史记录，确认顺序已经被正确调换。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Bash
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh"># 查看最后两个 commit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gh">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git log --oneline -2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">你现在应该会看到 远程的最后一个commit 的消息 在最上面（最新）的位置。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">附录：如何在编辑器中快速调换行顺序
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">在步骤 3 中，你不需要手动剪切和粘贴。几乎所有编辑器都支持“移动当前行”的快捷键（将光标放在该行任意位置即可）。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">常用 GUI 编辑器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Visual Studio Code (VS Code):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Windows / Linux: Alt + ↑ (上移) / Alt + ↓ (下移)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">macOS: Option + ↑ (上移) / Option + ↓ (下移)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sublime Text:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Windows / Linux: Ctrl + Shift + ↑ (上移) / Ctrl + Shift + ↓ (下移)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">macOS: Cmd + Ctrl + ↑ (上移) / Cmd + Ctrl + ↓ (下移)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Notepad++:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Ctrl + Shift + ↑ (上移) / Ctrl + Shift + ↓ (下移)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">常用终端编辑器 (Git 默认)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Vim / Vi (最常见的默认编辑器):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">按 Esc 键确保你处于普通模式 (Normal Mode)。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">将光标移动到你想移动的行。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">输入 ddp：dd (剪切当前行) + p (粘贴到下一行)，效果是与下一行交换。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">输入 ddkP：dd (剪切) + k (上移) + P (粘贴到上一行)，效果是与上一行交换。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">(在你的场景中，光标在第二行 pick &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">hash_B&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> ... 上时，按 ddkP 即可)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Nano (较简单的编辑器):
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Nano 没有直接的“移动行”快捷键，你必须使用剪切和粘贴：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">将光标放在要移动的行上。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">按 Ctrl + K (剪切该行)。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">将光标移动到目标位置（例如，移动到第一行）。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">按 Ctrl + U (粘贴该行)。
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="公式--github--github不显示md文件中的公式">|公式 | github | github不显示md文件中的公式
&lt;/h3>&lt;p>&lt;code>第一种方法：使用github推荐的公式写法（推荐）&lt;/code>
在写md的时候，使用&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">$` 和 `$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>来包围行内公式&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">```math
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">和
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ```
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>来包围单行公式，如下&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image.png"
width="1348"
height="145"
srcset="https://www.zata.cc/p/gitgithub/images/index/image_hu2980433107614408744.png 480w, https://www.zata.cc/p/gitgithub/images/index/image_hu11750368063988626786.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="929"
data-flex-basis="2231px"
>&lt;/p>
&lt;p>&lt;code>第二种方法： 插件&lt;/code>&lt;/p>
&lt;p>但是还是会有一部分显示不正确
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-1.png"
width="1015"
height="293"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-1_hu993762255634323821.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-1_hu1583790060066129962.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="346"
data-flex-basis="831px"
>&lt;/p>
&lt;p>解决方法：安装插件：https://chrome.google.com/webstore/detail/mathjax-plugin-for-github/ioemnmodlmafdkllaclgeombjnmnbima/related
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-2.png"
width="358"
height="59"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-2_hu14824977159200266602.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-2_hu10950753139731083826.png 1024w"
loading="lazy"
alt="插件名"
class="gallery-image"
data-flex-grow="606"
data-flex-basis="1456px"
>&lt;/p>
&lt;h3 id="git-使用ssh密钥登录github">git 使用ssh密钥登录github
&lt;/h3>&lt;p>&lt;code> 注意一个密钥只能登录一个github，如果你想要在新的github账户上面添加旧的ssh密钥，就会报错&lt;/code>
准备工作：本地先下载安装好git，注册并登陆github账号
在注册好后的github账号中先创建一个仓库
在本地git创建SSH key
第一步：设置全局的用户名和邮箱（这样主要是不用总是重填）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">git&lt;/span> &lt;span class="n">config&lt;/span> &lt;span class="o">--&lt;/span>&lt;span class="n">global&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="err">&amp;#39;用户名&amp;#39;&lt;/span> &lt;span class="c1">// 切换到你的github用户名上
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">git&lt;/span> &lt;span class="n">config&lt;/span> &lt;span class="o">--&lt;/span>&lt;span class="n">global&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">email&lt;/span> &lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">github账号注册用的邮箱&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第二步：生成密钥，有可能提示没有这个库，需要安装一下，去搜索一下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ssh&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">keygen&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">t&lt;/span> &lt;span class="n">rsa&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">C&lt;/span> &lt;span class="s">&amp;#34;你的邮箱地址&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第三步：查看自己本地的密钥，执行以下命令&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ls&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">al&lt;/span> &lt;span class="o">~/&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ssh&lt;/span> &lt;span class="c1">// 查看本机是否有秘钥文件 没有秘钥文件生成秘钥文件
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cd&lt;/span> &lt;span class="o">~/&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ssh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ls&lt;/span> &lt;span class="c1">// 查看 .ssh 中有什么文件
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cat&lt;/span> &lt;span class="n">id_rsa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">pub&lt;/span> &lt;span class="c1">// 查看本地的公钥
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cat&lt;/span> &lt;span class="n">id_rsa&lt;/span> &lt;span class="c1">// 查看本地的私钥
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="err">（如果是&lt;/span>&lt;span class="n">windows系统可以直接到C盘的对应用户名文件夹下的&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ssh文件夹中查看&lt;/span>&lt;span class="err">）&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第四步：将公钥复制粘贴到github上&lt;/p>
&lt;blockquote>
&lt;p>github上点击头像，点击Settings，进入后点击 SSH and GPS keys，接着点击 New SSH key
将公钥粘贴在key输入框那里，Title则随便输入可以就行&lt;/p>
&lt;/blockquote>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-3.png"
width="1327"
height="571"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-3_hu1087538447768357301.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-3_hu6470134803155830141.png 1024w"
loading="lazy"
alt="github ssh"
class="gallery-image"
data-flex-grow="232"
data-flex-basis="557px"
>&lt;/p>
&lt;h3 id="git-使用token登录github-并拉取项目-如果电脑上已经登录过了需要把账户信息清除掉如果是用ssh密钥登录的也不行清除token账户信息请看下面清除电脑上已经登录的github账户信息">&lt;code>git 使用token登录github 并拉取项目&lt;/code> （如果电脑上已经登录过了，需要把账户信息清除掉。&lt;strong>如果是用ssh密钥登录的也不行&lt;/strong>，清除token账户信息请看下面&amp;quot;清除电脑上已经登录的github账户信息&amp;rdquo;）
&lt;/h3>&lt;table>
&lt;tr>
&lt;td >
&lt;img src="images/index/image-4.png" >图1 打开设置
&lt;/td>
&lt;td >
&lt;img src="images/index/image-5.png" >图2 开发者设置
&lt;/td>
&lt;td >
&lt;img src="images/index/image-6.png" >图3 点击Token
&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td >
&lt;img src="images/index/image-7.png" >图4 生成classic Token
&lt;/td>
&lt;td >
&lt;img src="images/index/image-8.png" >图5 设置命名和权限
&lt;/td>
&lt;/tr>
&lt;/table>
&lt;p>&lt;strong>最后一步：&lt;/strong>
在新设备上pull或者push的时候，会让你登录，有两种方式，一种是账号密码，另一种就算token，选择token，然后粘贴上一步生成的token就可以了&lt;/p>
&lt;h3 id="github-要求2fa认证">github 要求2FA认证
&lt;/h3>&lt;p>今天上线的时候突然发现，github要求我设置2FA认证，不然就不能登录，手机号我必然是没有的，只能用安全密钥控制
具体的github说明在这里：https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication&lt;/p>
&lt;p>一句话说，就是需要用TOPT密钥管理工具生成动态密码，然后输入动态密码登录，然后第一次登录会给你一个github-recovery-codes.txt,如果更换设备需要使用这个恢复码登录新设备，然后登录新设备之后也是会给你一个新的恢复码&lt;/p>
&lt;p>如果是第一次登录，看到github要求进行2FA，可以安装如下 chrome插件：Github 2FA（去chrome商店搜索）&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-12.png"
width="1035"
height="813"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-12_hu7404912787645360837.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-12_hu13790825795733162414.png 1024w"
loading="lazy"
alt="Github 2FA应用图标"
class="gallery-image"
data-flex-grow="127"
data-flex-basis="305px"
>&lt;/p>
&lt;p>然后你回到github页面刷新，在上面图片红框的那个位置就会出现一个30s的密码，输入就可以确认，确认好之后会让你下周恢复密钥，记得下载保存&lt;/p>
&lt;h3 id="github-清除电脑上已经登录的github账户信息">github 清除电脑上已经登录的github账户信息
&lt;/h3>&lt;p>step1： 进入控制面板点击用户账户&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-9.png"
width="1123"
height="546"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-9_hu8136748358710120527.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-9_hu13854892858309720935.png 1024w"
loading="lazy"
alt="控制面板-用户账户"
class="gallery-image"
data-flex-grow="205"
data-flex-basis="493px"
>&lt;/p>
&lt;p>step2：管理windows凭证&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-10.png"
width="923"
height="546"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-10_hu11284426244296711471.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-10_hu739297296554875556.png 1024w"
loading="lazy"
alt="windows凭证"
class="gallery-image"
data-flex-grow="169"
data-flex-basis="405px"
>&lt;/p>
&lt;p>step3：删除github相关的凭证&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-11.png"
width="868"
height="275"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-11_hu9565429108820901483.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-11_hu15691339718458112265.png 1024w"
loading="lazy"
alt="删除github凭证"
class="gallery-image"
data-flex-grow="315"
data-flex-basis="757px"
>&lt;/p>
&lt;h3 id="git-config---global---add-safedirectory-设置安全目录">git config &amp;ndash;global &amp;ndash;add safe.directory 设置安全目录
&lt;/h3>&lt;p>命令用途
&lt;code>git config --global --add safe.directory&lt;/code> 命令用于将指定的目录添加到 Git 的安全目录列表中，解决 Git 安全机制导致的仓库访问问题。&lt;/p>
&lt;p>问题背景
从 Git 2.35.2 开始，Git 引入了更严格的安全机制，默认情况下会拒绝访问由其他用户拥有的目录中的 Git 仓库。这通常发生在以下情况：&lt;/p>
&lt;ul>
&lt;li>在 WSL (Windows Subsystem for Linux) 环境中&lt;/li>
&lt;li>在共享目录或挂载的目录中&lt;/li>
&lt;li>在 Docker 容器中访问宿主机目录&lt;/li>
&lt;li>在多用户系统中&lt;/li>
&lt;/ul>
&lt;p>命令语法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config --global --add safe.directory &amp;lt;directory-path&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用示例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 添加单个目录到安全目录列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --add safe.directory /code/GRT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 添加当前目录到安全目录列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --add safe.directory &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>&lt;span class="nb">pwd&lt;/span>&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 添加多个目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --add safe.directory /path/to/repo1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --add safe.directory /path/to/repo2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>查看当前安全目录列表&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查看所有安全目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --get-all safe.directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查看所有全局配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --list &lt;span class="p">|&lt;/span> grep safe.directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>删除安全目录&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 删除特定的安全目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --unset-all safe.directory /code/GRT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 删除所有安全目录配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global --unset-all safe.directory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>常见错误信息
当遇到安全目录问题时，Git 会显示类似以下的错误：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">fatal: detected dubious ownership in repository at &amp;#39;/code/GRT&amp;#39;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">To add an exception for this directory, call:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> git config --global --add safe.directory /code/GRT
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>安全注意事项&lt;/p>
&lt;ol>
&lt;li>&lt;strong>谨慎添加目录&lt;/strong>：只添加你信任的目录，避免添加系统关键目录&lt;/li>
&lt;li>&lt;strong>使用绝对路径&lt;/strong>：建议使用绝对路径而不是相对路径&lt;/li>
&lt;li>&lt;strong>定期检查&lt;/strong>：定期检查安全目录列表，删除不再需要的目录&lt;/li>
&lt;li>&lt;strong>环境隔离&lt;/strong>：在不同环境中使用不同的安全目录配置&lt;/li>
&lt;/ol>
&lt;p>替代方案
如果不想使用全局配置，也可以：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>使用本地配置&lt;/strong>：在特定仓库中使用 &lt;code>--local&lt;/code> 而不是 &lt;code>--global&lt;/code>&lt;/li>
&lt;li>&lt;strong>修改目录权限&lt;/strong>：确保目录的所有权正确&lt;/li>
&lt;li>&lt;strong>使用 Git 环境变量&lt;/strong>：设置 &lt;code>GIT_SAFE_DIRECTORIES&lt;/code> 环境变量&lt;/li>
&lt;/ol>
&lt;p>验证配置
配置完成后，可以验证是否生效：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 进入目标目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /code/GRT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 尝试执行 Git 命令&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 如果没有错误信息，说明配置成功&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="github-分支保护规则rulesets配置">GitHub 分支保护规则（Rulesets）配置
&lt;/h3>&lt;p>在团队协作中，保护主分支（如 &lt;code>main&lt;/code>）是非常重要的一项最佳实践。GitHub 提供了 &lt;strong>Rulesets&lt;/strong>（规则集）功能，可以灵活地配置分支保护策略，而无需启用组织级别的付费功能。&lt;/p>
&lt;p>下面介绍两种常见的配置方案：&lt;/p>
&lt;p>&lt;strong>方案一：极简保护（防删 + 防强制推送）&lt;/strong>&lt;/p>
&lt;p>适用于个人仓库或小型项目，仅开启最核心的两项保护：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Restrict deletions&lt;/strong> — 限制删除匹配的分支，防止误删主分支。&lt;/li>
&lt;li>&lt;strong>Block force pushes&lt;/strong> — 阻止强制推送，避免历史被覆盖。&lt;/li>
&lt;/ul>
&lt;p>配置截图如下：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-32.png"
width="1072"
height="1806"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-32_hu6418344265277619561.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-32_hu16847788663928288651.png 1024w"
loading="lazy"
alt="极简分支保护"
class="gallery-image"
data-flex-grow="59"
data-flex-basis="142px"
>&lt;/p>
&lt;p>&lt;strong>方案二：严格保护（推荐用于团队项目）&lt;/strong>&lt;/p>
&lt;p>适用于多人协作的项目，要求更规范的代码合入流程：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Restrict deletions&lt;/strong> — 限制删除分支。&lt;/li>
&lt;li>&lt;strong>Require a pull request before merging&lt;/strong> — 必须通过 Pull Request 才能合并代码。&lt;/li>
&lt;li>&lt;strong>Require status checks to pass&lt;/strong> — 要求指定的 CI 检查通过后才能合并。例如：
&lt;ul>
&lt;li>&lt;code>Python Quality Gate&lt;/code>&lt;/li>
&lt;li>&lt;code>Frontend Build&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Block force pushes&lt;/strong> — 阻止强制推送。&lt;/li>
&lt;/ul>
&lt;p>配置截图如下：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-33.png"
width="1072"
height="3033"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-33_hu11611640907184866084.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-33_hu16811386978142832023.png 1024w"
loading="lazy"
alt="严格分支保护"
class="gallery-image"
data-flex-grow="35"
data-flex-basis="84px"
>&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>提示&lt;/strong>：Rulesets 对私有仓库完全免费即可使用。对于团队项目，建议至少开启「Require a pull request before merging」和「Require status checks to pass」，以保证代码质量和审计追踪。&lt;/p>
&lt;/blockquote>
&lt;h3 id="git-clone-出现以下问题fatal-unable-to-access-xxx-gnutls_handshake-failed-the-tls-connection-was-non-properly-terminated">&lt;code>git clone 出现以下问题：fatal: unable to access XXX: gnutls_handshake() failed: The TLS connection was non-properly terminated.&lt;/code>
&lt;/h3>&lt;p>&lt;code>git clone 出现以下问题：fatal: unable to access 'https://github.com/QwenLM/Qwen.git/': gnutls_handshake() failed: The TLS connection was non-properly terminated.&lt;/code>&lt;/p>
&lt;p>可以参考stack overflow里面的&lt;a class="link" href="https://stackoverflow.com/questions/68801315/gnutls-handshake-failed-the-tls-connection-was-non-properly-terminated-while" target="_blank" rel="noopener"
>Stack&lt;/a>
我是执行下面两行代码解决（ubuntu系统）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">apt&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">get&lt;/span> &lt;span class="n">update&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">apt&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">get&lt;/span> &lt;span class="n">install&lt;/span> &lt;span class="n">curl&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="git-push-ssh-connect-to-host-githubcom-port-22-connection-timed-out-fatal-could-not">&lt;code>[git push] ssh: connect to host github.com port 22: Connection timed out fatal: Could not....&lt;/code>
&lt;/h3>&lt;p>最有可能是防火墙问题，可以参考github官方的解决方法 用443端口解决
&lt;a class="link" href="https://docs.github.com/en/authentication/troubleshooting-ssh/using-ssh-over-the-https-port" target="_blank" rel="noopener"
>https://docs.github.com/en/authentication/troubleshooting-ssh/using-ssh-over-the-https-port&lt;/a>&lt;/p>
&lt;p>第一步,用以下代码测试443端口是否可用&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ssh&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">T&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="mi">443&lt;/span> &lt;span class="n">git&lt;/span>&lt;span class="err">@&lt;/span>&lt;span class="n">ssh&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">github&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果出现这样就是可用的，那么恭喜，十拿九稳了！
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-16.png"
width="551"
height="48"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-16_hu17354657446761016326.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-16_hu6545698333154276200.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="1147"
data-flex-basis="2755px"
>
用如下ssh地址替代原来的&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">git&lt;/span> &lt;span class="n">clone&lt;/span> &lt;span class="nl">ssh&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="c1">//git@ssh.github.com:443/YOUR-USERNAME/YOUR-REPOSITORY.git
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意是替代，直接用原来的地址加端口是不行的。
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-17.png"
width="551"
height="148"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-17_hu9065490677750730365.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-17_hu15926033294578801456.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="372"
data-flex-basis="893px"
>&lt;/p>
&lt;p>拿下！&lt;/p>
&lt;h3 id="远程分支是v3版本本地的v2版本但是本地修改了文件还没有add也没有commit应该怎么更新本地">&lt;code>远程分支是v3版本，本地的v2版本，但是本地修改了文件还没有add也没有commit，应该怎么更新本地？&lt;/code>
&lt;/h3>&lt;p>&lt;strong>1. 第一步：首先保存你的本地修改：&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>git stash &lt;/code>&lt;/p>
&lt;p>这会将你当前的修改暂时保存起来&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>2. 第二步：拉取远程更新&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>git fetch origin&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>3. 第三步：更新本地分支到远程版本&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>git merge FETCH_HEAD&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>4. 第四步，恢复你之前的本地修改&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>cpp git stash pop &lt;/code>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>5. 如果在恢复 stash 时遇到冲突，你需要手动解决这些冲突。解决完冲突后，你可以:&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>添加解决冲突后的文件 git add .&lt;/p>
&lt;p>提交你的修改 git commit -m &amp;ldquo;your commit message&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>提示：&lt;/strong>&lt;/p>
&lt;p>如果你想在应用 stash 前查看保存了什么内容，可以用 git stash list 查看 stash 列表
如果你想查看具体改动，可以用 git stash show -p
如果合并时遇到问题，随时可以用 git status 查看当前状态
如果想放弃当前操作回到起点，可以用 git reset &amp;ndash;hard HEAD（注意这会丢失未提交的修改）&lt;/p>
&lt;h3 id="用githooks解决github大文件报错100m限制或50m限制-大文件-50m-githooks-git">用githooks解决github大文件报错100M限制或50M限制-大文件-50M-githooks-git
&lt;/h3>&lt;p>如果你已经commit了大文件，并且报错了，可以使用下面方法，基本上都起作用&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">apt-get install git-filter-repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 删除指定的大文件（路径必须完全匹配）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git filter-repo --path &lt;span class="s2">&amp;#34;路径地址&amp;#34;&lt;/span> --invert-paths
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果还没有提交&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. 把大文件取消追踪&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rm --cached &lt;span class="s2">&amp;#34;path/to/large/file&amp;#34;&lt;/span> &lt;span class="c1"># 引号括起来的是大文件地址&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. 把大文件加入.gitignore&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;path/to/large/file&amp;#34;&lt;/span> &amp;gt;&amp;gt; .gitignore
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. 更改提交 （当然不commit直接git push XXX 也是可以的）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .gitignore
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Update .gitignore to exclude large files&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push XXX main:main --force
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果已经在过去的几次commit提交了，并且知道在哪个commit开始出现，可以使用以下方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. 撤销最近的提交，但保留更改&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git reset --soft HEAD~1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 如果大文件在更早的提交（比如倒数第二次），用 HEAD~2 或具体哈希：&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># git reset --soft abc123^ # abc123 是包含大文件的提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. 移除大文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rm --cached &lt;span class="s2">&amp;#34;大文件名&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3.重新提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Remove large file XXX&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. 强制推送&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push XXX main:main --force
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我写了一个git hooks 文件，在commit大于设定size的文件的时候，拦截commit，并且把大文件名写入.gitignore ，同时从缓存区中移除大文件
&lt;strong>进行版本控制的时候，经常会由于大文件导致上传github出问题，并且版本回退也比较麻烦。
实际上我们很少代码文件会超过50M，而往往是由于数据文件过大导致错误，这些数据文件往往我们可能都不需要进行版本控制&lt;/strong>
&lt;font color = "red" size = 5>于是，不如直接通过脚本，默认不对这些大文件进行版本控制
&lt;/font>&lt;/p>
&lt;p>代码 （文件名设置为pre-commit，防在.git/hooks目录下，注意文件名要一致，这涉及到git hooks的逻辑，不做过多解释）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">#!/usr/bin/env python3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 我在2025年之前用的是 #!/bin/python,但是报错了，改成了上面的内容&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">subprocess&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">files&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">check_output&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s1">&amp;#39;git&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;diff&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;--cached&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;--name-status&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">text&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;utf-8&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">file&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">files&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\t&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\t&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;D&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\t&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getsize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size_in_mb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">file_size&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">1024&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1024&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">size_in_mb&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">50&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.gitignore&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;utf-8&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Remove the file from the Git index (staged area)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">check_output&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s1">&amp;#39;git&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;rm&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;--cached&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file_path&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Removed &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> from stage&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CalledProcessError&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Error removing file from stage: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Reset the file to unstage changes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">check_output&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s1">&amp;#39;git&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;reset&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file_path&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CalledProcessError&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Error while resetting file: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;The file is larger than 50MB and has been added to .gitignore. Please confirm and recommit!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/index.png"
width="705"
height="404"
srcset="https://www.zata.cc/p/gitgithub/images/index/index_hu17052794815196557193.png 480w, https://www.zata.cc/p/gitgithub/images/index/index_hu1959225404414415857.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="174"
data-flex-basis="418px"
>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/index-1.png"
width="734"
height="840"
srcset="https://www.zata.cc/p/gitgithub/images/index/index-1_hu12338691074657616501.png 480w, https://www.zata.cc/p/gitgithub/images/index/index-1_hu1304271098367262708.png 1024w"
loading="lazy"
alt="演示"
class="gallery-image"
data-flex-grow="87"
data-flex-basis="209px"
>&lt;/p>
&lt;p>&lt;strong>下面可以配置全局Git 钩子&lt;/strong>&lt;/p>
&lt;p>LINUX平台&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建全局 Git 钩子目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir -p ~/.git-template/hooks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建并编辑 pre-commit 钩子脚本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cat &amp;gt; ~/.git-template/hooks/pre-commit &lt;span class="s">&amp;lt;&amp;lt; &amp;#39;EOF&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">MAX_SIZE=$((50 * 1024 * 1024)) # 50MB in bytes
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"># 获取暂存区所有文件的列表
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">files=$(git diff --cached --name-only --diff-filter=ACM)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">for file in $files; do
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> # 检查文件是否存在
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> if [ -f &amp;#34;$file&amp;#34; ]; then
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> # 获取文件大小（字节）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> size=$(stat -f%z &amp;#34;$file&amp;#34; 2&amp;gt;/dev/null || stat -c%s &amp;#34;$file&amp;#34; 2&amp;gt;/dev/null)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> if [ &amp;#34;$size&amp;#34; -gt &amp;#34;$MAX_SIZE&amp;#34; ]; then
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;错误：文件 &amp;#39;$file&amp;#39; 超过 50MB（大小：$((size / 1024 / 1024))MB）&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> exit 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> fi
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> fi
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">done
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">exit 0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 赋予执行权限&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chmod +x ~/.git-template/hooks/pre-commit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 配置 Git 使用全局钩子模板&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global init.templatedir ~/.git-template
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># （可选）为现有仓库手动复制钩子（替换 /path/to/your/repo 为实际路径）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># cp ~/.git-template/hooks/pre-commit /path/to/your/repo/.git/hooks/pre-commit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># chmod +x /path/to/your/repo/.git/hooks/pre-commit&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>WINDOWS平台&lt;/p>
&lt;p>需要 POWERSHELL 因为环境变量&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 创建全局 Git 钩子目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$templateDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$env:USERPROFILE&lt;/span>&lt;span class="s2">\.git-template\hooks&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">New-Item&lt;/span> &lt;span class="n">-ItemType&lt;/span> &lt;span class="n">Directory&lt;/span> &lt;span class="n">-Force&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$templateDir&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 创建 pre-commit 钩子脚本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$hookPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$templateDir&lt;/span>&lt;span class="s2">\pre-commit&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Set-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$hookPath&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="sh">@&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">#!/bin/sh
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">MAX_SIZE=$((50 * 1024 * 1024)) # 50MB in bytes
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"># 获取暂存区所有文件的列表
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">files=$(git diff --cached --name-only --diff-filter=ACM)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">for file in $files; do
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> # 检查文件是否存在
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> if [ -f &amp;#34;$file&amp;#34; ]; then
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> # 获取文件大小（字节）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> size=$(wc -c &amp;lt; &amp;#34;$file&amp;#34;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> if [ &amp;#34;$size&amp;#34; -gt &amp;#34;$MAX_SIZE&amp;#34; ]; then
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> echo &amp;#34;错误：文件 &amp;#39;$file&amp;#39; 超过 50MB（大小：$((size / 1024 / 1024))MB）&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> exit 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> fi
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> fi
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">done
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">exit 0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;#39;@&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 赋予执行权限（Windows 下无需 chmod，但确保 Git Bash 支持）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 配置 Git 使用全局钩子模板&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">git&lt;/span> &lt;span class="n">config&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-global&lt;/span> &lt;span class="n">init&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">templatedir&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$env:USERPROFILE&lt;/span>&lt;span class="s2">\.git-template&amp;#34;&lt;/span> &lt;span class="c"># 如果你不用变量，那么就赋绝对路径&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># （可选）为现有仓库手动复制钩子（将以下路径替换为实际仓库路径）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># $repoPath = &amp;#34;C:\path\to\your\repo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Copy-Item -Path $hookPath -Destination &amp;#34;$repoPath\.git\hooks\pre-commit&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>也可以按照下面进行手动配置&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>首先创建一个文件夹，然后git init，可以手动将上面代码粘贴修改pre-commit文件&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/index-3.png"
width="886"
height="796"
srcset="https://www.zata.cc/p/gitgithub/images/index/index-3_hu4356868991785405460.png 480w, https://www.zata.cc/p/gitgithub/images/index/index-3_hu14436102453899749230.png 1024w"
loading="lazy"
alt="配置文件夹"
class="gallery-image"
data-flex-grow="111"
data-flex-basis="267px"
>&lt;/p>
&lt;ol start="2">
&lt;li>配置全局钩子，需要绝对路径&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/index-2.png"
width="997"
height="160"
srcset="https://www.zata.cc/p/gitgithub/images/index/index-2_hu15037366000381273471.png 480w, https://www.zata.cc/p/gitgithub/images/index/index-2_hu13621154539024177249.png 1024w"
loading="lazy"
alt="配置全局"
class="gallery-image"
data-flex-grow="623"
data-flex-basis="1495px"
>&lt;/p>
&lt;ol start="3">
&lt;li>可以测试一下，原理就是git init的时候，把设置的这些配置复制一份&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/index-4.png"
width="984"
height="707"
srcset="https://www.zata.cc/p/gitgithub/images/index/index-4_hu18398455187137645033.png 480w, https://www.zata.cc/p/gitgithub/images/index/index-4_hu18373867733037030671.png 1024w"
loading="lazy"
alt="创建的新本地git仓库"
class="gallery-image"
data-flex-grow="139"
data-flex-basis="334px"
>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/index-5.png"
width="1113"
height="968"
srcset="https://www.zata.cc/p/gitgithub/images/index/index-5_hu15228099333374333631.png 480w, https://www.zata.cc/p/gitgithub/images/index/index-5_hu649624552783475551.png 1024w"
loading="lazy"
alt="测试大文件"
class="gallery-image"
data-flex-grow="114"
data-flex-basis="275px"
>&lt;/p>
&lt;h3 id="cannot_lock_ref_error">cannot_lock_ref_error
&lt;/h3>&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/index-6.png"
width="1114"
height="209"
srcset="https://www.zata.cc/p/gitgithub/images/index/index-6_hu6141658079254375775.png 480w, https://www.zata.cc/p/gitgithub/images/index/index-6_hu8272317630638439298.png 1024w"
loading="lazy"
alt="cannot_lock_ref_error"
class="gallery-image"
data-flex-grow="533"
data-flex-basis="1279px"
>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">root@ce4322c051c6:/codes/dataAnalysisModels# git pull
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Enumerating objects: 193, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Counting objects: 100% &lt;span class="o">(&lt;/span>193/193&lt;span class="o">)&lt;/span>, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Compressing objects: 100% &lt;span class="o">(&lt;/span>178/178&lt;span class="o">)&lt;/span>, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: Total &lt;span class="m">191&lt;/span> &lt;span class="o">(&lt;/span>delta 10&lt;span class="o">)&lt;/span>, reused &lt;span class="m">188&lt;/span> &lt;span class="o">(&lt;/span>delta 10&lt;span class="o">)&lt;/span>, pack-reused &lt;span class="m">0&lt;/span> &lt;span class="o">(&lt;/span>from 0&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Receiving objects: 100% &lt;span class="o">(&lt;/span>191/191&lt;span class="o">)&lt;/span>, 115.48 MiB &lt;span class="p">|&lt;/span> 149.00 KiB/s, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Resolving deltas: 100% &lt;span class="o">(&lt;/span>10/10&lt;span class="o">)&lt;/span>, completed with &lt;span class="m">2&lt;/span> &lt;span class="nb">local&lt;/span> objects.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">error: cannot lock ref &lt;span class="s1">&amp;#39;refs/remotes/zata/main&amp;#39;&lt;/span>: is at 801efa1db3242f2be077de0d34e4eb29af0a5751 but expected aab6c46b69629454c3ad76e5a030157169eabb6e
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">From github.com:zata-zhangtao/dataAnalysisAndModeling_In-GY
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ! aab6c46..801efa1 main -&amp;gt; zata/main &lt;span class="o">(&lt;/span>unable to update &lt;span class="nb">local&lt;/span> ref&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我的解决方法是&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch --prune
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="云服务器无法访问github导致git失败方案">云服务器无法访问Github导致git失败方案
&lt;/h3>&lt;p>可以先去这个网站，哪些ip可用&lt;/p>
&lt;p>&lt;a class="link" href="https://ping.chinaz.com/github.com" target="_blank" rel="noopener"
>https://ping.chinaz.com/github.com&lt;/a>&lt;/p>
&lt;p>然后要修改服务器端的HOSTS&lt;/p>
&lt;p>例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">20.205.243.166 github.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">20.205.243.166 raw.githubusercontent.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>hosts位置在 /etc/hosts&lt;/p>
&lt;h2 id="知识点">知识点
&lt;/h2>&lt;h3 id="github-actions-密钥管理全指南repositoryenvironment-与-organization-secrets-的区别与最佳实践">GitHub Actions 密钥管理全指南：Repository、Environment 与 Organization Secrets 的区别与最佳实践
&lt;/h3>&lt;p>在配置 GitHub Actions CI/CD 流水线时，管理敏感信息（API Key、数据库密码、部署 Token）是重中之重。GitHub 提供了多种存储 Secrets（密钥）的方式，最常见的是 &lt;strong>Repository Secrets&lt;/strong>，但你可能也注意到了 &lt;strong>Environment Secrets&lt;/strong> 和 &lt;strong>Organization Secrets&lt;/strong>。&lt;/p>
&lt;p>它们到底有什么区别？如果我想让一个变量在几十个仓库里通用，又该怎么办？这篇文章将为你彻底理清这三者的关系、优先级和最佳应用场景。&lt;/p>
&lt;p>&lt;strong>一、Repository Secrets vs. Environment Secrets&lt;/strong>&lt;/p>
&lt;p>这是最基础的两个概念，决定了你的密钥是在“仓库级别”可见，还是在“特定部署环境”下可见。&lt;/p>
&lt;p>&lt;strong>1. Repository Secrets (仓库级密钥)&lt;/strong>&lt;/p>
&lt;p>这是最常用的类型。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>位置&lt;/strong>：&lt;code>Settings&lt;/code> -&amp;gt; &lt;code>Secrets and variables&lt;/code> -&amp;gt; &lt;code>Actions&lt;/code> -&amp;gt; &lt;code>Repository secrets&lt;/code>&lt;/li>
&lt;li>&lt;strong>作用域&lt;/strong>：整个代码仓库。仓库内的任何 Workflow、任何分支、任何 Job 都可以直接读取。&lt;/li>
&lt;li>&lt;strong>适用场景&lt;/strong>：
&lt;ul>
&lt;li>通用的 CI 工具 Token（如 Codecov, SonarQube）。&lt;/li>
&lt;li>构建阶段需要的非敏感于环境的凭证（如拉取私有 Docker 镜像的 Token）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. Environment Secrets (环境级密钥)&lt;/strong>&lt;/p>
&lt;p>这是为 CD（持续部署）设计的更高级功能。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>位置&lt;/strong>：&lt;code>Settings&lt;/code> -&amp;gt; &lt;code>Environments&lt;/code> -&amp;gt; 选择环境（如 &lt;code>production&lt;/code>） -&amp;gt; &lt;code>Environment secrets&lt;/code>&lt;/li>
&lt;li>&lt;strong>作用域&lt;/strong>：仅限在 Workflow YAML 中明确指定了该环境的 Job。&lt;/li>
&lt;li>&lt;strong>核心优势&lt;/strong>：
&lt;ol>
&lt;li>&lt;strong>部署保护（Deployment Protection Rules）&lt;/strong>：你可以设置 &lt;strong>Required reviewers (人工审批)&lt;/strong>。例如，Workflow 运行到部署生产环境的步骤时会暂停，直到管理员点击&amp;quot;Approve&amp;rdquo;，代码才能拿到 Environment Secret 并继续执行。&lt;/li>
&lt;li>&lt;strong>同名变量覆盖&lt;/strong>：允许开发环境和生产环境使用同一个变量名（如 &lt;code>DB_HOST&lt;/code>），但值不同。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>代码示例：如何使用 Environment Secret&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deploy-prod&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># 关键点：必须声明 environment，才能读取到该环境下的 Secret&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">production &lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># 如果 production 环境里定义了 API_KEY，这里读到的就是生产环境的 Key&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">API_KEY&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.API_KEY }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./deploy.sh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>3. 对比总结&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">特性&lt;/th>
&lt;th style="text-align: left">Repository Secrets&lt;/th>
&lt;th style="text-align: left">Environment Secrets&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>可见性&lt;/strong>&lt;/td>
&lt;td style="text-align: left">所有 Job 可见&lt;/td>
&lt;td style="text-align: left">仅声明 &lt;code>environment: xxx&lt;/code> 的 Job 可见&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>审批机制&lt;/strong>&lt;/td>
&lt;td style="text-align: left">不支持&lt;/td>
&lt;td style="text-align: left">&lt;strong>支持人工审批、等待计时器等&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>优先级&lt;/strong>&lt;/td>
&lt;td style="text-align: left">较低&lt;/td>
&lt;td style="text-align: left">&lt;strong>最高&lt;/strong> (覆盖同名 Repository Secret)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>典型用途&lt;/strong>&lt;/td>
&lt;td style="text-align: left">单元测试、Lint 检查、构建镜像&lt;/td>
&lt;td style="text-align: left">生产环境数据库密码、AWS 生产证书&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;p>&lt;strong>二、进阶痛点：我想定义所有仓库都能用的变量怎么办？&lt;/strong>&lt;/p>
&lt;p>当你拥有 20 个微服务仓库，且都需要使用同一个 NPM Token 或者 Slack 通知 Webhook URL 时，在每个仓库里重复配置 Repository Secrets 会让人崩溃。&lt;/p>
&lt;p>这时你需要 &lt;strong>Organization Secrets (组织级密钥)&lt;/strong>。&lt;/p>
&lt;p>&lt;strong>1. 什么是 Organization Secrets？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>位置&lt;/strong>：组织主页 -&amp;gt; &lt;code>Settings&lt;/code> -&amp;gt; &lt;code>Secrets and variables&lt;/code> -&amp;gt; &lt;code>Actions&lt;/code>。&lt;/li>
&lt;li>&lt;strong>前提&lt;/strong>：你的仓库必须属于一个 Organization（组织账号），个人账号不支持此功能。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. 强大的访问策略 (Access Policy)&lt;/strong>&lt;/p>
&lt;p>在创建组织密钥时，你可以控制它的传播范围：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>All repositories&lt;/strong>：组织下所有（现有和未来新建的）仓库都能自动读取。&lt;/li>
&lt;li>&lt;strong>Private repositories only&lt;/strong>：仅私有仓库可用（防止开源项目泄露公司 Token）。&lt;/li>
&lt;li>&lt;strong>Selected repositories&lt;/strong>：手动勾选特定仓库可用（&lt;strong>推荐&lt;/strong>，遵循最小权限原则）。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3. Organization Variables (组织级变量)&lt;/strong>&lt;/p>
&lt;p>除了加密的 Secrets，GitHub 还允许在组织级定义 &lt;strong>Variables&lt;/strong>（明文变量）。&lt;/p>
&lt;ul>
&lt;li>适用于非敏感配置，如 &lt;code>API_BASE_URL&lt;/code>、&lt;code>COMPANY_NAME&lt;/code>。&lt;/li>
&lt;li>在代码中通过 &lt;code>${{ vars.MY_VAR }}&lt;/code> 访问。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;strong>三、终极问题：同名变量的优先级（覆盖逻辑）&lt;/strong>&lt;/p>
&lt;p>如果我在 Organization、Repository 和 Environment 里都定义了同一个名字的变量（比如 &lt;code>DATABASE_URL&lt;/code>），GitHub 会读取哪一个？&lt;/p>
&lt;p>遵循 &lt;strong>“越具体，优先级越高”&lt;/strong> 的原则：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Environment Secrets&lt;/strong> (最高优先级) 👑&lt;/li>
&lt;li>&lt;strong>Repository Secrets&lt;/strong> (中等优先级)&lt;/li>
&lt;li>&lt;strong>Organization Secrets&lt;/strong> (最低优先级)&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>实战场景：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>你在 &lt;strong>组织级&lt;/strong> 设置了 &lt;code>SLACK_WEBHOOK&lt;/code> 用于日常通知。&lt;/li>
&lt;li>突然有个特定仓库 &lt;code>Project-X&lt;/code> 需要发送通知到另一个独立的 Slack 频道。&lt;/li>
&lt;li>你只需在 &lt;code>Project-X&lt;/code> 的 &lt;strong>Repository secrets&lt;/strong> 里新建一个同名的 &lt;code>SLACK_WEBHOOK&lt;/code>。&lt;/li>
&lt;li>GitHub 会自动优先使用仓库级的配置，而不会影响组织内其他 99 个仓库。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;strong>四、最佳实践决策清单&lt;/strong>&lt;/p>
&lt;p>在创建变量前，请对照此清单选择存储位置：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>这个变量是所有（或多个）项目通用的吗？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>是 -&amp;gt; &lt;strong>Organization Secrets&lt;/strong> (如：公司通用的 NPM Token, Slack Webhook)。&lt;/li>
&lt;li>否 -&amp;gt; 往下看。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>这个变量涉及“生产环境”或“高风险”操作吗？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>是（如 AWS Prod Key, 生产库密码）-&amp;gt; &lt;strong>Environment Secrets&lt;/strong> (并开启人工审批保护)。&lt;/li>
&lt;li>否 -&amp;gt; 往下看。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>这个变量需要在不同的环境（Dev/Test/Prod）有不同的值吗？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>是 -&amp;gt; &lt;strong>Environment Secrets&lt;/strong> (在不同环境里设同名变量)。&lt;/li>
&lt;li>否 -&amp;gt; 往下看。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>默认选项：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>上述情况都不是 -&amp;gt; &lt;strong>Repository Secrets&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;p>&lt;strong>结语&lt;/strong>&lt;/p>
&lt;p>掌握这三个层级的 Secrets 管理，不仅能让你的 GitHub Actions Workflow 代码更简洁（由 &lt;code>if/else&lt;/code> 地狱转变为统一变量名），还能大幅提升 CI/CD 流程的安全性。&lt;/p>
&lt;p>&lt;strong>Tip&lt;/strong>: 如果你是个人开发者账号，无法使用 Organization Secrets，建议创建一个免费的 Organization 并将仓库 Transfer 进去，以便享受全局变量管理的便利。&lt;/p>
&lt;h3 id="将python包发布到github并通过pip安装的教程">将Python包发布到GitHub并通过pip安装的教程
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>创建Python包结构&lt;/strong>&lt;br>
构建以下目录结构：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">your_package/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── your_package/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── your_module.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── setup.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── README.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── LICENSE
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── requirements.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>编写关键文件&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>setup.py&lt;/strong> 示例：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">setuptools&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">setup&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">find_packages&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">setup&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;your_package_name&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;0.1.0&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">packages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">find_packages&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">install_requires&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;requests&amp;gt;=2.25.1&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">author&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Your Name&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">author_email&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;your.email@example.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;A short description of your package&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">long_description&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;README.md&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">long_description_content_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;text/markdown&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;https://github.com/yourusername/your_package&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">classifiers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Programming Language :: Python :: 3&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;License :: OSI Approved :: MIT License&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>your_package/&lt;strong>init&lt;/strong>.py&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">__version__&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;0.1.0&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>初始化Git并上传到GitHub&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Initial commit&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote add origin https://github.com/yourusername/your_package.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git branch -M main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push -u origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>创建GitHub Release（可选，但推荐）&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>访问GitHub仓库页面，点击&amp;quot;Releases&amp;quot; -&amp;gt; &amp;ldquo;Create a new release&amp;rdquo;&lt;/li>
&lt;li>输入版本号（如v0.1.0），发布&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>通过pip安装&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>直接从GitHub安装：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install git+https://github.com/yourusername/your_package.git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>指定分支：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install git+https://github.com/yourusername/your_package.git@branch_name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>指定版本（需要有release）：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install git+https://github.com/yourusername/your_package.git@v0.1.0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>发布到PyPI（可选，允许标准pip安装）&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>安装工具：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install twine build
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>构建包：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">python -m build
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>上传到PyPI：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">twine upload dist/*
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>之后可使用：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install your_package_name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>注意事项&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>确保&lt;code>setup.py&lt;/code>信息准确&lt;/li>
&lt;li>设置清晰的GitHub仓库描述和topics&lt;/li>
&lt;li>使用MIT或其他合适的许可证&lt;/li>
&lt;li>编写详细的README.md，包含安装和使用说明&lt;/li>
&lt;li>发布到PyPI需注册账号并配置API token&lt;/li>
&lt;/ul>
&lt;h3 id="git-reset---hard-head-详解andgit-reset---soft-head-详解">git-reset&amp;mdash;hard-head-详解andgit-reset&amp;mdash;soft-head-详解
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git reset --hard HEAD
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>效果：&lt;/p>
&lt;p>撤销所有未提交的更改（包括工作目录和暂存区）。
HEAD 指向的提交成为当前状态，之前的修改全部丢失（不可恢复，除非有其他备份）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git reset --soft HEAD
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>功能：将当前分支的指针重置到 HEAD 指向的提交，但保留工作目录和暂存区的所有更改。
效果：&lt;/p>
&lt;p>撤销最近的提交（将 HEAD 指针移到当前提交），但修改的内容仍保留在工作目录或暂存区。
可以重新调整或重新提交这些更改。&lt;/p>
&lt;p>下面我将逐个参数解释这条命令的含义：&lt;/p>
&lt;p>命令分解&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>&lt;code>git reset&lt;/code>&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;code>git reset&lt;/code> 是 Git 用来重置当前分支的 HEAD（当前分支指针）到指定状态的命令。&lt;/li>
&lt;li>它可以影响 Git 的三个主要区域：
&lt;ul>
&lt;li>&lt;strong>工作目录（Working Directory）&lt;/strong>：你当前编辑的文件。&lt;/li>
&lt;li>&lt;strong>暂存区（Staging Area/Index）&lt;/strong>：通过 &lt;code>git add&lt;/code> 添加的文件。&lt;/li>
&lt;li>&lt;strong>提交历史（Commit History）&lt;/strong>：Git 仓库中的提交记录。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>--hard&lt;/code>&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;code>--hard&lt;/code> 是 &lt;code>git reset&lt;/code> 的一个选项，指定重置的模式。&lt;/li>
&lt;li>它表示&lt;strong>完全重置&lt;/strong>，不仅会移动 HEAD 指针，还会：
&lt;ul>
&lt;li>重置工作目录中的文件内容，使其与指定的提交状态一致。&lt;/li>
&lt;li>清空暂存区的内容。&lt;/li>
&lt;li>丢弃所有未提交的更改（包括工作目录和暂存区的修改）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>简单来说，&lt;code>--hard&lt;/code> 会让你的工作目录、暂存区和提交历史完全恢复到指定的提交状态，&lt;strong>不可恢复已丢弃的更改&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>HEAD^&lt;/code>&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;code>HEAD&lt;/code> 是 Git 中的一个指针，指向当前分支的最新提交。&lt;/li>
&lt;li>&lt;code>^&lt;/code> 是一个相对引用，表示&amp;quot;当前 HEAD 的上一个提交&amp;quot;（即父提交）。&lt;/li>
&lt;li>因此，&lt;code>HEAD^&lt;/code> 表示当前分支最新提交的上一个提交。&lt;/li>
&lt;li>如果当前分支的提交历史是 &lt;code>A &amp;lt;- B &amp;lt;- C&lt;/code>（C 是 HEAD），那么 &lt;code>HEAD^&lt;/code> 指向 &lt;code>B&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>整体含义
&lt;code>git reset --hard HEAD^&lt;/code> 的作用是：&lt;/p>
&lt;ul>
&lt;li>将当前分支的 HEAD 指针移动到上一个提交（&lt;code>HEAD^&lt;/code>）。&lt;/li>
&lt;li>重置工作目录和暂存区，使其与 &lt;code>HEAD^&lt;/code> 指向的提交状态完全一致。&lt;/li>
&lt;li>&lt;strong>丢弃&lt;/strong>当前 HEAD 提交（最新提交）以及工作目录和暂存区的所有未提交更改。&lt;/li>
&lt;/ul>
&lt;p>示例场景
假设你的提交历史如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">A &amp;lt;- B &amp;lt;- C (HEAD)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="githook脚本版本控制管理">githook脚本版本控制管理
&lt;/h3>&lt;p>在 Git 项目中，&lt;code>.githooks&lt;/code> 目录中的钩子（hook）脚本默认是不会被 Git 版本控制系统自动纳入版本管理的，因为 &lt;code>.githooks&lt;/code> 目录通常被视为本地配置的一部分。为了将 Git 钩子脚本保留到项目中并与团队共享，你需要采取一些额外的步骤。以下是具体的方法：&lt;/p>
&lt;p>方法一：将钩子脚本纳入版本控制&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>将 &lt;code>.githooks&lt;/code> 目录重命名或移动到项目中&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>默认情况下，Git 钩子存储在 &lt;code>.git/hooks&lt;/code> 目录中，这些文件不会被 Git 跟踪。你可以将钩子脚本移动到项目的一个自定义目录（例如 &lt;code>githooks&lt;/code> 或 &lt;code>hooks&lt;/code>），并纳入版本控制。&lt;/li>
&lt;li>示例：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir githooks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mv .git/hooks/pre-commit githooks/pre-commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>配置 Git 使用自定义钩子目录&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>使用以下命令告诉 Git 使用项目中的自定义钩子目录：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config core.hooksPath githooks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">cd&lt;/span> githooks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 查找所有文件 (f) 并赋予执行权限 &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">find . -type f -exec chmod +x &lt;span class="o">{}&lt;/span> &lt;span class="se">\;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>这会让 Git 使用 &lt;code>githooks&lt;/code> 目录中的钩子脚本，而不是默认的 &lt;code>.git/hooks&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>将钩子脚本提交到版本控制&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>将 &lt;code>githooks&lt;/code> 目录添加到 Git 版本控制：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add githooks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Add git hooks to project&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>团队成员同步配置&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>其他团队成员在克隆或拉取项目后，需要手动运行 &lt;code>git config core.hooksPath githooks&lt;/code> 来启用自定义钩子路径。或者，你可以通过脚本自动设置。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>方法二：使用脚本自动安装钩子
为了让团队成员无需手动配置 &lt;code>core.hooksPath&lt;/code>，你可以在项目中添加一个安装脚本，自动将钩子脚本复制到 &lt;code>.git/hooks&lt;/code> 目录。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>创建安装脚本&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>在项目根目录创建一个脚本（例如 &lt;code>install-hooks.sh&lt;/code>）：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>cp githooks/* .git/hooks/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chmod +x .git/hooks/*
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Git hooks installed successfully.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>这个脚本会将 &lt;code>githooks&lt;/code> 目录中的钩子复制到 &lt;code>.git/hooks&lt;/code> 目录，并确保它们具有可执行权限。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>添加到版本控制&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>将 &lt;code>install-hooks.sh&lt;/code> 和 &lt;code>githooks&lt;/code> 目录提交到 Git：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add githooks install-hooks.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Add git hooks and install script&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>运行安装脚本&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>团队成员在克隆项目后，运行以下命令来安装钩子：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">./install-hooks.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>方法三：使用 Git 模板目录
如果你希望钩子脚本在所有新项目中自动生效，可以配置 Git 的全局模板目录：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>创建全局钩子模板&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>复制默认的 Git 钩子模板到自定义目录：(如果你还没有自定义模板目录，可以通过下面的代码创建一个)
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git init --template&lt;span class="o">=&lt;/span>/path/to/custom-template
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>在 &lt;code>/path/to/custom-template/hooks&lt;/code> 中添加你的钩子脚本。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>也可以配置全局模板路径&lt;/strong>就不用第一步了：&lt;/p>
&lt;ul>
&lt;li>设置 Git 的全局模板路径：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config --global init.templateDir /path/to/custom-template
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>之后，任何新初始化的 Git 仓库都会使用这个模板。&lt;/li>
&lt;li>具体的使用和介绍可见shou 配置钩子脚本，请查看&lt;a class="link" href="#%e7%94%a8githooks%e8%a7%a3%e5%86%b3github%e5%a4%a7%e6%96%87%e4%bb%b6%e6%8a%a5%e9%94%99100M%e9%99%90%e5%88%b6%e6%88%9650M%e9%99%90%e5%88%b6-%e5%a4%a7%e6%96%87%e4%bb%b6-50M-githooks-git" >用git hooks解决github大文件报错，100M限制或50M限制|大文件|50M|git hooks|git&lt;/a>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>注意事项&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>这种方法适合个人开发环境，但不适合团队项目，因为模板目录是本地的，无法直接共享。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>方法四：使用工具管理钩子
可以使用一些工具来简化 Git 钩子的管理和共享，例如：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Husky&lt;/strong>（适用于 Node.js 项目）：&lt;/p>
&lt;ul>
&lt;li>如果你的项目是 Node.js 项目，可以使用 Husky 来管理 Git 钩子。安装 Husky 后，它会自动管理 &lt;code>.git/hooks&lt;/code> 目录，并在 &lt;code>package.json&lt;/code> 中定义钩子脚本。&lt;/li>
&lt;li>安装：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npm install husky --save-dev
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>配置（在 &lt;code>package.json&lt;/code> 中）：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;husky&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;hooks&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;pre-commit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;echo &amp;#39;Running pre-commit hook&amp;#39;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>pre-commit&lt;/strong>（适用于 Python 项目）：&lt;/p>
&lt;ul>
&lt;li>如果是 Python 项目，可以使用 &lt;code>pre-commit&lt;/code> 框架来管理钩子。创建一个 &lt;code>.pre-commit-config.yaml&lt;/code> 文件，定义钩子脚本，并提交到版本控制。&lt;/li>
&lt;li>安装：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install pre-commit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pre-commit install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>注意事项&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>权限问题&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>确保钩子脚本具有可执行权限（&lt;code>chmod +x githooks/*&lt;/code>）。&lt;/li>
&lt;li>在 Windows 系统上，可能需要额外处理文件权限问题。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>跨平台兼容性&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>如果团队成员使用不同操作系统（例如 Windows 和 Linux），确保钩子脚本是跨平台的（例如，使用 Bash 脚本或 Python 脚本）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>文档说明&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>在项目的 &lt;code>README.md&lt;/code> 中添加说明，告诉团队成员如何启用钩子（例如运行 &lt;code>install-hooks.sh&lt;/code> 或设置 &lt;code>core.hooksPath&lt;/code>）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>避免覆盖本地钩子&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>如果直接覆盖 &lt;code>.git/hooks&lt;/code>，可能会覆盖团队成员的本地钩子配置。使用 &lt;code>core.hooksPath&lt;/code> 或脚本复制的方式更安全。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>总结
最推荐的方式是将钩子脚本放入项目中的 &lt;code>githooks&lt;/code> 目录，提交到版本控制，并通过脚本或 &lt;code>git config core.hooksPath&lt;/code> 自动配置。结合工具如 Husky 或 pre-commit 可以进一步简化管理。根据项目类型和团队习惯选择合适的方法。&lt;/p>
&lt;ul>
&lt;li>当前 HEAD 指向提交 &lt;code>C&lt;/code>。&lt;/li>
&lt;li>执行 &lt;code>git reset --hard HEAD^&lt;/code> 后：
&lt;ul>
&lt;li>HEAD 移动到 &lt;code>B&lt;/code>（&lt;code>HEAD^&lt;/code>）。&lt;/li>
&lt;li>提交 &lt;code>C&lt;/code> 从当前分支的提交历史中移除（但可能仍存在于 Git 的对象数据库中，直到被垃圾回收）。&lt;/li>
&lt;li>工作目录和暂存区的内容恢复到提交 &lt;code>B&lt;/code> 的状态。&lt;/li>
&lt;li>任何未提交的更改（工作目录或暂存区）都会被永久删除。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>新的提交历史变为：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">A &amp;lt;- B (HEAD)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意事项&lt;/p>
&lt;ul>
&lt;li>&lt;strong>数据丢失风险&lt;/strong>：&lt;code>--hard&lt;/code> 会永久删除未提交的更改和指定的提交（&lt;code>HEAD&lt;/code> 到 &lt;code>HEAD^&lt;/code> 之间的提交）。在执行前，建议使用 &lt;code>git status&lt;/code> 检查是否有未提交的更改，或者用 &lt;code>git log&lt;/code> 确认提交历史。&lt;/li>
&lt;li>&lt;strong>备份建议&lt;/strong>：如果不确定是否需要丢弃更改，可以先用 &lt;code>git branch backup&lt;/code> 创建一个备份分支，以保留当前 HEAD 的状态。&lt;/li>
&lt;li>&lt;strong>远程仓库影响&lt;/strong>：如果当前分支已经推送到远程仓库（如 GitHub），执行 &lt;code>git reset --hard HEAD^&lt;/code> 后需要用 &lt;code>git push --force&lt;/code> 强制推送，这可能会影响其他协作者，需谨慎操作。&lt;/li>
&lt;/ul>
&lt;p>总结&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>git reset&lt;/code>&lt;/strong>: 重置 HEAD 到指定状态。&lt;/li>
&lt;li>&lt;strong>&lt;code>--hard&lt;/code>&lt;/strong>: 完全重置，丢弃工作目录和暂存区的更改。&lt;/li>
&lt;li>&lt;strong>&lt;code>HEAD^&lt;/code>&lt;/strong>: 指向当前 HEAD 的上一个提交。&lt;/li>
&lt;/ul>
&lt;p>这条命令的总体效果是&amp;quot;撤销最近一次提交并恢复到上一个提交的状态，同时丢弃所有未提交的更改&amp;quot;。如果你只是想撤销提交但保留更改，可以考虑使用 &lt;code>git reset --soft HEAD^&lt;/code> 或其他命令（如 &lt;code>git revert&lt;/code>）。&lt;/p>
&lt;h2 id="实战----使用">实战 &amp;ndash; 使用
&lt;/h2>&lt;h3 id="软件版本管理与热修复流程">软件版本管理与热修复流程
&lt;/h3>&lt;p>这是一个非常经典的软件版本管理问题。在真实的开发场景中非常常见，通常被称为**“热修复”（Hotfix）或“补丁发布”（Patch Release）**。&lt;/p>
&lt;p>为了在不影响 0.6.0 开发进度的情况下修复 0.5.0 的 bug，你需要基于 0.5.0 的代码拉取一个新分支，修复 bug 后发布 0.5.1，然后再把修复代码同步回 main 分支。&lt;/p>
&lt;p>以下是标准的处理流程（假设你使用的是 Git）：&lt;/p>
&lt;p>&lt;strong>第一步：找到 0.5.0 的代码并拉取新分支&lt;/strong>&lt;/p>
&lt;p>通常你在发布 0.5.0 时会打一个标签（Tag），或者你能找到发布 0.5.0 时的那个 Commit 记录。我们需要基于这个点创建一个专门用于修复和发布的分支（比如叫 hotfix-0.5.1 或 release-0.5.x）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 假设你的 0.5.0 标签名为 v0.5.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout -b hotfix-0.5.1 v0.5.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 如果你没有打标签，可以找到当时的 commit hash（比如 a1b2c3d）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout -b hotfix-0.5.1 a1b2c3d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>第二步：在新分支上修复 Bug 并修改版本号&lt;/strong>&lt;/p>
&lt;p>现在你的代码状态已经完全回退到了 0.5.0 发布时的样子。在这里修复那个 bug，并将项目配置文件中的版本号从 0.5.0 修改为 0.5.1（如果你有 package.json、pom.xml 等文件的话）。提交你的代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;fix: 修复了 0.5.0 版本的严重 bug&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;chore: 升级版本号至 0.5.1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>第三步：发布 0.5.1&lt;/strong>&lt;/p>
&lt;p>现在你可以基于这个 hotfix-0.5.1 分支去打包、测试并发布产品了。发布完成后，别忘了打上新标签：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git tag v0.5.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin v0.5.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin hotfix-0.5.1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>到这一步，你的用户已经可以拿到没有 bug 的 0.5.1 版本了，而你的 main 分支毫无影响。&lt;/p>
&lt;p>&lt;strong>第四步：将修复代码同步回 main 分支（极其重要！）&lt;/strong>&lt;/p>
&lt;p>这一步绝对不能忘！否则你以后发布 0.6.0 时，这个 bug 还会再次出现（也就是所谓的回归 bug）。你有两种常见的方式将修复同步回 main：&lt;/p>
&lt;p>&lt;strong>方式 A：合并分支（Merge）—— 适合 Git Flow 等标准工作流&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git merge hotfix-0.5.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 如果有冲突，解决冲突后提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意：这可能会把 0.5.1 的版本号更改也合并进来，你可能需要在 main 分支再次修改版本号回 0.6.0-dev。&lt;/p>
&lt;p>&lt;strong>方式 B：摘取提交（Cherry-pick）—— 很多团队更喜欢这种，因为它更干净&lt;/strong>&lt;/p>
&lt;p>如果你在 hotfix-0.5.1 分支上只有一两个修复 bug 的 Commit，你可以只把修复 bug 的代码拿过来，而不拿修改版本号的代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 先用 git log 看一下你修复 bug 的那个 commit 的 hash 值（比如 f8e9d0c）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 切换回 main 分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 将修复代码“摘”过来&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git cherry-pick f8e9d0c
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>总结流程图&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl"> (0.5.0) -----------------------------------&amp;gt; (0.6.0) [main 分支]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | ^
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | | (同步修复代码 Merge 或 Cherry-pick)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> +---&amp;gt;[修 bug] ---&amp;gt; (发布 0.5.1) --------------+ [hotfix 分支]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过这种方式，既保证了 0.5.0 用户的可用性，又让 main 分支可以继续安心开发 0.6.0 的新功能。&lt;/p>
&lt;p>&lt;strong>关于 Main 分支的历史记录问题&lt;/strong>&lt;/p>
&lt;p>这个问题非常关键！答案是：这取决于你用哪种方式（Merge 还是 Cherry-pick）把代码同步回 main。准确地说，你关心的“记录”分为两种：修复 Bug 的代码记录（比如提交信息：&amp;ldquo;fix: 修复了 xxx&amp;rdquo;）和 0.5.1 的发布记录（比如提交信息：&amp;ldquo;chore: 升级版本号至 0.5.1&amp;rdquo; 以及 v0.5.1 的标签 Tag）。&lt;/p>
&lt;p>&lt;strong>情况一：如果你使用的是 Cherry-pick（摘取）—— 推荐方式&lt;/strong>&lt;/p>
&lt;p>如果你采用的是 cherry-pick，你只把“修复 Bug&amp;quot;的那个 commit 拿到了 main 分支。在 main 的历史中：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>能看见：&lt;/strong> 修复 Bug 的记录（但 Git 会为它生成一个新的 Commit Hash）。&lt;/li>
&lt;li>&lt;strong>看不见：&lt;/strong> 任何关于&amp;quot;0.5.1&amp;quot;字眼的记录（包括改版本号的 commit 和 0.5.1 的 tag 都不会在 main 上出现）。&lt;/li>
&lt;/ul>
&lt;p>结果：main 分支的历史非常干净，看起来就像是在开发 0.6.0 的过程中顺手修了一个 bug，历史记录是一条直线向前。&lt;/p>
&lt;p>Cherry-pick 后的 main 记录看起来像这样：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl"> * 9b8c7d6 (HEAD -&amp;gt; main) fix: 修复了导致崩溃的严重 bug &amp;lt;-- 这是 cherry-pick 过来的新 commit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * 5a4b3c2 feat: 0.6.0 的新功能 B
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * 4z3y2x1 feat: 0.6.0 的新功能 A
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * a1b2c3d (tag: v0.5.0) release: 发布 0.5.0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>情况二：如果你使用的是 Merge（合并）&lt;/strong>&lt;/p>
&lt;p>如果你直接在 main 分支执行 &lt;code>git merge hotfix-0.5.1&lt;/code>。在 main 的历史中：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>能看见：&lt;/strong> 0.5.1 分支上的所有记录，原封不动地出现在了这里。&lt;/li>
&lt;li>&lt;strong>能看见：&lt;/strong> &amp;ldquo;chore: 升级版本号至 0.5.1&amp;rdquo; 的提交。&lt;/li>
&lt;li>&lt;strong>能看见：&lt;/strong> 一个额外的合并记录（比如 &amp;ldquo;Merge branch &amp;lsquo;hotfix-0.5.1&amp;rsquo; into main&amp;rdquo;）。&lt;/li>
&lt;/ul>
&lt;p>结果：你的 main 分支历史里会混入 0.5.1 的发布痕迹。如果在合并时遇到了代码冲突（比如 main 的版本号已经改成了 0.6.0-dev，而 hotfix 改成了 0.5.1），你还需要手动解决冲突，保留 0.6.0-dev。&lt;/p>
&lt;p>Merge 后的 main 记录看起来像这样：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl"> * d4e5f6g (HEAD -&amp;gt; main) Merge branch &amp;#39;hotfix-0.5.1&amp;#39; into main &amp;lt;-- 合并节点
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> |\
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | * f8e9d0c (tag: v0.5.1, hotfix-0.5.1) chore: 升级版本号至 0.5.1 &amp;lt;-- 0.5.1 的痕迹进来了
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | * e7d8c9b fix: 修复了导致崩溃的严重 bug
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * | 5a4b3c2 feat: 0.6.0 的新功能 B
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * | 4z3y2x1 feat: 0.6.0 的新功能 A
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> |/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * a1b2c3d (tag: v0.5.0) release: 发布 0.5.0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>总结与建议&lt;/strong>&lt;/p>
&lt;p>如果你不想在 main 分支里看到 0.5.1 这种历史版本号的“噪音”，只想要修复 bug 的代码，那么极其建议使用 &lt;strong>cherry-pick&lt;/strong>。&lt;/p>
&lt;p>这是大型开源项目（比如 Vue, React）和大多数商业公司的标准做法：&lt;/p>
&lt;ol>
&lt;li>main 分支永远只看前方（0.6.0、0.7.0）。&lt;/li>
&lt;li>旧版本（0.5.0）出了问题，在旧版本对应的分支（hotfix-0.5.x）上修补并发布 0.5.1。&lt;/li>
&lt;li>把修补代码像“摘樱桃”一样（cherry-pick）摘回 main 分支。&lt;/li>
&lt;/ol>
&lt;p>这样 main 里就看不见 0.5.1 的版本发布记录，但 Bug 确实被修好了。&lt;/p>
&lt;h3 id="变基合并多个提交">变基合并多个提交
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 例:变基合并最近2个提交&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase -i HEAD~2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个命令会打开你的默认文本编辑器（通常是 Vim、VSCode 或 Nano），显示类似以下内容：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">pick c2b3a4d 实现用户登录API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick d3c4b5a 添加输入验证
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick e4d5c6b 移除调试日志
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick f5e6d7a 修复拼写错误
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 变基 b1a2b3c..f5e6d7a 到 b1a2b3c（4个提交）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">#
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 命令:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># p, pick &amp;lt;提交&amp;gt; = 使用提交
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># r, reword &amp;lt;提交&amp;gt; = 使用提交，但编辑提交信息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># e, edit &amp;lt;提交&amp;gt; = 使用提交，但停下来修改提交
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># s, squash &amp;lt;提交&amp;gt; = 使用提交，但合并到前一个提交
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># f, fixup &amp;lt;提交&amp;gt; = 类似于&amp;#34;squash&amp;#34;，但丢弃提交信息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># x, exec &amp;lt;命令&amp;gt; = 使用shell运行命令（其余行）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># b, break = 在此处停止（稍后用&amp;#39;git rebase --continue&amp;#39;继续）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># d, drop &amp;lt;提交&amp;gt; = 删除提交
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># l, label &amp;lt;标签&amp;gt; = 用名称标记当前HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># t, reset &amp;lt;标签&amp;gt; = 重置HEAD到标签
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># m, merge [-C &amp;lt;提交&amp;gt; | -c &amp;lt;提交&amp;gt;] &amp;lt;标签&amp;gt; [# &amp;lt;单行信息&amp;gt;]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># . 创建合并提交，使用原合并提交的信息（如果没有原合并提交，则使用单行信息）
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们需要将后面的3个提交&amp;quot;压缩&amp;quot;（squash）到第一个提交中。编辑文件如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">pick c2b3a4d 实现用户登录API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">squash d3c4b5a 添加输入验证
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">squash e4d5c6b 移除调试日志
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">squash f5e6d7a 修复拼写错误
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>保存并关闭编辑器。Git 会开始处理这些提交，然后再次打开编辑器让你编辑合并后的提交信息。&lt;/p>
&lt;h3 id="第四步编写合并后的提交信息">第四步：编写合并后的提交信息
&lt;/h3>&lt;p>你会看到一个新的编辑器窗口，显示所有被合并提交的信息：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl"># 这是一个合并了4个提交的组合提交。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 第一个提交信息：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">实现用户登录API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 这是第二个提交信息：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">添加输入验证
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 这是第三个提交信息：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">移除调试日志
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 这是第四个提交信息：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">修复拼写错误
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 请输入新的提交信息，以说明此组合提交的更改。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># 以&amp;#39;#&amp;#39;开头的行将被忽略，空信息会中止提交。
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>删除所有内容，编写一个新的、更有意义的提交信息&lt;/p>
&lt;p>保存并关闭编辑器，Git 就会完成变基操作。&lt;/p>
&lt;h3 id="多轮代码提交后才发现重大bug如何优雅地修改上上个-commit">多轮代码提交后才发现重大Bug？如何优雅地修改“上上个” Commit
&lt;/h3>&lt;p>这是一个为你整理好的博客笔记模板，标题和结构都优化过了，适合发布在 CSDN、掘金、Notion 或个人博客上。&lt;/p>
&lt;p>&lt;strong>📌 问题场景&lt;/strong>&lt;/p>
&lt;p>我在开发中遇到了一个棘手的情况：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>位置&lt;/strong>：倒数第三个 Commit (&lt;code>HEAD~2&lt;/code>) 提交的代码有问题。&lt;/li>
&lt;li>&lt;strong>需求&lt;/strong>：我需要对这个 Commit 进行&lt;strong>大规模的修改/重构&lt;/strong>。&lt;/li>
&lt;li>&lt;strong>工具&lt;/strong>：VS Code。&lt;/li>
&lt;/ol>
&lt;p>直接提交一个新的 Fix Commit 虽然简单，但会让 Git 历史变得脏乱。作为有追求的工程师，我希望历史记录干净整洁。本文记录了两种处理方案：&lt;strong>&amp;ldquo;手术刀模式 (Rebase)&amp;rdquo;&lt;/strong> 和 &lt;strong>&amp;ldquo;推土机模式 (Reset)&amp;rdquo;&lt;/strong>。&lt;/p>
&lt;p>&lt;strong>🛡️ 核心前提：建立安全沙盒&lt;/strong>&lt;/p>
&lt;p>&lt;strong>在修改 Git 历史前，永远不要直接在主分支（如 main/dev）上操作！&lt;/strong>
一旦操作失误（如变基失败），很难恢复。&lt;/p>
&lt;p>&lt;strong>正确做法&lt;/strong>：新建一个临时分支进行&amp;quot;实验&amp;quot;。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout -b fix-old-commit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 所有的修改都在这个分支上进行，确认无误后再合并回主分支或强推。&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>方案一：手术刀模式 (Interactive Rebase)&lt;/strong>&lt;/p>
&lt;p>&lt;strong>适用场景&lt;/strong>：只想精准修复那个错误的 Commit，且&lt;strong>必须保留&lt;/strong>它后面提交的 Commit 记录（例如后面的提交是别人写的，或者与当前修改无关）。&lt;/p>
&lt;p>&lt;strong>操作步骤&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>启动变基&lt;/strong>：
在 VS Code 终端输入命令，回溯到前 3 个版本：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase -i HEAD~3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>&lt;strong>标记要修改的 Commit&lt;/strong>：
Git 会弹出一个编辑器（或 &lt;code>git-rebase-todo&lt;/code> 文件），找到那个有问题的 Commit，将行首的 &lt;code>pick&lt;/code> 修改为 &lt;strong>&lt;code>edit&lt;/code>&lt;/strong>。&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;code>pick&lt;/code> -&amp;gt; &lt;code>edit&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;ol start="3">
&lt;li>
&lt;p>&lt;strong>修改代码&lt;/strong>：
保存并关闭文件后，Git 会暂停在那个 Commit 的时间点。
此时在 VS Code 中进行大规模的代码修改。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>提交修正&lt;/strong>：
改完后，暂存文件并修补当前 Commit：&lt;/p>
&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit --amend --no-edit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="5">
&lt;li>&lt;strong>完成变基&lt;/strong>：
应用后续的提交，回到现代：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase --continue
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>(如果有冲突，在 VS Code 中解冲突 -&amp;gt; add -&amp;gt; continue 即可)&lt;/em>&lt;/p>
&lt;p>&lt;strong>方案二：推土机模式 (Reset &amp;ndash;soft)&lt;/strong>&lt;/p>
&lt;p>&lt;strong>适用场景&lt;/strong>：觉得最近这几次提交都很乱，或者逻辑强相关。不如&lt;strong>把最近的 3 个 Commit 撤销掉，捏成一个完美的 Commit&lt;/strong>。&lt;/p>
&lt;p>&lt;strong>操作步骤&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>软重置&lt;/strong>：
将指针回退 3 步，但&lt;strong>保留文件修改&lt;/strong>在暂存区：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git reset --soft HEAD~3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>
&lt;p>&lt;strong>状态变化&lt;/strong>：
此时，过去 3 次提交的历史记录消失了，但所有的代码变动都还在，并且处于 &lt;strong>Staged (暂存区/绿色)&lt;/strong> 状态。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>修改与重构&lt;/strong>：
直接在现在的代码基础上进行大规模修改、修复 Bug。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>提交新版本&lt;/strong>：&lt;/p>
&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;refactor: 重构核心逻辑（合并了之前的多次尝试）&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>⚖️ 方案对比总结&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>特性&lt;/th>
&lt;th>方案一：Rebase -i (变基)&lt;/th>
&lt;th>方案二：Reset &amp;ndash;soft (重置)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>形象比喻&lt;/strong>&lt;/td>
&lt;td>&lt;strong>精准手术&lt;/strong> 🔪&lt;/td>
&lt;td>&lt;strong>推土机&lt;/strong> 🚜&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>历史记录&lt;/strong>&lt;/td>
&lt;td>保持原有提交数量，只修改其中一个&lt;/td>
&lt;td>将多个历史提交合并为一个新提交&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>后续提交&lt;/strong>&lt;/td>
&lt;td>保留后续 Commit 的独立性&lt;/td>
&lt;td>后续 Commit 也会被合并掉&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>冲突风险&lt;/strong>&lt;/td>
&lt;td>可能会遇到多次冲突（每个后续 Commit 都可能冲突）&lt;/td>
&lt;td>&lt;strong>无冲突&lt;/strong>（因为是一次性提交）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>推荐指数&lt;/strong>&lt;/td>
&lt;td>⭐⭐⭐⭐ (团队协作且需保留历史时)&lt;/td>
&lt;td>⭐⭐⭐⭐⭐ (个人开发或整理烂代码时)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>💡 VS Code 插件推荐&lt;/strong>&lt;/p>
&lt;p>如果你不习惯命令行，推荐安装 &lt;strong>Git Graph&lt;/strong>。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Rebase&lt;/strong>: 右键父节点 -&amp;gt; &lt;code>Rebase current branch on this commit&lt;/code> -&amp;gt; 勾选 &lt;code>Interactive&lt;/code>。&lt;/li>
&lt;li>&lt;strong>Reset&lt;/strong>: 右键目标节点 -&amp;gt; &lt;code>Reset current branch to this commit&lt;/code> -&amp;gt; 选择 &lt;code>Soft&lt;/code>。&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>最后提示&lt;/strong>：如果你修改的分支已经 Push 到了远程且有同事在协作，请务必与同事沟通，因为修改历史记录需要 &lt;code>git push -f&lt;/code> (强制推送)，这可能会覆盖同事的代码！&lt;/p>
&lt;/blockquote>
&lt;h3 id="如何彻底删除-git-历史记录中的大文件">如何彻底删除 Git 历史记录中的大文件
&lt;/h3>&lt;p>本教程旨在解决一个常见问题：当你在 &lt;code>git push&lt;/code> 时，即使已经删除了某个大文件，GitHub 依然提示 &lt;code>GH001: Large files detected&lt;/code> 错误，导致推送失败。&lt;/p>
&lt;p>问题场景&lt;/p>
&lt;p>你执行了 &lt;code>git rm a_large_file.pkl&lt;/code> 并创建了一个新的 commit，但在推送时仍然看到类似下面的报错：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">remote: error: File your_project/a_large_file.pkl is 107.01 MB&lt;span class="p">;&lt;/span> this exceeds GitHub&lt;span class="err">&amp;#39;&lt;/span>s file size limit of 100.00 MB
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">remote: error: GH001: Large files detected.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">! &lt;span class="o">[&lt;/span>remote rejected&lt;span class="o">]&lt;/span> main -&amp;gt; main &lt;span class="o">(&lt;/span>pre-receive hook declined&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-20.png"
width="966"
height="596"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-20_hu7271088009656506584.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-20_hu5124425688743671859.png 1024w"
loading="lazy"
alt="问题"
class="gallery-image"
data-flex-grow="162"
data-flex-basis="388px"
>&lt;/p>
&lt;p>&lt;strong>原因是：&lt;/strong> Git 会保存每一次的提交记录。虽然你在最新的提交中删除了该文件，但它依然存在于仓库的过往历史中。推送时，GitHub 会检查所有历史记录，发现这个超大文件后便会拒绝接收。&lt;/p>
&lt;p>要解决此问题，必须从 Git 的历史记录中将该文件彻底清除。&lt;/p>
&lt;hr>
&lt;p>推荐方案：使用 &lt;code>git-filter-repo&lt;/code> (更简单、更快速)&lt;/p>
&lt;p>&lt;code>git-filter-repo&lt;/code> 是 Git 官方现在推荐用来清理历史记录的工具，它比 Git 的原生命令更高效且易于使用。&lt;/p>
&lt;p>1. 安装 &lt;code>git-filter-repo&lt;/code>&lt;/p>
&lt;p>如果尚未安装，请先执行安装。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>macOS (使用 Homebrew):&lt;/strong>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">brew install git-filter-repo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>对于其他系统，请参考其&lt;a class="link" href="https://www.google.com/search?q=https://github.com/newren/git-filter-repo/blob/main/INSTALL.md" target="_blank" rel="noopener"
>官方安装文档&lt;/a>。&lt;/li>
&lt;/ul>
&lt;p>2. 从历史记录中删除文件&lt;/p>
&lt;p>在你的本地仓库根目录运行以下命令。&lt;strong>此操作会重写历史记录&lt;/strong>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 将 &amp;#34;path/to/your/large_file.pkl&amp;#34; 替换为你的大文件实际路径&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git filter-repo --path &lt;span class="s2">&amp;#34;path/to/your/large_file.pkl&amp;#34;&lt;/span> --invert-paths
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这条命令会自动处理所有分支和标签，从中移除对指定文件的所有引用。&lt;/p>
&lt;p>3. 强制推送到远程仓库&lt;/p>
&lt;p>由于本地历史已被重写，你需要强制推送来覆盖远程仓库的历史。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push --force
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>备选方案：使用纯 Git 命令 &lt;code>git filter-branch&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-21.png"
width="966"
height="2382"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-21_hu12267635484686840794.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-21_hu18328967835013978016.png 1024w"
loading="lazy"
alt="git filter-branch"
class="gallery-image"
data-flex-grow="40"
data-flex-basis="97px"
>&lt;/p>
&lt;p>如果你不想安装任何新工具，可以使用 Git 内置的 &lt;code>filter-branch&lt;/code> 命令。&lt;/p>
&lt;p>&lt;strong>警告：&lt;/strong> 此命令非常复杂且速度慢，操作前强烈建议&lt;strong>备份你的整个项目文件夹&lt;/strong>。&lt;/p>
&lt;p>1. 执行历史重写命令&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 将 &amp;#34;path/to/your/large_file.pkl&amp;#34; 替换为你的大文件实际路径&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git filter-branch --force --index-filter &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s1">&amp;#39;git rm --cached --ignore-unmatch &amp;#34;path/to/your/large_file.pkl&amp;#34;&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>--prune-empty --tag-name-filter cat -- --all
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>--ignore-unmatch&lt;/code>: 确保在不包含该文件的历史 commit 上命令不会报错。&lt;/li>
&lt;li>此命令执行速度可能很慢，请耐心等待。&lt;/li>
&lt;/ul>
&lt;p>2. 清理仓库并回收空间&lt;/p>
&lt;p>&lt;code>filter-branch&lt;/code> 会留下备份。运行以下命令以彻底清除旧数据并压缩仓库。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git reflog expire --expire&lt;span class="o">=&lt;/span>now --all
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git gc --prune&lt;span class="o">=&lt;/span>now --aggressive
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>3. 强制推送&lt;/p>
&lt;p>同样，你需要强制推送来更新远程仓库。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push --force
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>未来建议：使用 Git LFS 管理大文件&lt;/p>
&lt;p>为了从根源上避免此类问题，当项目中必须包含大文件时，应使用 &lt;strong>Git Large File Storage (LFS)&lt;/strong>。&lt;/p>
&lt;p>Git LFS 会将大文件存储在专门的服务器上，而在你的仓库中只保留一个轻量级的指针文件，从而使仓库保持小巧和快速。&lt;/p>
&lt;p>LFS 快速上手&lt;/p>
&lt;ol>
&lt;li>&lt;strong>安装 LFS 客户端&lt;/strong>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># macOS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">brew install git-lfs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>在仓库中启用 LFS&lt;/strong> (每个项目只需执行一次)
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git lfs install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>追踪指定类型的文件&lt;/strong> (例如，所有 &lt;code>.pkl&lt;/code> 和 &lt;code>.onnx&lt;/code> 文件)
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git lfs track &lt;span class="s2">&amp;#34;*.pkl&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git lfs track &lt;span class="s2">&amp;#34;*.onnx&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>提交 &lt;code>.gitattributes&lt;/code> 文件&lt;/strong>
&lt;code>git lfs track&lt;/code> 命令会创建一个 &lt;code>.gitattributes&lt;/code> 文件，确保将它添加到版本控制中。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add .gitattributes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Configure Git LFS to track large files&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>之后，你就可以像平常一样 &lt;code>git add&lt;/code> 和 &lt;code>git commit&lt;/code> 大文件了，LFS 会自动处理它们。&lt;/li>
&lt;/ol>
&lt;h3 id="如何优雅地处理不再使用的-github-仓库">如何优雅地处理不再使用的 GitHub 仓库
&lt;/h3>&lt;p>当一个项目长期不用，但又不想彻底删除时，你有以下三种方法可以将其&amp;quot;隐藏&amp;quot;起来，同时保留代码。&lt;/p>
&lt;p>方案一：归档仓库 (Archive) - ⭐最推荐&lt;/p>
&lt;p>这是 GitHub 官方设计的最佳方案，用于封存项目。&lt;/p>
&lt;p>&lt;strong>效果:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>仓库从你的主页列表消失。&lt;/li>
&lt;li>项目变为只读，无法再推送新代码。&lt;/li>
&lt;li>&lt;strong>完整保留&lt;/strong>所有代码、提交历史、Issues、PRs、Wiki 和 Star。&lt;/li>
&lt;li>可以随时一键&amp;quot;取消归档&amp;quot;来恢复项目。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>操作步骤:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>进入仓库页面，点击 &lt;code>Settings&lt;/code> (设置)。&lt;/li>
&lt;li>在 &lt;code>General&lt;/code> (常规) 标签页，拉到最下方的 &lt;code>Danger Zone&lt;/code> (危险区域)。&lt;/li>
&lt;li>点击 &lt;code>Archive this repository&lt;/code> (归档这个仓库) 并确认。&lt;/li>
&lt;/ol>
&lt;p>方案二：设为私有仓库 (Make Private)&lt;/p>
&lt;p>如果只是不想让公众看到，但自己还可能修改。&lt;/p>
&lt;p>&lt;strong>效果:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>仓库从公开主页消失，只有你和协作者可见。&lt;/li>
&lt;li>所有功能（推送、提交）完全正常。&lt;/li>
&lt;li>&lt;strong>注意：&lt;/strong> 仓库在你自己的仓库列表中依然可见。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>操作步骤:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>进入仓库 &lt;code>Settings&lt;/code> -&amp;gt; &lt;code>General&lt;/code> -&amp;gt; &lt;code>Danger Zone&lt;/code>。&lt;/li>
&lt;li>点击 &lt;code>Change repository visibility&lt;/code> (更改仓库可见性)。&lt;/li>
&lt;li>选择 &lt;code>Make private&lt;/code> (设为私有) 并确认。&lt;/li>
&lt;/ol>
&lt;p>方案三：作为另一项目的分支 (不推荐)&lt;/p>
&lt;p>将旧仓库的历史合并到另一个项目中，然后删除旧仓库。这是一种复杂且有损的操作。&lt;/p>
&lt;p>&lt;strong>效果:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>代码和提交历史被合并到新项目的一个分支上。&lt;/li>
&lt;li>&lt;strong>警告：&lt;/strong> 将&lt;strong>永久丢失&lt;/strong>旧仓库所有的 Issues、PRs、Wiki 等宝贵记录。&lt;/li>
&lt;li>会使主项目的历史变得复杂。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>操作步骤 (命令行):&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. 进入你的主项目目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /path/to/main-project
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. 添加旧仓库为临时远程源&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote add old_repo https://github.com/user/old-repo.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. 拉取旧仓库数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch old_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. 基于旧仓库历史创建新分支 (假设其主分支为 main)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git switch -c archive/old-project old_repo/main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 5. 推送新分支到主项目&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push -u origin archive/old-project
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 6. 删除临时远程源&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote remove old_repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 7. 去 GitHub 网站上手动删除 old-repo 仓库&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>总结对比&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">方法&lt;/th>
&lt;th style="text-align: left">优点&lt;/th>
&lt;th style="text-align: left">缺点&lt;/th>
&lt;th style="text-align: left">推荐度&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>归档 (Archive)&lt;/strong>&lt;/td>
&lt;td style="text-align: left">保留所有记录、操作简单、可逆&lt;/td>
&lt;td style="text-align: left">项目只读&lt;/td>
&lt;td style="text-align: left">⭐⭐⭐⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>设为私有 (Private)&lt;/strong>&lt;/td>
&lt;td style="text-align: left">不公开、可继续编辑&lt;/td>
&lt;td style="text-align: left">仍在自己列表显示&lt;/td>
&lt;td style="text-align: left">⭐⭐⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">&lt;strong>作为分支合并&lt;/strong>&lt;/td>
&lt;td style="text-align: left">物理上整合代码&lt;/td>
&lt;td style="text-align: left">&lt;strong>丢失Issues/PRs等记录&lt;/strong>、操作复杂&lt;/td>
&lt;td style="text-align: left">⭐&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>结论：&lt;/strong> 对于&amp;quot;长期不用但想完整保留&amp;quot;的场景，请始终选择&lt;strong>归档 (Archive)&lt;/strong>。&lt;/p>
&lt;h3 id="一个电脑想要同时使用两个github账号ssh登录">一个电脑想要同时使用两个github账号ssh登录
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>第一步，生成另一个账号专用的ssh密钥和公钥，然后把公钥复制到那个账号的github里面&lt;/p>
&lt;/li>
&lt;li>
&lt;p>配置客户端以使用正确账号&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>vim ~/.ssh/config&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># zata-zhangtao 账号专用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Host github.com-zata
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> HostName github.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> User git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> IdentityFile ~/.ssh/id_ed25519_zata
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> IdentitiesOnly yes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>然后更新 remote URL ，使用自定义的Host&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 例如原本是： git@github.com:zata-zhangtao/ZataTree.git ，改成&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote set-url zata git@github.com-zata:zata-zhangtao/ZataTree.git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="恢复被-git-合并覆盖的提交并防止未来覆盖">恢复被 Git 合并覆盖的提交并防止未来覆盖
&lt;/h3>&lt;p>问题背景
主分支（&lt;code>main&lt;/code>）的修改在合并（如 &lt;code>zata_ssh/hugo&lt;/code>）时被覆盖，可能是快速合并或 &lt;code>ort&lt;/code> 策略自动选择远程分支内容导致。&lt;/p>
&lt;p>恢复被覆盖的提交&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>查看历史&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git reflog main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>找到合并前的提交（如 &lt;code>b510d7b&lt;/code>）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>恢复提交&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git reset --hard b510d7b
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>备份分支&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git branch main-backup main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>推送更改（谨慎）&lt;/strong>：
如果已推送到远程，需强制推送：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push --force
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>警告&lt;/strong>：提前通知团队，强制推送会影响远程历史。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>重新合并（避免覆盖）&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>拉取远程分支&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch zata_ssh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>非快速合并&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git merge --no-ff zata_ssh/hugo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>若有冲突，手动解决：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add &amp;lt;file&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>或使用变基&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout zata_ssh/hugo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git merge zata_ssh/hugo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>预防未来覆盖&lt;/p>
&lt;ul>
&lt;li>&lt;strong>禁用快速合并&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config --global merge.ff &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git config --global pull.ff only
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>预览差异&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git diff main zata_ssh/hugo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>测试合并&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout -b temp-merge
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git merge zata_ssh/hugo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;p>注意事项&lt;/p>
&lt;ul>
&lt;li>检查合并提交（&lt;code>61d17c8&lt;/code>, &lt;code>14e36c9&lt;/code>）的文件变化：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git show 61d17c8
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>确认 &lt;code>main&lt;/code> 跟踪分支：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git branch -vv
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="当前正在进行代码的开发但是想要看历史commit的项目完整代码而当前的工作区保证原样">当前正在进行代码的开发，但是想要看历史commit的项目完整代码，而当前的工作区保证原样
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 临时保存当前工作目录中的未提交更改&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git stash
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 切换到指定的 commit（替换 &amp;lt;commit id&amp;gt; 为实际的 commit 哈希值，例如 b2dfde96604dcce732aefccc4c7b4dc1fc8b161a）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout &amp;lt;commit id&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 返回到原始分支（替换 &amp;lt;branch name&amp;gt; 为实际的分支名，例如 main）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout &amp;lt;branch name&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 恢复之前保存的更改&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git stash pop
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="在-git-中如果你想回退到上一个版本继续开发同时保留已经提交到-main-分支的最新提交可以通过创建新分支并回退的方式实现">在 Git 中，如果你想回退到上一个版本继续开发，同时保留已经提交到 &lt;code>main&lt;/code> 分支的最新提交，可以通过创建新分支并回退的方式实现。
&lt;/h3>&lt;p>以下是一个推荐的方案和详细教程，基于 Git 的最佳实践，确保操作安全且保留所有历史记录。&lt;/p>
&lt;hr>
&lt;ul>
&lt;li>方案一(推荐)：&lt;/li>
&lt;/ul>
&lt;ol>
&lt;li>基于当前代码创建一个新分支，在新分支上介绍功能修改情况&lt;/li>
&lt;li>main分支回退到上一个版本&lt;/li>
&lt;li>接着在main分支上进行开发&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git branch &amp;lt;branchName&amp;gt; &lt;span class="c1"># 创建一个新分支&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git log --oneline &lt;span class="c1"># 查看历史commit，方便下面的切换&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git reset --hard &amp;lt;HEAD^ 或者 commitId&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>方案二：&lt;/li>
&lt;/ul>
&lt;ol>
&lt;li>直接在main分支上使用revert方法进行回退&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git revert HEAD
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这会创建一个新的提交，撤销本次更改，恢复上一步状态，但保留所有提交历史。然后可以继续在 &lt;code>main&lt;/code> 分支上开发。
&lt;img src="https://www.zata.cc/p/gitgithub/images/index/image-19.png"
width="362"
height="232"
srcset="https://www.zata.cc/p/gitgithub/images/index/image-19_hu16817798853553054885.png 480w, https://www.zata.cc/p/gitgithub/images/index/image-19_hu3042514927919901623.png 1024w"
loading="lazy"
alt="revert"
class="gallery-image"
data-flex-grow="156"
data-flex-basis="374px"
>&lt;/p>
&lt;h3 id="假设你当前在main分支暂存区有文件file1txt和file2txt想保存到新分支feature-branch">假设你当前在&lt;code>main&lt;/code>分支，暂存区有文件&lt;code>file1.txt&lt;/code>和&lt;code>file2.txt&lt;/code>，想保存到新分支&lt;code>feature-branch&lt;/code>
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout -b feature-branch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Add file1 and file2 to feature branch&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin feature-branch
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="排查-git-push失败问题">排查 Git push失败问题
&lt;/h3>&lt;p>当 &lt;code>git push&lt;/code> 失败并提示 &lt;code>Updates were rejected because the remote contains work that you do not have locally&lt;/code>，可以按照以下步骤查看远程仓库中的更改并解决问题：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>获取远程更改&lt;/strong>&lt;br>
运行 &lt;code>git fetch origin&lt;/code> 下载远程仓库的最新状态，不影响本地工作目录。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>比较本地与远程分支&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>查看提交历史：&lt;code>git log --oneline --graph --all&lt;/code>&lt;br>
显示本地 &lt;code>main&lt;/code> 和远程 &lt;code>origin/main&lt;/code> 的提交差异。&lt;/li>
&lt;li>查看文件差异：&lt;code>git diff --name-only origin/main main&lt;/code>&lt;br>
列出远程和本地分支间更改的文件。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>检查远程独有提交&lt;/strong>&lt;br>
使用 &lt;code>git log main..origin/main --oneline&lt;/code> 查看远程 &lt;code>origin/main&lt;/code> 中独有的提交。&lt;br>
查看具体提交内容：&lt;code>git show &amp;lt;commit-hash&amp;gt;&lt;/code>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>合并远程更改&lt;/strong>&lt;br>
运行 &lt;code>git pull origin main&lt;/code> 合并远程更改到本地。如有冲突，手动解决后提交。&lt;br>
然后推送：&lt;code>git push origin main&lt;/code>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>谨慎使用强制推送&lt;/strong>&lt;br>
若确定覆盖远程更改，运行 &lt;code>git push origin main --force&lt;/code>（注意：可能丢失他人工作，仅在确认安全时使用）。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>建议&lt;/strong>：优先检查远程更改（&lt;code>git fetch&lt;/code> 和 &lt;code>git log&lt;/code>），根据需要合并（&lt;code>git pull&lt;/code>）或强制推送。&lt;/p>
&lt;h3 id="推送当前分支到远程仓库并保持分支名">推送当前分支到远程仓库并保持分支名
&lt;/h3>&lt;p>要将当前分支推送到远程仓库并保持当前分支的名字，可以按照以下步骤操作：&lt;/p>
&lt;p>步骤&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>确认当前分支&lt;/strong>：
确保你位于正确的分支。运行以下命令查看当前分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git branch
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>当前分支会有一个 &lt;code>*&lt;/code> 标记，例如 &lt;code>* 0710display-prototype3&lt;/code>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>推送当前分支到远程仓库&lt;/strong>：
使用以下命令将当前分支推送到远程仓库（通常是 &lt;code>origin&lt;/code>），并保持相同的分支名：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push origin &lt;span class="k">$(&lt;/span>git branch --show-current&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>git branch --show-current&lt;/code> 会返回当前分支的名称（例如 &lt;code>0710display-prototype3&lt;/code>）。&lt;/li>
&lt;li>&lt;code>git push origin &amp;lt;branch-name&amp;gt;&lt;/code> 将当前分支推送到远程仓库的同名分支。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>设置上游分支（如果需要）&lt;/strong>：
如果这是第一次推送当前分支到远程仓库，Git 可能会提示当前分支没有上游分支（&lt;code>no upstream branch&lt;/code>）。你可以通过以下命令推送并同时设置上游分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push --set-upstream origin &lt;span class="k">$(&lt;/span>git branch --show-current&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或者简写为：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push -u origin &lt;span class="k">$(&lt;/span>git branch --show-current&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这会将当前分支推送到远程仓库，并将远程分支设置为当前分支的上游分支，方便后续直接使用 &lt;code>git push&lt;/code> 或 &lt;code>git pull&lt;/code>。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>示例
假设你的当前分支是 &lt;code>0710display-prototype3&lt;/code>，你可以运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push origin 0710display-prototype3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或者更通用地：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push origin &lt;span class="k">$(&lt;/span>git branch --show-current&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果需要设置上游分支：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push --set-upstream origin 0710display-prototype3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意事项&lt;/p>
&lt;ul>
&lt;li>&lt;strong>检查远程仓库&lt;/strong>：
确保远程仓库（如 &lt;code>origin&lt;/code>）已配置正确。运行 &lt;code>git remote -v&lt;/code> 查看远程仓库的 URL。&lt;/li>
&lt;li>&lt;strong>工作区状态&lt;/strong>：
确保你已提交所有更改（&lt;code>git commit&lt;/code>），否则运行 &lt;code>git status&lt;/code> 检查是否有未提交的更改。&lt;/li>
&lt;li>&lt;strong>分支名冲突&lt;/strong>：
如果远程仓库已存在同名分支，推送可能会失败（例如，提示需要拉取或强制推送）。可以先运行 &lt;code>git fetch origin&lt;/code> 检查远程分支状态，或者使用 &lt;code>git push --force&lt;/code>（谨慎使用，仅当你确定要覆盖远程分支）。&lt;/li>
&lt;/ul>
&lt;p>验证推送
推送完成后，运行以下命令确认远程分支已创建：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git branch -r
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你应该能看到 &lt;code>origin/0710display-prototype3&lt;/code> 在远程分支列表中。&lt;/p>
&lt;p>如果遇到任何错误（例如权限问题或冲突），请分享错误信息，我可以帮你进一步排查！&lt;/p>
&lt;h3 id="git-pull-时出现-cannot-lock-ref-错误的解决方案">git pull 时出现 &amp;ldquo;cannot lock ref&amp;rdquo; 错误的解决方案
&lt;/h3>&lt;p>当执行 &lt;code>git pull&lt;/code> 时出现类似以下错误：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">error: cannot lock ref &amp;#39;refs/remotes/zata/hugo&amp;#39;: unable to resolve reference &amp;#39;refs/remotes/zata/hugo&amp;#39;: reference broken
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个错误通常是因为本地的 Git 引用缓存与远程仓库状态不一致导致的。&lt;/p>
&lt;p>问题原因&lt;/p>
&lt;ol>
&lt;li>&lt;strong>远程分支被强制更新&lt;/strong>：远程仓库的分支可能被强制推送（&lt;code>git push --force&lt;/code>），导致本地缓存的提交哈希值与远程最新的提交哈希值不匹配。&lt;/li>
&lt;li>&lt;strong>本地引用损坏或不一致&lt;/strong>：本地的 &lt;code>.git/refs/remotes/&lt;/code> 文件可能被锁定、损坏，或者由于网络中断等原因未正确更新。&lt;/li>
&lt;li>&lt;strong>Git 缓存问题&lt;/strong>：Git 的引用日志或跟踪分支信息可能出现了问题，导致无法正常同步。&lt;/li>
&lt;/ol>
&lt;p>解决方法
以下是几种解决方法，建议按顺序尝试：&lt;/p>
&lt;p>&lt;strong>方法 1：清理并重新拉取&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch --prune
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>git fetch --prune&lt;/code> 会更新本地对远程分支的跟踪信息，并删除远程已不存在的分支引用。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>方法 2：强制更新本地引用&lt;/strong>
如果确认远程分支的最新状态是你需要的，可以强制更新本地的远程分支引用：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git update-ref refs/remotes/zata/hugo origin/hugo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>git update-ref&lt;/code> 手动将本地的远程分支引用更新为远程分支的最新状态。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>方法 3：删除并重置本地跟踪分支&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">rm .git/refs/remotes/zata/hugo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>手动删除本地引用文件，然后重新获取远程分支信息并拉取。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>方法 4：检查锁文件&lt;/strong>
错误信息提到&amp;quot;cannot lock ref&amp;quot;，可能是因为存在锁文件导致引用无法更新：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">rm .git/refs/remotes/zata/hugo.lock
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>如果存在锁文件，删除它以解除锁定。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>方法 5：彻底清理并重新克隆（最后手段）&lt;/strong>
如果以上方法都无效，且你不介意丢失本地未提交的更改：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -rf ZataTree
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://github.com/zata-zhangtao/ZataTree.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ZataTree
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;strong>注意&lt;/strong>：在执行此操作前，请备份所有本地未提交的更改（例如通过 &lt;code>git stash&lt;/code> 或复制工作目录）。&lt;/li>
&lt;/ul>
&lt;p>预防措施&lt;/p>
&lt;ol>
&lt;li>&lt;strong>避免强制推送&lt;/strong>：如果多人协作，尽量避免对公共分支使用 &lt;code>git push --force&lt;/code>，改用 &lt;code>git push --force-with-lease&lt;/code> 以减少冲突。&lt;/li>
&lt;li>&lt;strong>定期清理&lt;/strong>：定期运行 &lt;code>git fetch --prune&lt;/code> 清理无效的远程分支引用。&lt;/li>
&lt;li>&lt;strong>检查网络&lt;/strong>：确保网络连接稳定，避免 &lt;code>git pull&lt;/code> 中断导致引用不一致。&lt;/li>
&lt;/ol>
&lt;h3 id="git-无法识别文件名大小写更改一文彻底解决重命名难题">Git 无法识别文件名大小写更改？一文彻底解决重命名难题
&lt;/h3>&lt;blockquote>
&lt;p>适用场景：你在 Windows 或 macOS 上将 &lt;code>readme.md&lt;/code> 改为 &lt;code>Readme.md&lt;/code>，但 &lt;code>git status&lt;/code> 却毫无反应——别慌，这不是 Git 的 bug，而是文件系统的“锅”。本文教你如何正确处理 Git 中的大小写重命名。&lt;/p>
&lt;/blockquote>
&lt;p>你执行了如下操作：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mv readme.md Readme.md
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>结果 Git &lt;strong>完全没反应&lt;/strong>，仿佛什么都没发生。即使你强制 &lt;code>git add Readme.md&lt;/code>，Git 可能还会报错：“文件已存在”或“路径冲突”。&lt;/p>
&lt;p>为什么？&lt;/p>
&lt;p>Git 本身是支持文件名大小写的，但它会&lt;strong>尊重底层操作系统的文件系统行为&lt;/strong>：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>操作系统&lt;/th>
&lt;th>文件系统&lt;/th>
&lt;th>是否区分大小写&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Linux&lt;/td>
&lt;td>ext4, XFS 等&lt;/td>
&lt;td>✅ 是&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>macOS&lt;/td>
&lt;td>APFS / HFS+（默认）&lt;/td>
&lt;td>❌ 否&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Windows&lt;/td>
&lt;td>NTFS&lt;/td>
&lt;td>❌ 否&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>在 macOS 和 Windows 上，&lt;code>readme.md&lt;/code> 和 &lt;code>Readme.md&lt;/code> 被视为&lt;strong>同一个文件&lt;/strong>。因此，当你重命名时，文件系统认为“文件没变”，Git 也就检测不到任何修改。&lt;/p>
&lt;blockquote>
&lt;p>💡 这不是 Git 的缺陷，而是为了兼容性做出的设计选择。&lt;/p>
&lt;/blockquote>
&lt;p>✅ 正确解决方案：使用 &lt;code>git mv&lt;/code> 分两步走&lt;/p>
&lt;p>由于直接重命名会被文件系统“吞掉”，我们需要&lt;strong>绕过文件系统的限制&lt;/strong>。最可靠的方法是：&lt;strong>先改成一个临时名字，再改成目标名字&lt;/strong>。&lt;/p>
&lt;p>步骤示例&lt;/p>
&lt;p>假设你想把 &lt;code>login.js&lt;/code> 改为 &lt;code>Login.js&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 第一步：重命名为临时文件（名字不能和原名仅大小写不同）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git mv login.js temp_login.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 第二步：从临时文件重命名为目标文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git mv temp_login.js Login.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 提交更改&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Rename login.js to Login.js&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>✅ 这样 Git 就会正确记录为一次 &lt;strong>重命名操作&lt;/strong>，而不是“删除 + 新增”，保持历史连续性。&lt;/p>
&lt;p>⚠️ 常见误区&lt;/p>
&lt;p>❌ 直接在文件管理器中改名&lt;/p>
&lt;ul>
&lt;li>在 Finder（macOS）或资源管理器（Windows）里右键重命名 → Git 无法感知。&lt;/li>
&lt;li>结果：Git 认为原文件被删除，新文件未跟踪。&lt;/li>
&lt;/ul>
&lt;p>❌ 强行设置 &lt;code>core.ignorecase false&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config core.ignorecase &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>虽然能让 Git “假装”区分大小写，但在不支持的系统上会导致状态混乱（比如误报文件丢失）。&lt;/li>
&lt;li>&lt;strong>不推荐&lt;/strong>，尤其在团队协作中可能引发更多问题。&lt;/li>
&lt;/ul>
&lt;p>🛠️ 高级技巧：批量重命名脚本（可选）&lt;/p>
&lt;p>如果你有多个文件需要改名，可以写个小脚本：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="c1"># rename_case.sh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">old&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;myfile.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">new&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;MyFile.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git mv &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$old&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;temp_&lt;/span>&lt;span class="nv">$$&lt;/span>&lt;span class="s2">.&lt;/span>&lt;span class="nv">$old&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git mv &lt;span class="s2">&amp;#34;temp_&lt;/span>&lt;span class="nv">$$&lt;/span>&lt;span class="s2">.&lt;/span>&lt;span class="nv">$old&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$new&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Renamed &lt;/span>&lt;span class="nv">$old&lt;/span>&lt;span class="s2"> → &lt;/span>&lt;span class="nv">$new&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">chmod +x rename_case.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">./rename_case.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;code>$&lt;/code>$ 是进程 ID，确保临时文件名唯一。&lt;/p>
&lt;/blockquote>
&lt;p>🌐 跨平台协作建议&lt;/p>
&lt;p>如果你的团队同时使用 Windows、macOS 和 Linux，请遵守以下规范：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>避免仅靠大小写区分文件名&lt;/strong>
❌ 不要同时存在 &lt;code>User.js&lt;/code> 和 &lt;code>user.js&lt;/code>&lt;/li>
&lt;li>&lt;strong>统一命名风格&lt;/strong>
✅ 推荐全小写 + 下划线/短横线：&lt;code>user_profile.js&lt;/code> 或 &lt;code>user-profile.js&lt;/code>&lt;/li>
&lt;li>&lt;strong>重命名一律用 &lt;code>git mv&lt;/code>&lt;/strong>
即使在 Linux 上，也养成好习惯&lt;/li>
&lt;/ol>
&lt;p>🔚 总结&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>问题&lt;/th>
&lt;th>原因&lt;/th>
&lt;th>解决方案&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Git 不识别大小写重命名&lt;/td>
&lt;td>文件系统不区分大小写（Win/macOS）&lt;/td>
&lt;td>✅ 用 &lt;code>git mv&lt;/code> 分两步重命名&lt;br>✅ 避免仅靠大小写区分文件&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>记住：&lt;strong>Git 是忠实的记录者，但它的“眼睛”受限于操作系统&lt;/strong>。理解这一点，就能从容应对各种“诡异”行为。&lt;/p>
&lt;p>📌 小贴士：下次遇到类似问题，先问自己——“我的文件系统真的支持这个操作吗？”&lt;/p>
&lt;p>&lt;strong>作者&lt;/strong>：你的名字
&lt;strong>标签&lt;/strong>：#Git #开发技巧 #跨平台开发 #版本控制
&lt;strong>发布时间&lt;/strong>：2026年1月16日&lt;/p>
&lt;h3 id="如何将clone下来的项目推送到自己的新仓库并同步原始仓库更新">如何将clone下来的项目推送到自己的新仓库并同步原始仓库更新
&lt;/h3>&lt;p>当你 &lt;code>clone&lt;/code> 一个项目，你的本地仓库默认会有一个名为 &lt;code>origin&lt;/code> 的远程连接，指向你克隆的那个仓库地址。现在你既想保留自己的修改，又想同步原始仓库的更新，并最终将所有代码推送到你自己的一个全新仓库。&lt;/p>
&lt;p>下面是详细的步骤，分为两种情况：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>方案一：简单直接，将推送目标&amp;quot;切换&amp;quot;到你的新仓库。&lt;/strong>&lt;/li>
&lt;li>&lt;strong>方案二：最佳实践，同时管理&amp;quot;原始仓库&amp;quot;和&amp;quot;你的仓库&amp;quot;两个远程地址。&lt;/strong> (推荐)&lt;/li>
&lt;/ul>
&lt;p>前提：创建你自己的远程仓库&lt;/p>
&lt;hr>
&lt;p>无论使用哪种方案，你都需要先在代码托管平台（如 GitHub、Gitee、GitLab）上创建一个&lt;strong>空的&lt;/strong>新仓库。&lt;/p>
&lt;p>&lt;strong>非常重要：&lt;/strong> 创建仓库时，&lt;strong>不要&lt;/strong>勾选&amp;quot;使用README文件初始化仓库&amp;quot;、&amp;ldquo;添加 .gitignore&amp;rdquo; 或 &amp;ldquo;选择许可证&amp;rdquo;，以避免产生不兼容的提交历史。&lt;/p>
&lt;p>创建好之后，复制新仓库的 URL 地址（HTTPS 或 SSH 格式），比如 &lt;code>https://github.com/your-username/your-new-repo.git&lt;/code>。&lt;/p>
&lt;hr>
&lt;p>方案一：切换远程仓库地址 (简单直接)&lt;/p>
&lt;p>这个方案直接把本地仓库的 &lt;code>origin&lt;/code> 指向从原始仓库地址修改为你的新仓库地址。&lt;/p>
&lt;p>第一步：提交你的本地更改&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;这里写下你的提交信息，比如：添加了xx功能&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第二步：同步原始仓库的更新&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git pull --rebase origin main &lt;span class="c1"># 如果你的分支不是 main，请替换为实际分支名&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>git pull --rebase&lt;/code> 会先拉取原始仓库的新提交，再把你本地的提交&amp;quot;重新播放&amp;quot;在最前面，保持提交历史线性。&lt;/li>
&lt;li>如果遇到冲突，解决后用 &lt;code>git add &amp;lt;文件名&amp;gt;&lt;/code> 标记解决，然后 &lt;code>git rebase --continue&lt;/code>。&lt;/li>
&lt;/ul>
&lt;p>第三步：更改远程仓库 &lt;code>origin&lt;/code> 的 URL&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git remote -v &lt;span class="c1"># 查看当前远程仓库地址&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote set-url origin &amp;lt;你自己的新仓库URL&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote -v &lt;span class="c1"># 再次确认&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第四步：推送到你自己的仓库&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push -u origin main &lt;span class="c1"># -u 建立本地分支与远程分支的追踪关系&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>方案二：添加新的远程仓库 (最佳实践)&lt;/p>
&lt;p>这个方案保留了原始仓库的连接（通常命名为 &lt;code>upstream&lt;/code>），同时添加你自己的仓库作为新的远程连接（通常还叫 &lt;code>origin&lt;/code>）。这样做的好处是，未来你还可以随时方便地从原始仓库拉取更新。&lt;/p>
&lt;p>第一步和第二步：同方案一&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;你的提交信息&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull --rebase origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第三步：重命名原始仓库并添加你自己的仓库&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git remote rename origin upstream &lt;span class="c1"># 原始仓库重命名为 upstream&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote add origin &amp;lt;你自己的新仓库URL&amp;gt; &lt;span class="c1"># 添加你自己的仓库为 origin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git remote -v &lt;span class="c1"># 检查远程仓库配置&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>此时你应该能看到：&lt;/p>
&lt;ul>
&lt;li>&lt;code>origin&lt;/code> 指向你的新仓库地址（可读写）。&lt;/li>
&lt;li>&lt;code>upstream&lt;/code> 指向你最初克隆的那个原始仓库地址（通常是只读的）。&lt;/li>
&lt;/ul>
&lt;p>第四步：推送到你自己的仓库&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git push -u origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>未来的工作流&lt;/p>
&lt;ul>
&lt;li>推送自己的修改：&lt;code>git push origin main&lt;/code>&lt;/li>
&lt;li>同步原始项目的更新：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch upstream
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase upstream/main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>常见问题与注意事项&lt;/p>
&lt;ul>
&lt;li>&lt;strong>分支名不是 main？&lt;/strong>
&lt;ul>
&lt;li>如果你的分支名是 &lt;code>master&lt;/code> 或其他，请将命令中的 &lt;code>main&lt;/code> 替换为实际分支名。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>遇到冲突怎么办？&lt;/strong>
&lt;ul>
&lt;li>Git 会提示你解决冲突。解决后 &lt;code>git add &amp;lt;文件&amp;gt;&lt;/code>，然后 &lt;code>git rebase --continue&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>推送时遇到权限问题？&lt;/strong>
&lt;ul>
&lt;li>检查你是否有新仓库的写权限，或 SSH/Token 配置是否正确。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>未来如何同步原始仓库的更新？&lt;/strong>
&lt;ul>
&lt;li>只需 &lt;code>git fetch upstream&lt;/code>，然后 &lt;code>git rebase upstream/main&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item></channel></rss>