资讯动态

Git实战笔记:三大区域模型与高频命令,告别记不住

发布时间:2026/10/8 13:55:48 来源:尧图企业网站定制
很多人学Git其实是卡在“命令太多记不住”这个坎上。我自己刚开始也是这样每天打开终端就对着一个git help发呆今天提交忘了加文件、明天分支合并变出一堆冲突最后干脆回到老办法把代码压缩包改名加日期。直到后来被一次事故教育了——本地没提交的代码被误删找回来成本极高才老老实实把Git从头到尾系统过了一遍。这篇笔记原本是我整理给自己看的按“理解模型 → 搭好环境 → 日常高频操作 → 协作场景 → 疑难杂症”五条线梳理现在把它完整放出来。适用对象包括刚装好Git不知道第一步干什么的新手、用了一段时间但每次遇到分支合并都要百度的初级开发者以及想把手头Git问题一次性排查干净的老同学。这里没有任何花里胡哨的源码分析全部是实际敲过的命令和踩过的坑。1. Git 到底是个什么东西先搞懂三个区域1.1 别急着敲命令先建一个“存档”心智模型很多教程上来就让你git init、git add、git commit但你根本不知道这些动作在干嘛。我打个比方Git 就像你玩那种带存档机制的游戏。工作区是你正在打的这一关暂存区是一个“准备存档的候选名单”版本库是真正写入硬盘的存档文件。你在游戏里捡了金币、开了宝箱如果不进存档点commit退出游戏就全没了。对应到代码里就是工作区Working Directory你肉眼看到的、编辑器里正在编辑的文件。暂存区Index / Stage执行git add之后文件被放在了“待提交”区域。它像是提交前的一个缓冲让你可以分批次挑文件提交。版本库Repository执行git commit之后文件被生成一个 commit 对象永久记录当前的快照。这个模型能解释 90% 的日常操作。比如很多人问为什么git diff有时候什么都不显示就是因为修改还在工作区没被 addgit diff默认只比较工作区和暂存区git diff --staged才是比较暂存区和版本库。理解了这三个区域你看到任何命令都能迅速判断它操作的是哪个层次。1.2 为什么说 Git 的分布式设计是“买保险”Git 和 SVN 最大的区别是SVN 的仓库在中央服务器上本地永远是“客户”Git 则把整个仓库历史完整克隆到本地每一个克隆都是一个完整的仓库。这意味着你离线也能提交、看历史、切分支断网照样干活。等有网络了再 push别人也能从你的仓库拉走完整记录。这个设计还有一个隐含优势仓库不依赖单一节点本地就是最可靠的备份。我自己后来在团队里强制推行“必须每天至少 commit 一次及时 push”不是不信任同事的代码习惯而是 Git 分布式的特性让代码在每个人的电脑上都有了一份可恢复的副本。1.3 理解 Git 的“快照”而不是“补丁”SVN 记录的是文件差异集合Git 记录的是每次提交时整个项目的快照。听起来很占空间但 Git 做了压缩和对象去重相同的文件不会被重复存储。这也解释了为什么 Git 操作那么快切分支其实就是切换指针不是复制文件。如果你理解了“快照”这个概念git checkout、git reset、git revert这些命令就不难懂了。它们本质上是“把指针移到某个快照并选择性地同步工作区内容”。2. 从零搭好环境安装、配置与免密登录2.1 不同系统安装 Git 的正确姿势Windows 用户建议直接从 Git 官网下载安装包也可以使用国内镜像加速下载。安装过程基本是“下一步下一步”但有几个选项值得留意Git Bash 是推荐的命令行环境安装后会在右键菜单出现建议使用它而不是老的 CMD 来操作 Git。换行符转换建议保持默认Checkout Windows-style, commit Unix-style后续文件出现\r\n相关怪问题再来逐个排查。勾选“Enable Git Credential Manager”后面 https 推送不用反复输密码就靠它。Linux 和 macOS 用户走包管理器即可。macOS 如果装过 Xcode Command Line Tools系统可能自带 Git但版本偏老推荐用 Homebrew 装新版本。验证是否成功终端执行git --version能看到版本号就说明基本安装到位了。有个容易被忽略的细节是Windows 装完后要重新启动一次终端否则环境变量可能没刷新。2.2 第一次提交前的三件套配置新机器上第一次 commit 之前必须先告诉 Git 你是谁。很多人跳过了这一步结果提交记录里显示的是一个奇怪的“你的名字随机串”后面再想改历史非常麻烦。执行命令时把邮箱改成你自己的真实邮箱git config --global user.name 你的名字 git config --global user.email 你的邮箱--global表示全局生效如果某个项目需要不同身份比如工作项目和私人项目去掉--global在项目目录里再设置一次即可。配置文件位置在用户当前目录下的.gitconfig你可以直接用文本编辑器打开检查。这里我强烈建议花两分钟设置默认分支名和常用别名git config --global init.defaultBranch main git config --global alias.lg log --oneline --graph --all git config --global alias.st status git config --global alias.cm commit -m别看别名是小事实际用起来能省掉大量重复输入。git lg是我每天用最频繁的命令可以直观看到分支提交拓扑。2.3 SSH 密钥配置实现免密的“正经方式”如果你用 https 协议 clone 仓库每次 push/pull 都要输账号密码虽然 Credential Manager 能记住但在一些服务器环境里并没有这个组件。更常见的做法是配 SSH 密钥一次生成长期免密。生成密钥的命令注意-C后面的邮箱只是备注不影响密钥本身ssh-keygen -t ed25519 -C 你的邮箱默认一路回车即可密钥会生成在~/.ssh/下id_ed25519是私钥绝对不能泄露id_ed25519.pub是公钥需要填到代码托管平台。以 Gitee 为例登录后在“设置 → SSH 公钥”里粘贴.pub文件内容。GitHub 在“Settings → SSH and GPG keys”里操作路径类似。绑定完成后测试一下ssh -T gitgitee.com如果能收到欢迎信息说明认证成功。此时再用 SSH 协议的仓库地址 clonepush/pull 都不需要密码了。对于多台电脑使用同一个账号的场景最省事的做法是每台电脑各自生成一对密钥把各自的公钥都添加到账号的 SSH 公钥列表里。不建议把同一份私钥复制到多台机器一旦某台机器被入侵私钥泄露就全盘暴露。2.4 远程仓库推送失败token 与密码的坑2021 年后 GitHub 已经不允许用账号密码直接推代码Gitee 等平台也在逐步收紧。遇到remote: Support for password authentication was removed这类提示解决方式是在平台设置里生成一个 Personal Access Token把它当作密码填入推拉认证框。Windows 的 Credential Manager 会自动记住这个 token后续不再询问。生成的 token 要妥善保存平台通常只展示一次。我的习惯是把 token 直接放进专用密码管理器而不是随手写在笔记里。3. 日常高频操作从提交到回滚的完整闭环3.1 新项目起步init 还是 clone本地从零开始的项目在项目根目录执行git init然后git add .把所有文件加入暂存区。再看一眼.gitignore有没有把node_modules、target、.idea这类目录排除掉——这个文件非常重要我第一次用 Git 时不注意把 3 万多个依赖文件全提交上去了仓库瞬间膨胀到几百 MB每次操作都卡。已有远程仓库的情况直接执行git clone gitgithub.com:user/repo.gitclone 之后默认在主干分支main 或 master并且本地自动关联了远程名为origin的仓库。对比一下init 后需要手动git remote add origin 地址才能和远程建立连接。3.2 提交信息的“及格线”写法很多团队对提交注释没有要求但既然这份笔记叫“自用”我给自己定了一条规矩每次 commit 信息必须在 50 个字符内说清楚这件事“做了什么”而不是“改了代码”。比如git commit -m fix: 修复登录页验证码过期后仍可提交的问题而不是git commit -m update code推荐采用 Angular 风格的提交前缀feat表示新功能fix表示修复docs表示文档变更refactor表示重构test表示测试相关。这样后期用git log --oneline扫一眼整个版本演进一目了然。一个提交只做一件事这是个黄金原则。你花十分钟拆分的提交会让三天后的自己感激不尽。3.3 commit --amend改注释和补漏文件这个命令解决两类问题一是上一次的提交注释写错了、写得不完整二是上次提交漏了文件不想额外产生一个“fix typo”的提交记录。用法非常直观# 修改上一次提交的注释 git commit --amend -m 修正后的提交信息 # 补充漏掉的文件到上一次提交 git add 漏掉的文件 git commit --amend --no-edit--amend的底层原理是放弃当前的 commit把这个提交的父节点拿出来合并工作区新内容生成一个新的 commit。所以它对历史有“改写”效果。这里有一条红线如果上一次提交已经 push 到远程、且其他人可能已经基于它拉过分支绝对不要 amend。强行 amend 后会与远程历史冲突别人 pull 时会变得很痛苦。正确的做法是已推送的提交就让它留在历史里再补一个正向的 commit。另外如果 commit 的 message 里敲了中文出现乱码通常是终端编码问题设置git config --global core.quotepath false后中文文件名和注释就能正常显示了。3.4 查看历史记录log、diff、show 的组合用法日常最常用的排查组合我整理成了这个顺序git status # 先看工作区有什么变化 git diff # 再看未暂存的具体改动 git lg # 然后看历史拓扑 git show commit-hash # 某个特定提交改了什么git show默认展示提交说明和 diff 内容如果只想看某次提交改了哪个文件加--stat参数。查某一行代码谁改的用git blame file这个命令在定位“莫名其妙坏掉”的代码时是救命稻草。3.5 代码写了一半想切分支stash 大法场景我不信你没遇到过正在 dev 分支写功能写了一半测试突然说线上有个紧急 bug需要马上切到主分支修。这些写到一半的改动不想提交但也舍不得丢怎么办git stash # 临时保存当前工作区改动 git checkout main # 安心切分支 # 修完 bug 之后 git checkout dev git stash pop # 恢复之前的工作stash保存的是一个栈结构可以git stash list查看也可以多次 stash。唯一要注意的是 pop 时可能会因为新分支有冲突而提示手动解决冲突后即可。这个命令帮我节省了无数次的“复制半成品代码到临时文件”操作。4. 分支管理与团队协作从“一个人写”到“一群人写”4.1 分支的本质就是一个指针忘了分支是“代码副本”的想法它只是一个指向某个 commit 的指针。创建分支的成本极低所以 Git 的常见协作模型是“每需求一个分支”。日常流程是从主干切出 feature 分支开发完成后合并回主干。git branch dev # 创建 dev 分支 git checkout dev # 切换到 dev git switch dev # 或者这个命令作用和上面一样 git checkout -b feature/login # 创建并切换一步到位个人更推荐git switch系列git switch -c 分支名创建并切换语义清晰不会像checkout一样负载过重。删除分支用git branch -d注意如果分支上有未合并的提交会报错需要大写-D强制删除——慎用。4.2 从 master 剪切代码到 dev选择 merge 还是 cherry-pick有同学问“我在 master 上写了代码怎样剪切到 dev 分支上”。这个需求分两种情况。如果 master 上的这些代码只是想带到 dev 去继续开发最简单的是git checkout dev git merge master这时 dev 会包含 master 当前的全部提交。但如果 master 上有很多不想带过去的提交只要其中某个 commit那就用cherry-pickgit checkout dev git cherry-pick commit号它相当于把这个 commit 在 dev 分支上“重做一遍”。我再强调一遍cherry-pick会重新生成一个 commit它和原 commit 的 hash 不同这很正常不要试图找“同一个提交被移动过去”的错觉。实测下来跨分支捡代码的场景cherry-pick 比 merge 灵活得多但也要求你清楚自己在捡什么。捡错了可以用git cherry-pick --abort放弃。4.3 分支合并两种方式merge 与 rebase 的选择merge生成一个合并提交历史呈网状能清晰看到分支从哪里分叉、在哪里汇合。适合团队协作时保留真实开发轨迹。rebase将当前分支的提交“重新基于”目标分支的最新点历史变成一条直线。适合个人开发时保持提交历史清爽。我个人的习惯是功能分支合入主干用 merge保留完整的合入记录本地同步 master 最新代码用 rebase避免污染主干历史。对比一下# merge 方式 git checkout main git merge feature/login # rebase 方式在 feature 分支上执行 git rebase mainrebase 的代价是会改写当前分支的 commit hash所以和--amend一样不要对已推送且多人共用的分支执行 rebase。记住这个原则就不会出事。4.4 解决冲突的经验之谈合并分支最头疼的是冲突。第一次遇到时我很慌看到一屏的、、就想重来。其实处理冲突的正确姿势是用编辑器搜索冲突标记逐个文件处理。决定最终保留哪一侧或者两者都拼接起来。删除所有冲突标记符号。重新git add这些文件并git commit。冲突本质上不是技术问题而是沟通问题。如果是和别人合写同一块代码务必在合并前问清楚对方意图。我之前吃过亏想当然地选了我这边的版本把同事对同一行变量名的结构调整冲掉了线上直接编译失败。后来团队约定了一个规矩冲突时保留双方注释、协商解决杜绝“赢者通吃”。4.5 撤销的三种场景Commit 本地、Commit 已推送、未提交撤销是使用频率最高、也是最容易记混的操作。按对象分三种没有提交只想放弃修改git checkout -- file或git restore file把工作区文件恢复到暂存区/HEAD 的样子。提交了但还没推送git reset --soft HEAD~1撤销 commit 但保留暂存区git reset --hard HEAD~1连改动一起扔掉。注意--hard很危险会丢代码除非你现在一个角落里还有备份否则不要轻易用。已经推送到远程分支有两条路。一条是git revert commit生成一个反向提交安全、不改写历史推荐在团队协作时使用。另一条是git reset --hard commit后git push --force强制覆盖远程历史这是危险操作必须确认分支只有你自己在开发才能用。我当时在 IDEA 里误操作过一次 force push把同事的两次提交冲没了最后花了一上午从其他人本地仓库找回来教训极其深刻。如果是用 IDEA 操作右键项目“Git → Show History”里能选中历史提交选择“Revert Commit”也能达到同样效果。但无论什么工具原理不变本地已推送且多人协作优先 revert一个人独享分支才考虑 reset force push。4.6 子模块 submodule把仓库嵌进仓库项目里需要引入另一个 Git 仓库作为依赖直接用git submodule add 仓库地址然后git submodule update --init --recursive初始化。需要注意submodule 在父仓库里记录的是它指向的具体 commit不是“最新版”。所以父仓库更新时子模块不一定同步更新需要手动在子模块目录里拉取。说实话submodule 的坑比收益多。最典型的问题是子模块切换分支后父仓库会显示“modified content”。如果团队没有约定尽量用包管理器管理依赖submodule 仅用于那些非要源码级引入的场景。5. 疑难杂症排查我整理的高频问题速查表5.1 SSH 认证失败“Permission denied (publickey)”这是拉取代码时最经典的报错。排查步骤按优先级排序ssh -T gitgitee.com或ssh -T gitgithub.com看是否返回欢迎语。如果提示 permission denied说明公钥没配对。ls -al ~/.ssh/检查公钥是否存在。在平台设置里确认公钥内容与本地.pub文件一致注意粘贴时不要多空格、少换行。如果新换过电脑检查~/.ssh/config是否有旧配置或者系统里是否存在多个密钥文件。一个隐蔽的问题是公司 IT 的代理或防火墙拦截了 22 端口。GitHub 提供 443 端口的 ssh 访问可以在~/.ssh/config里加一行Host github.comHostName ssh.github.comPort 443绕过。Gitee 也类似需要时直接查对应文档即可。5.2 git open /dev/null or dup failed: No such file or directory这个报错不算大众但搜到的解释太少了。我实测的经历是这个错误的触发场景与标准输入输出流重定向相关常见于 Git Bash 环境在某些杀毒软件、终端工具或权限受限的目录下运行时无法正常给子进程分配文件描述符。排查顺序先关闭所有占用 Git Bash 的第三方终端如某些 IDE 内置终端改用官方 Git Bash 执行再检查项目路径是否有中文和空格我遇到过一次 Windows 路径带中文导致系统调用失败最后看杀毒软件是否拦截了 Git 的临时文件目录权限。这个报错几乎不影响 Git 本身的数据完整性重点是把程序运行环境弄干净。5.3 遇到 .git 目录泄露怎么处理网上有个热词“git 目录泄露如何下载”这其实是一个安全话题。如果有人把仓库的.git目录直接暴露在 web 站点上访问者可能通过特殊请求读取提交历史、源码和敏感配置。对于开发者来说正确的关注点应该是部署生产环境时确认站点根目录不包含.git目录或者配置规则禁止访问.git路径。代码托管平台的私有仓库不是“安全仓库”真正的密钥数据库密码、token绝不能提交进任何仓库。如果发现自己的仓库已经泄露第一件事是马上把泄露的密钥视为“已泄露”去平台撤销并重新生成而不是仅仅删除历史提交。这个话题的教训是.git 目录是仓库的心脏它不应该出现在任何对外服务的目录里。前端项目构建时默认会把整个项目拷进 dist构建产物过滤.git是必做配置。5.4 高频问题速查表问题典型原因解决命令/操作git pull提示“refusing to merge unrelated histories”两仓库没有共同祖先git pull origin main --allow-unrelated-histories中文文件名显示为\346...未设置 quotepathgit config --global core.quotepath falseWindows 下代码行尾变化导致 diff 巨大换行符 CRLF 被转换统一配置core.autocrlf团队约定为 true 或 falsepush 时要求输入 token 而不是密码平台取消密码认证生成 Personal Access Token 并使用command not found: gitPATH 未配置或未安装重新安装/重启终端/macOS 用 Homebrew 安装fatal: refusing to merge unrelated histories变体本地仓库与远程仓库历史独立首次合并用--allow-unrelated-histories修改一个文件后 diff 没显示没 adddiff 默认对比暂存区git diff HEAD查看未暂存改动5.5 常见 GUI 和 IDE 集成工具评点命令行是基础但团队里的同学更多时候是在 IDE 里操作。我用过四类工具简单说说感受Git GUIGit 自带的简易图形界面功能极简适合看 commit 关系图实际操作不是很有优势。TortoiseGit小乌龟Windows 经典工具右键菜单集成适合不习惯命令行的同事。优点是直观缺点是功能相对有限遇到复杂 rebase 容易懵。IDEA 内置 Git功能最完整的 IDE 集成之一支持从历史里查看 diff、cherry-pick、交互式 rebase。热词里的“idea 修改 git 提交的账户”“idea 撤销远程分支代码”都能在 VCS 菜单下完成。最常见的问题是提交账户不对检查 IDEA 的 Settings → Version Control → Git 里有没有勾选“Use credential helper”以及在全局 git config 中 user.name/email 是否正确。VS Code 内置 Git轻量好用日常 status、diff、commit 完全够用。胜在流畅适合小型项目复杂合并建议还是用 IDE 或命令行完成。我自己的习惯是日常写代码的机器用 IDEA 内置 Git 看 diff、提交遇到需要处理历史或复杂冲突时切到命令行两者各管一段。工具选哪个不重要核心是把 Git 的模型吃透换任何工具都不慌。写在最后一个折腾Git多年的人的真实体会来回踩了这么多坑最大的体会其实只有一个Git 不需要“背命令”需要“建模型”。当你脑子里清楚快照、指针、分支这些概念再回头看commit、merge、rebase、reset每个命令都只是“对某个对象执行某种操作”。很多报错能凭借模型推理出原因根本不用查文档。这份笔记里写的每一条命令我都在真实项目里验证过。如果你按着流程装好了环境跑通了第一次提交建议立刻做两件事一是把三条最常用的命令改成别名二是打开终端敲一遍git lg看看自己的提交历史。等你哪天不用查命令就能完成分支合并和代码回滚了说明 Git 这门手艺已经真正长在你身上了。最后再分享一个小技巧给自己定一条“下班前必须把工作区清零”的规矩要么提交、要么 stash保证工作区永远干净。这不仅防止代码丢失更重要的是第二天回来打开电脑时你永远可以瞬间进入状态而不必对着一堆改了一半的文件发呆。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑