13太保玩转github-第2太保-李嗣昭-本地客户端
13太保玩转github-第02太保-胆勇谨厚-本地客户端与Git/gh基本功三套入口不是三套流程先把基本功练成条件反射text[读者] 会用 Git但 Desktop、命令行、gh 各记一套[痛点] 换台机器就复现不出昨天的操作[现在读] springaialibabapractice 要求本地流程可复现[读完] 能统一三入口产出可验证的本地配置文档text[旧方案] 桌面点几下 命令行补两刀 gh 现查现用 | v[新需求] 多维护者协作同一仓库、同一提交规范 | v[冲突] 三套入口三套记忆Git 状态在脑子里对不上 | v[后果] 提交混入无关文件PR 描述现编换台机器重来我是老李手里维护的是 lifuchun522/springaialibabapractice。第 01 篇把仓库骨架和分支约定立住了这一篇要解决的问题更土同一件事团队里三个人能用三种方式做出来结果还不一样。《新五代史》写这位太保「胆勇过人」又写他「谨厚」受戒之后能长期自律。放到工具链上胆勇是敢直接上手敲命令谨厚是不给自己留侥幸——配置写一次、流程记一次以后不再靠记忆救场。任务是围绕「本地客户端」把 GitHub 的产品能力落到这个仓库上不是只看界面会点哪里而是做完之后有可验证的配置、可复现的输出、可交接的文档。三套入口要不要统一成一条流程这些配置该写进仓库还是留在个人机器上如果只有老李能跑通这套流程算不算成立# 01、故事周三下午仓库要新增一个 GitHub 操作文档目录。同事按自己的习惯动手打开 GitHub DesktopFile → Clone repositoryCurrent branch → New branch 建了分支改完文件在 Changes 里写了 Summary点了 Commit然后就停住了——他不知道 PR 在哪里建。换到另一台机器上老李用命令行三分钟走完同一条路clone、switch、add、commit、push、gh pr create。两件事都做成了但没人说得清哪一步必须验证、哪一步可以随手点。当前方案是「谁的机器谁说了算」有人用命令行有人用桌面客户端还有人用 IDE 内置的 Git。变化在于githubops/NN-*教程分支要和项目自身的chapter/NN-*功能分支并行存在仓库开始多人并行维护靠「我记得我推过了」已经不够。冲突也在这里Desktop 把 Git 状态藏在按钮后面命令行把状态摆在眼前两者本身并不冲突真正冲突的是没人规定过哪一步用哪个入口、哪一步必须留下证据。工具越顺手越容易在无约束的状态下各走各的。 三入口并行 一条线未定 手熟非本事 可复现才算# 02、问题旧方案在单机单人的时候毫无问题一个人、一台机器、一套肌肉记忆快且省事。一旦换人换机器记忆链就断在第一步。业务影响是可感知的PR 里混进.env、IDE 临时文件、日志评审时间被消耗在区分「真改动」和「噪音」上历史追溯困难回滚时不知道该回滚哪一处。技术表现同样可观测git status里堆着一批未跟踪的本地文件git diff --stat显示整文件重写本地有提交而远端没有gh pr create因为未认证直接失败提交信息五花八门无法按范围过滤历史。本章要拿到的可验证完成标准- 新克隆的仓库按docs/github-ops/02-local-clients.md执行能走完 clone → 分支 → 提交 → push → PR 全链路- 提交的 diff 只包含预期文件不出现换行符噪音- 提交完成后git status干净- 文档里记录的命令输出与实际执行结果一致别人能照着复跑。这四条都能被第三方核对不是「感觉差不多了」。 记忆不可靠 状态要摆明 标准能验证 流程才算成# 03、原理这一章只讲三个支撑后面所有操作的原理。第一三个入口一个内核。GitHub Desktop、git、gh 最终都作用在同一份 Git 对象库和同一套 GitHub 平台上。Desktop 是一个真正的 Git 客户端它把工作区、暂存区、本地提交、推送这些状态可视化但它不是 GitHub SaaS 的替代品分支保护、PR 评审、Actions、权限都在平台那一侧。把这条边界想清楚才不会出现「我在本地提交了为什么没人来评审」的错觉。第二提交的边界由暂存区决定不由编辑器决定。git add -p允许你只暂存某一个 hunkDesktop 的 Changes 勾选框是同一件事的图形表达。谁控制了 index谁就决定了这次提交表达什么语义。这条原理解释了后面所有「diff 里为什么多出无关文件」的问题。第三认证是账号级能力仓库里不该出现凭据。gh auth login、SSH key、HTTPS 凭据管理器解决的是「你是谁」这是一次性问题而.env、token 文件属于内容必须被.gitignore挡住。把这两件事分层才能避免把密钥写进历史的灾难。反直觉判断图形客户端用得越顺越需要命令行。因为 GUI 把最容易出问题的那部分状态——index、远端跟踪引用、换行符转换——藏到了界面之后而排障恰恰要从这些状态开始。 界面遮状态 命令见真身 边界在暂存 凭据不入仓# 04、架构text[输入] 一次本地改动 | v[模块] 工作区 / 暂存区 / 本地仓库 / 远端 | v[数据/状态] index、HEAD、分支引用、远端跟踪引用 | v[处理] add → commit → push → PR | v[输出] 远端分支 Pull Request 评审记录边界三套入口共用同一台状态机不能各自演一套。Desktop 覆盖的是最常用的那条路径gh 覆盖的是仓库与 PR 级别的操作git 覆盖其余一切。任何入口做的动作都应该能被另外两个解释和验证。收益一次配置、三条入口、一个结果。换机器只需要重放配置不需要重放记忆。代价需要先把策略定下来——默认分支名、pull.rebase的取舍、换行符策略——并且把这些策略写进仓库而不是写进个人笔记。前期会多花一点时间。适用条件单仓库、多维护者、走 PR 评审流程的团队。如果只有一个人且永不复现这套约束并不划算。 一内核三面 同状态同源 策略先统一 再谈快与慢# 05、实战一次目标跑通最小但完整的链路并产出本章产物。环境以你本机实际安装版本为准Git for Windows 或 macOS 系统 Git、GitHub Desktop、GitHub CLIgh。依赖网络可访问 github.com账号对lifuchun522/springaialibabapractice具备读写权限。第一步全局配置只做一次属于账号级bashgit config --global user.name 你的名字git config --global user.email 你的邮箱git config --global init.defaultBranch maingit config --global pull.rebase falsegit config --global core.autocrlf true # WindowsmacOS/Linux 视团队策略取 input 或 falsegit config --list --show-origincore.autocrlf 必须与团队策略一致pull.rebase 也要显式设定不要让 Git 用默认行为替你决定。第二步克隆仓库并建教程分支bashgit clone https://github.com/lifuchun522/springaialibabapractice.gitcd springaialibabapracticegit switch -c githubops/02-local-clientsgit status示例输出consoleOn branch githubops/02-local-clientsnothing to commit, working tree clean第三步写 .gitignore把不该进仓库的东西挡在外面gitignore.env.env.**.loglogs/.idea/.vscode/.DS_StoreThumbs.dbtarget/build/再补一份 .gitattributes把换行符从个人设置升级为仓库契约gitattributes* textauto eollf*.bat text eolcrlf*.cmd text eolcrlf*.png binary*.jpg binary第四步GitHub Desktop 侧菜单保持官方英文形式- File → Clone repository确认远端仓库地址与本地目录- Current branch → New branch创建 githubops/02-local-clients- Changes → Summary / Description → CommitSummary 写提交主题Description 写动机- Push origin把本地提交推到远端- Branch → Create pull request从当前分支直达 PR 页面。第五步命令行侧同一条流程的另一种表达bashgit add -pgit add docs/github-ops/02-local-clients.mdgit statusgit commit -m docs(gh02): document desktop git and gh workflowsgit push -u origin githubops/02-local-clients第六步gh 侧的认证与 PRbashgh auth logingh auth statusgh repo view --webgh pr create --fillgh pr create --fill会用提交信息预填标题与正文但它只是省去手打最后仍然要人工确认内容再提交自动填充不等于可以跳过评审。第七步写产物文档docs/github-ops/02-local-clients.md至少包含三块内容Desktop 英文菜单到中文解释的对照表、Git 与 gh 常用命令速查、三入口等价关系表并附上本次的验收记录。对照表示例| Desktop 菜单英文 | 中文解释 | 对应的 git / gh 命令 || --- | --- | --- || File → Clone repository | 文件 → 克隆仓库把远端仓库拉成本地目录 |git clone|| Current branch → New branch | 当前分支 → 新建分支基于当前 HEAD 建分支并切换 |git switch -c|| Changes → Commit | 变更 → 提交把已勾选的改动写成本地提交 |git add -pgit commit|| Push origin | 推送源端把本地提交推到 origin |git push -u origin|| Branch → Create pull request | 分支 → 创建拉取请求从当前分支发起 PR |gh pr create --fill|验收方式在一台干净的机器或一个全新的克隆目录上照文档从零执行能走到 PR 创建成功并且git status干净、git diff --stat只有预期文件。说明本节中的命令与界面路径来自 GitHub 官方文档Desktop 入门见 https://docs.github.com/en/desktop/overview/getting-started-with-github-desktop gh 命令手册见 https://cli.github.com/manual/gh 。具体命令输出与截图需要你在自己的环境执行后补入docs/github-ops/未在当前环境实测的部分以下为预期结果。 先配再动手 一次只一事 输出留证据 他人能重放# 06、排查## 诊断一Desktop 里提交成功GitHub 上看不到现象在 Desktop 里点了 Commit界面提示成功但远端分支上没有新提交。怀疑提交只写进了本地仓库或者被推到了另一个分支。检查git status、git log --oneline -3、git log origin/githubops/02-local-clients --oneline -3。证据git status输出Your branch is ahead of ‘origin/githubops/02-local-clients’ by 1 commit本地日志比远端多一条。根因Commit 和 Push 是两个动作。Commit 是纯粹的本地对象写入Push origin 才是网络动作Desktop 把它们放在两个按钮上命令行把它们放在两条命令里。修复点 Push origin或者执行git push -u origin githubops/02-local-clients。**错误尝试** 在 Desktop 里再点一次 Commit。为什么错误Commit 是本地幂等动作重复提交会让同一份改动变成两个提交历史更乱而且它完全没有触碰「没有推送」这个真正的问题。正确顺序是先读状态再决定是推还是改。## 诊断二只改了几行diff 却被标成整文件重写现象git diff --stat显示整个文件被删再加内容其实只改了几行。怀疑Windows 工作区的 CRLF 与仓库里的 LF 之间发生了转换。检查git config core.autocrlf、仓库根目录是否存在.gitattributes、git diff --stat的具体行数。证据diff 中每一行都同时出现在减号和加号里文字内容一致只有行尾不可见。根因工作区使用 CRLF、仓库使用 LF缺少统一策略时Git 会把行尾差异当成内容差异。修复加入.gitattributes* textauto eollf让core.autocrlf与团队策略一致然后执行git add --renormalize .重新规范化并把这批规范化单独提交一次避免和业务改动混在一起。**错误尝试** 让每个人自己去编辑器里把换行符改成 LF。为什么错误编辑器设置属于个人环境不可复现也不可审计下一个人克隆下来会再次重演同样的问题。策略必须落在仓库里。## 诊断三gh 命令报未认证现象执行gh pr create时提示需要先认证。怀疑本机未登录或者登录的 token 缺少所需权限。检查gh auth status。证据输出显示未登录到 github.com或者缺少repo相关 scope。根因gh 使用的是账号级凭据与 Git 推送用的凭据是两套东西登录一次不等于另一套也配好了。修复执行gh auth login重新登录并选择需要的 scope使用 SSH 的场景在 GitHub 网页端 Settings → SSH and GPG keys 检查公钥是否已登记凭据本身不要写进仓库也不要贴进文档。 先看状态表 再谈改代码 强推非解法 证据定根因# 07、优化V2 的全部改动都来自第 06 章的证据不做无依据的加固。根因归纳成三条状态不可见、策略不可复现、凭据与内容混在一起。修改一把策略写进仓库。新增.gitattributes* textauto eollf二进制文件单独声明让换行符从个人设置变成仓库契约。修改原因诊断二证明问题出在策略缺失而不是某台机器。新行为任何机器克隆后行尾转换规则由仓库决定。验证重新克隆后git diff --stat不再出现整文件重写。修改二把排除规则写进.gitignore。.env、.env.、.log、logs/、.idea/、.vscode/、target/、build/一律不入仓。修改原因诊断一暴露的git status噪音。新行为提交后工作区干净。验证git status输出 working tree clean。修改三把提交边界显式化。统一用git add -p或 Desktop 的 Changes 勾选一次提交只表达一件事提交信息采用docs(gh02): …这类前缀便于按范围过滤历史。修改原因混提交让回滚和评审变贵。新行为每个提交可以单独回滚。验证git log --oneline中每条提交描述自洽。修改四把三入口映射成同一张流程表写进docs/github-ops/02-local-clients.mdDesktop 的五个菜单路径与 git、gh 命令一一对照。修改原因诊断一的本质是入口之间没有对照关系。新行为任选一个入口都能查到等价操作。验证让另一位维护者只看文档完成一次贡献。修改五把认证分层写清楚。账号级凭据SSH key、gh token只在 Settings 检查不进仓库项目级配置.gitignore、.gitattributes进仓库。修改原因诊断三说明身份与内容必须分层。新行为文档里永远不出现任何密钥。验证对文档做一次关键字自查。以上验证方式都需要在实际环境中执行后记录真实输出本文不提供任何推测性的性能或收益数字。 契约进仓库 排除进配置 提交只一事 换机亦如初# 08、演进text[同一输入一次本地改动] | --[V1] 靠记忆选入口 / 代价状态不可见、换机重来 | --[V2] 契约进仓库 三入口映射 / 代价需先统一策略前期多花时间 |[Trade-off]得到可复现、可审计、可交接失去随手一点的自由以及「我这台机器能跑」的侥幸边界单仓库多维护者收益最大个人玩具仓库不值得逐项比较正确性方面V1 依赖个人记忆V2 依赖仓库内契约后者可以被第三方验证。稳定性方面V2 消除了换行符与未跟踪文件带来的噪音diff 更稳定评审更聚焦。复杂度方面V2 多了两个配置文件与一份文档新人的阅读成本上升这是明确的代价。成本方面V2 是一次性前期投入收益从第二位维护者加入时开始兑现。适用范围方面适合走 PR 评审的多人仓库单人短周期实验仓库不必套用。遗留问题方面分支合并策略在团队层面仍需显式约定pull.rebase只是把它显性化并没有替你做出选择同时 Desktop 与 gh 的版本更新可能调整菜单位置文档需要随版本维护。 旧法靠记忆 新法靠契约 得失皆明处 边界自划清# 09、洞见## 9.1 入口可以多流程只能有一条反直觉判断工具越多越应该砍流程而不是给每个工具配一套流程。Desktop、git、gh 是三面镜子照的是同一份状态一旦允许它们各自为政成本不是线性增加而是组合爆炸。判断标准很简单这次操作能否用另外两个入口解释清楚## 9.2 影响克隆结果的进仓库影响你是谁的在账号层反直觉判断把配置写进教程比写进仓库更难维护。教程会过期仓库里的.gitattributes每次克隆都会生效。凡是影响「别人克隆后得到什么」的进仓库凡是只影响「你是谁」的凭据、SSH key留在账号层在 Settings 里检查即可。## 9.3 提交边界是设计出来的不是攒出来的git add -p与 Desktop 的勾选框表达的是同一个真相一次提交的语义由 index 决定。提交前滚一遍变更列表是成本最低的一次自我评审也是后续回滚粒度的决定因素。## 9.4 排障从状态开始不从操作开始反直觉判断遇到问题第一反应是「再点一次、再敲一次」往往是在制造更难回滚的历史。先看git status、git log、gh auth status把状态读明白操作才有方向强制覆盖和强推通常只推迟了问题的暴露时间。 多面不多流 契约入仓库 提交先设计 排障先看态# 10、系统落地原来有什么一个只有提交历史、没有本地操作约定的仓库每个人一套习惯靠记忆维持一致性。本篇新增了什么docs/github-ops/02-local-clients.md这份本地客户端操作规范以及其中的 Desktop 菜单对照表、Git 与 gh 命令速查、三入口等价关系表仓库层面的.gitignore与.gitattributes契约一条从 clone 到 PR 的三入口等价流程。分支落在githubops/02-local-clients建议提交信息为docs(gh02): document desktop git and gh workflows。现在能做什么任意一位维护者在一台干净机器上按文档执行可以独立完成一次完整贡献并且产出的 diff 只包含预期文件结果可被他人核对。还缺什么分支合并策略pull.rebase与合并方式还没有在团队层面写死缺少自动化守门比如检测敏感文件是否被误提交、检查换行符规范化缺少 PR 模板与评审清单评审质量仍然依赖评审者的经验。下一步如何演进把本地流程接到仓库自动化上用 GitHub Actions 做最低限度的守门把「靠人记得」的部分继续迁移到「靠机制保证」让本地客户端规范从文档变成流程的一部分。 旧仓无约定 新约入版本 尚缺自动化 且行且补齐# 11、小结textQ1 → 要统一三个入口共用一条可验证流程而不是三套习惯Q2 → 影响克隆结果的写进仓库影响身份的在账号层检查Q3 → 换人按文档在干净环境重放一次能走到 PR 创建成功就算可复现状态 → 本地三入口已收敛为一条流程产物落在 docs/github-ops/ 三问皆有答 一档可重放 流程已收敛 余下自动化# 12、作业## 12.1 理解题为什么说 GitHub Desktop 不是 GitHub SaaS 的替代品参考答案Desktop 是运行在本地的 Git 客户端负责工作区、暂存区、本地提交与推送这一段平台侧的分支保护、PR 评审、Actions、权限属于 SaaS 能力。二者是同一条流程的不同段落不能互相替代。把它当成 SaaS 用就会出现「我在本地提交了为什么没人评审」的错觉。## 12.2 实战题在一个全新克隆的目录里把 clone → 分支 → 提交 → push → PR 完整走一遍并记录输出。参考答案git clone→git switch -c githubops/02-local-clients→ 修改文件 →git add -p→git commit -m docs(gh02): …→git push -u origin githubops/02-local-clients→gh pr create --fill。验收看三点git status干净、git diff --stat只含预期文件、远端出现对应 PR。真实输出需要你自己采集并写入docs/github-ops/。## 12.3 排障题git diff --stat显示整个文件被重写如何定位与修复参考答案先看git config core.autocrlf和是否存在.gitattributes判断是否为行尾差异确认后用.gitattributes统一为* textauto eollf执行git add --renormalize . 单独提交一次规范化。不要用强制覆盖或者强推来掩盖问题那样只会把问题推给下一个人。## 12.4 架构判断题团队里有人只用 Desktop、有人只用命令行是否应该禁止其中一种参考答案不应该。要禁止的是「未被定义流程」而不是工具本身。正确做法是把三入口映射到同一张流程表指定每个动作的等价操作与验收点工具选择自由、状态与流程一致。判断依据依旧是那句话这次操作能否用另外两个入口解释清楚。 题题问边界 答答要证据 手练加脑练 功到自然成# 13、思考回到本篇的核心冲突问题从来不是「哪个客户端更好用」而是「同一个动作在三套入口下是否得到同一个可复现的结果」。工具的自由度越高流程的确定性就越值钱。把影响克隆结果的配置写进仓库把只影响身份的东西留在账号层把每一次提交的边界显式设计出来——这三件事做完本地客户端才真正从熟练度变成基本功。 工具可多面 流程须一条 契约先落定 功在可重放