ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Git基本命令不只是commit和push:搞懂三区状态转移与分支合并避坑指南

Git基本命令不只是commit和push:搞懂三区状态转移与分支合并避坑指南 简介这是《GIT基本命令》Word文档面向刚接触Git的开发者与运维人员按实际工作流系统梳理分布式版本控制的高频操作。全书约349KB内含1个docx文件结构清晰覆盖SSH密钥配置、仓库克隆与更新、代码提交与还原、分支管理、远程仓库同步、冲突解决、标签操作、stash暂存与rebase等核心主题每一类均配有可直接复制的命令示例适合作为日常开发中的速查手册。已有378人学习参考对于希望快速上手Git并减少版本管理踩坑的新手而言这份要点式笔记能帮助快速建立操作框架并在合并分支或回滚版本时提供明确指令依据。1. 为什么说 GIT 基本命令不是“commit push”从一次备份事故说起有一次帮同事救代码他把项目提交到本地仓库以为已经备份了可他把整个依赖目录和本地配置都加了进来远程推不上去推上去也是一堆无用文件。问题出在他把 GIT 基本命令理解成“记住几个动词”完全没意识到这些命令操作的是三个不同的区域工作区、暂存区和仓库。真正的基本命令是一条从git init到git status、git add、git commit再到branch、merge、pull、push的状态转移链。熟练的人不是背下来的是看一眼git status就知道下一步该用哪个命令。这篇按本地、分支、远程三条线讲清命令的边界和参数并把新手最容易翻车的几个场景单独列成避坑清单。适合刚装好 Git 却不敢乱动历史、以及要给新同事做技术普及的人。2. 本地三区闭环从 git init 到 git commit 的每一步都不该省GIT 基本命令的本地部分本质上是在“工作区 / 暂存区 / 仓库”三个区域之间做状态转移。工作区就是你在编辑器中看到的文件暂存区是 Git 内部用 index 文件维护的一份清单记录“下一次提交里要包含哪些内容”仓库才是已经挂进版本历史的提交对象。对新人这三个区域分不清commit 就成了黑匣子出了问题也只能靠猜。2.1 git init 与首次配置先解决“你是谁”再动手很多人装好 Git 之后第一件事就是git init然后写代码、git add .、git commit结果提交记录里全是“unknow”。原因不是命令错了而是没配置提交者身份。Git 每次提交都会把user.name和user.email写进 commit 对象不配置的话Git 会直接拒绝生成提交并提示你去设置身份。# 在项目根目录初始化仓库生成 .git 目录 git init # 配置提交者姓名和邮箱--global 表示对当前用户所有仓库生效 git config --global user.name Your Name git config --global user.email youexample.com # 查看当前仓库实际生效的配置 git config --list逻辑很简单git init只是生成了一个.git目录这个目录就是版本库本体所有历史、分支、配置都装在里面。git config把身份写进~/.gitconfig。如果你只在一台电脑上工作--global就够了如果公司仓库和个人仓库需要不同身份就不要加--global而是进到某个仓库里单独设置这样优先级更高。git config的配置级别有三级--system、--global、--local。生效优先级是 local global system也就是说在某一个仓库里单独设的user.email会覆盖全局配置。我一般建议团队在 README 里写明必填配置避免有人拿自己邮箱提交到公司仓库。另外一个很实用的小命令是git config user.name它只读当前身份不打开整个配置文件。第一次提交前还应该顺手建好.gitignore。依赖目录、编译产物、日志和本地环境配置都不要进版本库不然第一次git add .就会把一堆垃圾带进去。可以用下面这种方式快速验证忽略规则# 先写忽略规则再 add比事后清理省事得多 echo node_modules/ .gitignore echo *.log .gitignore # 查看某文件是否正被某条规则忽略 git check-ignore -v node_modules/pkg/index.jsgit check-ignore -v会精确告诉你这个文件被哪一行规则挡住排查“为什么 add 不进去”的时候非常好用。注意忽略规则只对未跟踪文件生效已经被 Git 跟踪的文件就算写进.gitignore也照样会被提交。要想让它停止跟踪得用后面避坑章节里说的git rm --cached。2.2 git add 的三种姿势与暂存区本质在三个区域里暂存区是最容易被跳过的一个。很多人的习惯是git add .然后git commit完全不管中间这层 index 到底记了什么。git add做的事不是复制文件而是把当前工作区文件的内容生成一个 blob 对象并把这个对象的路径和哈希更新到索引里。换句话说暂存区是“下次提交的照片草稿”。# 暂存所有改动包括删除和新文件符合 .gitignore 的除外 git add -A # 只暂存当前目录及其子目录的变化 git add . # 只暂存已经被 Git 跟踪的文件修改和删除不处理未跟踪的新文件 git add -u # 逐块检查后暂存适合拆分提交、避免夹带敏感信息 git add -p # 查看简化状态第一列是暂存区第二列是工作区 git status --shortgit add -A、git add .、git add -u这三个命令很多人以为差不多实际上有区别。-A是整个工作树无论你在哪个子目录执行都会把全仓库的变化纳入进来.是把当前目录及其子目录的变化纳入进来-u只处理已经被跟踪文件的改动和删除新文件不会进暂存区。日常开发里我习惯用git add -A做一次全量暂存再用git status --short确认没有携带异常文件。git status --short的输出是两列符号。左边表示暂存区状态右边表示工作区状态。比如M file表示文件已修改但还没提交到暂存区MM file表示暂存区里有一版修改工作区里又改了一版。这也是一个常见翻车点你先git add了一次然后又改了文件结果 commit 提交的是旧版本新改动还在工作区里。所以代码改完不要只 add 一次提交前再看一眼状态。git add -p是一个被严重低估的命令。它会把文件里的改动按 hunk 拆开让你逐个选择是否暂存。遇到一个大文件里混着两件事比如一个功能改动和一个日志输出就能用-p把它们拆成两个提交。按y暂存当前块按n跳过按e编辑块内容。新手第一次用可能会觉得界面奇怪但拆提交时它是最好用的后悔药之一。2.3 git status 和 git diff提交前一定要看的两个命令我见过不少开发者的提交习惯是“改完直接 commit”从来不跑git status和git diff。这样做的结果就是提交信息写得跟实际改动对不上或者把调试代码提交上去自己都不知道。git status是看全局状态git diff是看具体内容改动两者加起来才是一个完整的提交前检查。# 查看文件整体状态包括未跟踪、已暂存、未暂存 git status # 工作区 vs 暂存区看还有哪些修改没 add git diff # 暂存区 vs 仓库看这次将要被 commit 的内容 git diff --cached # 工作区 vs 仓库看相对上次提交的全部改动 git diff HEAD # 只看改动涉及哪些文件不展开具体内容 git diff --name-onlygit diff默认比较的是工作区和暂存区所以它可以回答“我改了什么但还没 add”。git diff --cached比较的是暂存区和当前提交也就是“提交按钮按下去之后仓库会多出什么”。提交前最该看的不是git diff而是git diff --cached因为这才是 commit 真正会用到的内容。如果你想看从上次提交到现在的全部变化包括已暂存和未暂存的那就用git diff HEAD。git status的完整输出还会提示分支领先或落后多少这在本地开发时很直观。比如Your branch is ahead of origin/main by 2 commits说明本地有 2 个提交还没 push。这个提示比你自己去记状态可靠得多。最后一步就是提交。git commit -m feat: add user profile page是最简单的写法。如果不带-mGit 会打开默认编辑器让你写提交信息很多新手第一次看到 vim 就愣住了不知道怎么退出。可以在安装配置时顺手设置成 VSCode 或别的编辑器git config --global core.editor code --wait git commit -m feat: add user profile page提交信息不是随便写几个字就完事基本格式是“做什么 为什么”。比如feat: 调整模块结构比更新了有用得多。团队里如果有人把提交信息全写成“fix”过两个月看git log谁都看不懂。这个习惯不用等团队规范自己先执行就有价值。3. 分支与合并把 GIT 分支合并从“乱套”变成可预期的操作GIT 基本命令到了分支这一层才开始真正体现出它的价值。没有分支所有代码都在一条时间线上改错一个地方就是连锁反应。分支合并在线工程里每天都会发生但不少人对merge、rebase、cherry-pick之间的关系说不清楚于是遇到冲突就只能靠复制文件来“硬合并”。这一章的目标是让你做完一次分支合并后不用靠猜。3.1 创建、切换与删除branch、switch 和 checkout 的正确分工分支在 Git 里只是一个 40 位哈希的引用指向某个 commit。创建分支就是在这个指针上贴一个新名字成本极低。所以 Git 鼓励你多开分支而不是等一个大功能快做完了才开分支。基础命令有三个git branch用来创建和删除git switch用来切换git checkout是老版切换命令但身兼两职。# 基于当前分支创建一个新分支 git branch feature # 切换到已有分支 git checkout feature # 推荐使用语义更纯粹的 switch 命令 git switch feature # 创建并切换 git switch -c feature # 删除已经合并过的分支安全删除 git branch -d feature # 强制删除未合并分支仅在你确定这些提交不要了的时候用 git branch -D feature为什么推荐git switch因为老命令git checkout既用来切换分支也用来恢复文件比如git checkout -- file会把工作区文件还原成暂存区状态。这两个动作是相反的语义一个是改 HEAD 指针一个是改动工作区内容。命令混在一起新手容易把刚写的代码 checkout 掉。从 Git 2.23 开始官方拆出了git switch和git restore建议新项目直接教这两个。切换分支时有个很容易踩的坑如果工作区里有未提交的改动而目标分支和当前分支对同一个文件的状态不一致Git 会拒绝切换报错提示“Your local changes would be overwritten”。这不是 Git 不让你切换而是它不想替你决定怎么处理这些未提交内容。解决方式要么git commit要么git stash暂存。跨界切换前先看一眼git status是基本素养。git branch -d与-D的区别也值得记住。-d会检查待删除分支上的提交是否已经被合并如果没合并它拒绝删除防止你丢提交。-D是跳过这个检查的强制删除。我建议日常多用-d只有当你确认这个分支彻底没用了才用-D。删除分支只是删掉名字commit 对象不会立刻消失但如果不做任何追溯它们就真的变成孤儿了。3.2 merge 和 rebase两种整合方式怎么选分支合并有两种常用手段git merge和git rebase。它们的最终结果都是把一个分支的改动整合到另一个分支但产生的历史形态完全不同。很多团队冲突不在代码上而在“应该用 merge 还是 rebase”的认知上。我的判断标准很简单要看这个提交是否已经被别人拉走公共分支用 merge纯本地私有分支可以用 rebase。# 先切到集成分支 git switch main # 如果 main 没有新提交会直接快进到 feature 的提交 git merge feature # 强制生成一个合并提交保留“功能分支存在过”的痕迹 git merge --no-ff feature # 把 feature 上的提交重放到 main 最新提交之后 git switch feature git rebase main先解释快进当 main 从创建 feature 之后一直没有新提交那么 merge 就是把 main 这个指针直接挪到 feature 所在的提交上没有新增 commit这就是 fast-forward。大多数情况建议用git merge --no-ff它能强制产生一个合并提交把“什么时候把功能合进来的”这个节点明确写在历史上。如果直接快进feature 的提交会平滑拼进 main看起来像一直在 main 上开发后面 review 代码时会缺少一个合并边界。git rebase做的事情则是把 feature 上的提交摘下来重新挂到 main 的最新提交之后。commit 的内容没变但 commit 的哈希会全部改变因为父提交变了。对纯本地分支来说rebase 可以避免产生大量合并提交让历史变成一条干净的线。但一旦其他人已经从这个分支拉过代码rebase 重写历史会让对方的仓库出现两条不一致的开发线。团队协作时公共分支上的提交也不要随意 amend。已经推送过的提交被 amend等于变成了另一个提交对象所有人下次 pull 都会产生分叉。正确做法是新增一个提交来修正问题或者用回滚命令。记住一句话merge 保留历史rebase 整理历史但重写历史是要付出代价的。3.3 冲突不等于翻车一次冲突解决的完整命令流很多人第一次看到CONFLICT (content): Merge conflict in main.go就慌了觉得自己把代码弄坏了。其实冲突只是 Git 的一种提示两个分支对同一个文件的同一块区域做了不同修改Git 不知道哪个才对所以把决定权交给你。冲突不可怕真正可怕的是用“复制粘贴整个文件”来绕过冲突。假设你在main分支上改了config.yaml的一行你的同事在feature分支上也改了同一行。你切回 main 执行git merge featureGit 会报冲突。这时先不要乱动执行git status你会看到文件状态是both modified这意味着两侧各自有改动git switch main git merge feature # 假设冲突出现查看冲突文件清单 git status打开冲突文件你会看到类似 HEAD、、 feature的标记。 HEAD和之间是当前分支main的内容和 feature之间是 feature 分支的内容。你要做的不是把其中一个删干净而是判断保留哪个、修改哪个最后把三个标记行全部删掉。# 编辑完冲突文件后标记为已解决 git add . # 继续完成合并提交 git merge --continue # 如果中途决定放弃合并回到 merge 之前状态 git merge --abortgit merge --continue会打开编辑器让你确认合并提交信息默认信息已经很完整直接保存退出即可。要注意的是git add .之后冲突状态就解除了但 Git 不会校验你是否真的解决正确只会记录你的决定。所以合并完要立刻把相关文件打开看一眼跑一遍测试或编译再推远程。git merge --abort是合并操作的后悔药。如果冲突太多或者发现合错分支了--abort会把工作区和索引恢复到 merge 之前的样子看起来什么都没发生过。还有一个相关命令git merge --quit它只退出合并流程而不回滚适合你手动解决了冲突但不想启动编辑器的情况。建议每个新人都把这三个命令背下来add、continue、abort。4. 远程协作push / pull 之前把 GIT 基本命令再捋一遍本地命令再熟一旦接上远程仓库就会多出一层“本地分支和远程分支”的对应关系。远程协作的关键不是记住push和pull这两个动词而是理解fetch、remote、origin这些概念。很多人在 SSH 认证失败上反复折腾其实问题不在网络而在没有理顺本地和远端的连接配置。4.1 从 clone 开始还是手动 init 后接 remote接远程仓库有两条路一种是用git clone把别人已有的仓库复制下来另一种是本地已经用git init建好了仓库再手动关联远程地址。这两条路的命令不一样选错就会在git remote add之后收到 “remote origin already exists” 的提示。# 在已有远程仓库的基础上开始地址用 SSH 格式 git clone gitgithub.com:user/repo.git # 本地已有仓库手动关联远程地址 git remote add origin gitgithub.com:user/repo.git # 查看当前仓库关联了哪些远程地址 git remote -vgit clone会做三件事把远程仓库的提交下载到本地、默认创建一个名为origin的远程别名、把远程分支记录到refs/remotes/origin/下。所以你 clone 完不用再git remote add直接git status就能看到本地分支和 origin/main 的关系。如果你现有本地仓库已经写了代码不要在 clone 新仓库之后把文件复制过去正确的做法是在托管平台建一个空仓库然后执行git remote add origin 地址。git remote -v是排查远程故障的第一步。它会显示当前仓库绑定的所有 fetch 和 push 地址。有时候我们想切换远程地址比如从 HTTPS 改成 SSH可以用# 修改已有远程地址 git remote set-url origin gitgithub.com:user/repo.git很多 SSH 认证失败其实是绑定的地址协议不对。HTTPS 方式要求用户名密码或 tokenSSH 方式要求密钥。用git remote -v看一眼 URL 前缀能省掉大量排查时间。另外不要在仓库里保存远程地址中带密钥的 URL尤其是.git/config会明文记录这部分信息提交历史里一旦出现密钥就应该视为泄露并立即更换。4.2 fetch 与 pull先看清楚再合并git pull可以看作两个命令的组合先git fetch再做一次git merge。但组合在一起后它掩盖了一个重要事实fetch 本身是不会改变你当前工作区和本地分支的。很多冲突之所以发生是因为用户直接 pull没看清远程到底改了什么就自动进入合并流程。# 只拉取远程更新不合并到本地分支 git fetch origin # 查看 main 与 origin/main 之间的提交差异 git log --oneline main..origin/main # 查看具体文件差异 git diff main origin/main # 只允许快进式拉取如果分叉就失败 git pull --ff-only # 用 rebase 方式拉取避免产生多余合并提交 git pull --rebasegit fetch拉取下来的远程状态在origin/main这个引用里。你可以把origin/main当作一个只读的追踪分支用来对比“远程已经到哪了、本地还没到哪”。git log main..origin/main表示“查看仅在 origin/main 上出现的提交”也就是远程有的、本地没有的提交。看完之后你再决定是git merge还是git rebase。git pull --ff-only是个很安全的设置如果本地分支没有产生分叉就直接快进到远程最新状态如果本地有独立提交它宁可失败也不生成一个莫名其妙的合并提交。这对集成分支很有用。git pull --rebase则是把本地未推送的提交重放到远程最新提交之后适合功能分支。两者的选择原则跟第 3 章 merge/rebase 一致公共集成分支别乱 rebase个人功能分支优先 rebase。如果你正处于“改了代码但还没提交临时需要 pull”的状态可以直接用git pull --rebase --autostash。它会先把未提交的改动藏起来完成 rebase 后再弹回来这比你自己手动git stash再 pop 更省事。不过这个命令不要在第一次 pull 时就拿来用最好先理解 stash 的机制出了问题才知道怎么恢复。4.3 push 的安全行为和 SSH 认证失败排查git push是把本地分支的提交上传到远程分支。它也有一个快进要求如果远程分支已经出现了本地没有的提交Git 会拒绝推送报错提示non-fast-forward。这是保护机制防止你用本地旧历史覆盖远程新提交。遇到这种拒绝先fetch看差距再 pull不要直接--force。# 第一次推送时设置上游关联之后可以直接 git push git push -u origin main # 查看本地分支和远程分支的关联关系 git status -sb # 强制推送的保守替代方案只在远程没有变化时生效 git push --force-with-lease-u的作用是把本地分支的 upstream 设置成origin/main之后直接git push就不带参数了。git status -sb的输出里会显示[ahead 1]这样的标记一眼就能看出本地领先或落后多少。--force-with-lease是强制推送的安全版本它会先确认远程分支的状态还和你上次 fetch 到的一致才允许覆盖如果远程已经被别人改动过它就拒绝执行。这个机制比git push --force多一层保险我基本只在重开公共 CI 时才考虑使用。SSH 认证失败是安装配置教程里最常见的问题。表现有很多种clone 时提示Permission denied (publickey)或者ssh: connect to host ...超时。最常见的场景是本地生成的公钥没有添加到托管平台。# 测试 SSH 连接是否成功 ssh -T gitgithub.com # 如果提示没有加载密钥启动 ssh-agent 并添加私钥 eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519 # 查看公钥内容复制到托管平台的 SSH Key 列表 cat ~/.ssh/id_ed25519.pubssh -T是一个测试连接命令连接成功后托管平台通常会返回一句欢迎语然后退出这是正常的。ssh-add把私钥加载进内存如果提示No such file说明私钥路径不对先确认你生成的是id_ed25519还是id_rsa。多台电脑或不同账号切换时还会遇到 “remote origin already exists” 或 “please make sure you have the correct access rights” 的提示这时可以检查git config --list看当前仓库绑定的账号身份是否对应正确的密钥。密码忘了一点不丢人密钥和远程地址才是真正的主角。5. Git 基本命令避坑5 个让新手破防的场景与自查方法基本命令不难难的是在出错时知道是哪条命令的副作用。下面这 5 个场景是团队日常提问里最常见的全都按“现象 → 原因 → 解决”拆开讲。读完以后你不需要背住所有参数只需要记住一个原则凡是会覆盖历史或工作区的命令执行前先看一眼git status。5.1 第一坑提交时把独立文件、日志和密钥一起推上去了现象第一次提交时执行了git add .结果node_modules、dist、.env全进了仓库推上去之后远程仓库变得巨大甚至有可能因为一份.env泄露了内部地址。原因git add .会把当前目录下所有没有被忽略的文件都纳入暂存区包括配置文件、构建产物和各种日志。.gitignore没建立或者建立太晚Git 不会主动帮你识别“不该提交的文件”。解决把.env这类文件从 Git 跟踪列表里移除但保留在本地磁盘上然后提交这次移除动作# 把 .env 写进忽略规则 echo .env .gitignore # 停止跟踪但保留本地文件 git rm --cached .env # 查看改动确认 .env 已不在跟踪列表 git status --shortgit rm --cached是把文件从索引里移除工作区文件不会受影响。提交之后远程仓库里的.env仍然会留在历史记录中所以如果里面是真实密钥光删掉还不够要更换密钥。新建项目时我建议第一份提交只放.gitignore和 README先确认忽略规则生效再开始写业务代码。5.2 第二坑在公共分支上顺手 commit --amend把同事的历史搞乱现象你在 main 分支上提交了一个修复然后发现提交信息写错了执行git commit --amend修改后推送到远程其他同事拉取时出现两条历史甚至 push 被拒绝。原因git commit --amend的本质是重新生成一个提交对象新对象的哈希和原来完全不同。它只是把“当前提交”替换成了“另一个提交”如果原来的提交已经被其他人拉走那么重写会让两边历史无法对上。解决--amend只适合本地还没推送的提交或者只属于你一个人的私有分支。公共分支上的提交信息写错用git revert追加一条新提交来修复而不是修改原提交# 追加一个反向提交保留原始历史 git revert HEADgit revert HEAD会生成一条新提交内容正好抵消上一次修改。这样做的代价是历史里多了一条记录但团队其他人的仓库不会产生分叉。记住这个边界重写历史前先问一句“这个提交有没有被别人看到过”看到过就不能改。5.3 第三坑reset --hard 把未提交的改动一起抹掉了现象写了半天代码打算撤掉一次提交执行了git reset --hard HEAD结果工作区里的未提交改动全没了连新建文件也消失了。原因git reset --hard的作用不只移动 HEAD 指针它还会把暂存区和工作区一起重置到指定状态。任何未未提交、未暂存的改动都会被直接覆盖掉。更惨的是未被 Git 跟踪的新文件根本不进入索引reset 对它们不理不睬所以也无从恢复。解决执行危险命令之前先把当前改动存起来git stash git reset --hard HEAD git stash popgit stash会把工作区和暂存区的改动保存到一个临时栈里然后让你在一个干净状态下做 reset最后用git stash pop把改动恢复回来。如果已经执行了 reset 才发现问题赶紧用git reflog找到 reset 前的 HEAD 位置再git reset --hard回去。但未被跟踪的文件仍然救不回来所以我对新人只有一条建议重要工作要么提交要么持续备份拖越久越危险。5.4 第四坑git pull 默认合并把分支图搞得像蜘蛛网现象明明只是拉取远程更新却生成了一堆Merge branch main of ...这样的提交分支图看起来十分混乱但代码没有任何冲突。原因git pull默认执行的是 fetch merge。如果本地和远程在同一个分支上各自都有新提交Git 会直接生成一个合并提交来把两边串起来。这个提交本身无害但对集成分支来说会污染历史。解决拉取时明确告诉 Git 你要线性历史或者在全局配置里改掉默认行为# 当前命令只允许 fast-forward分叉就报错 git pull --ff-only # 通用做法把 pull 的默认策略改为 rebase git config --global pull.rebase true改成pull.rebase true后git pull等价于git pull --rebase本地尚未推送的提交会被挪到远程最新提交之后。这样分支线是平滑的。要注意如果本地提交和远程提交改动了同一段代码rebase 过程中同样会触发冲突解决方式和 merge 冲突一样解决后执行git rebase --continue。不要因为怕冲突就退回默认 merge冲突本身不是需要消除的问题。5.5 第五坑大小写重命名和换行符差异Git 假装没看到现象把README.md重命名为readme.md执行git status却没有任何变化或者同一个文件在 Windows 和 Linux 上来回编辑后Git 显示整份文件都被修改实际上只改了一行。原因Git 默认会继承文件系统的大小写行为。在 Windows 和 macOS 上文件系统通常不区分大小写所以 Git 不会把一个只改了大小写的文件视为修改。换行符则是由于core.autocrlf在各机器上配置不一致Windows 用 CRLFLinux/macOS 用 LFGit 在 diff 时把换行符差异也算进了修改里。解决先消除这两类“看不见的差异”。想让 Git 跟踪大小写重命名在大小写不敏感的文件系统上可以绕一段改名操作git mv README.md README2.md git mv README2.md readme.md换行符则需要团队统一配置。拉取时让 Git 把远程内容转成 LF提交时按仓库里的规则处理最稳妥的是在仓库里放一份.gitattributes文件把文本文件的行尾固定下来。如果历史里已经混入了大量 CRLF可以执行git add --renormalize .来重新规范化。注意这个操作会改动很多文件的索引状态执行前必须让团队知道最好单独用一个提交来完成避免和其他代码改动混在一起。6. 进阶技巧用 log 和 reflog 给每一次 Git 操作留后悔药命令越学越多真正能让你在意外发生时不慌的反而是两个读状态的命令git log和git reflog。git log看的是提交历史而git reflog看的是本地每次 HEAD 移动的操作记录。即使一个分支被删了被 reset 了只要操作发生在这台电脑上reflog 里通常都还留着痕迹。# 查看分支图和提交位置-all 包含远程跟踪分支 git log --oneline --graph --all --decorate # 看最近 10 次本地 HEAD 操作记录 git reflog -10 # 找到被 reset 掉之前的 HEAD{2} git reset --hard HEAD{2}git log --oneline --graph是快速观察分支结构的首选。--graph用字符画出提交拓扑--decorate会在提交旁标注分支和标签名。git reflog则更像一份本地操作流水账每条记录都带有HEAD{n}这样的位置标记。假如你误执行了git reset --hard HEAD~1reflog 会记录 reset 之前的提交位置直接git reset --hard HEAD{2}就能退回原状。命令看什么典型用途git logcommit 历史审查代码演进、分支合并关系git reflogHEAD 移动记录找回被 reset、被删除的本地状态我自己的习惯是每次觉得“操作乱了”第一个动作不是执行撤销而是先跑git status和git log --oneline -5。看完这两项再打开git reflog判断要回退到哪个点。这样做的次数多了你会发现大多数翻车其实都能在提交之前拦住。还有一个我一直保留的习惯提交前一定会看git diff --cached确认将要提交的内容和提交信息完全对应。这个动作比任何命令都重要它让我避免过无数次把临时调试代码提交上去。记住Git 基本命令不是“背得越多越强”而是“状态看得越清越稳”。希望这些命令和踩坑记录能帮你在下次操作前少走一段弯路。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进