Git 命令速查手册:从分支管理到代码回滚的完整实践指南
写代码这些年Git 是我电脑上打开频率最高的工具之一。它本质上就是一个分布式的版本管理系统但真正用得好的开发者和只会git add、git commit的开发者效率差得不是一星半点。这篇文章不是 Git 官网文档的翻译而是我基于多年实际开发经验写的一份命令速查手册覆盖日常开发里 90% 以上的高频场景从安装配置、基础提交到分支管理、远程协作、撤销回滚、疑难杂症排查每一段都是实测过、踩过坑之后沉淀下来的干货。不管你是刚入行的新手还是用了 Git 好几年的老手这份手册都能帮你少走很多弯路建议直接收藏。1. 环境准备与基础配置很多人用 Git 第一步就卡在环境上不是装不上就是装完了一运行提示git 无法将“git”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。这类问题十有八九是环境变量没配好。先解决安装的问题再去说配置。1.1 各平台安装方式Windows 平台最简单直接去 Git 官网下载安装包一路 Next 就能装完。不过有几个选项值得认真看一下默认编辑器建议选 Vim 以外的编辑器比如 Notepad 或者 VS Code因为新手在 Git Bash 里误入 Vim 之后经常不知道怎么退出网上求助帖里:wq和:q!已经快被问烂了。PATH 环境变量那里选默认的 Git from the command line and also from 3rd-party software 就行这样 CMD 和 PowerShell 里都能直接用git命令。换行符转换那个选项如果团队全部是 Windows 环境选第一个如果团队里有 Linux 或者 Mac 的同事选第二个 Checkout as-is, commit as-is也就是不自动转换换行符避免出现整个文件都被标记为修改的尴尬情况。Linux 和 macOS 用户就省事很多。Ubuntu 和 Debian 系用apt install gitCentOS、RHEL 系用yum install git或者dnf install gitmacOS 装了 Homebrew 的直接brew install git。装完敲git --version能输出版本号就说明装对了。1.2 全局配置三件套装好 Git 之后第一件事不是急着建仓库而是先把身份信息配置好。这步不做你第一次 commit 就会看到一串莫名其妙的用户名和邮箱因为 Git 会拿你系统的主机名去凑数。git config --global user.name 你的名字 git config --global user.email 你的邮箱 git config --global core.editor code --wait这三个配置分别对应提交作者、提交邮箱和默认编辑器。user.name和user.email会写进每一个 commit 里团队协作的时候代码评审人就是靠这个信息知道谁改的代码。邮箱建议用公司邮箱或者在 GitHub、GitLab 上绑定过的邮箱不然你的提交头像显示不出来。core.editor配成code --wait的意思是当你执行git commit没带-m参数时会打开 VS Code 让你写提交信息关掉编辑器之后提交才会继续执行。如果你是 Vim 熟练工这步也可以不配。还有个容易被忽略的配置是默认分支名。Git 早期版本默认分支叫master现在主流已经是main了。新仓库直接改掉省得后面还得手动重命名分支git config --global init.defaultBranch main查配置用git config --list改错了想删除用git config --global --unset 配置名比如删掉刚才的user.name就是这个命令。1.3 代理、换行符与常见环境问题国内网络环境下拉取境外仓库经常慢到怀疑人生。这种情况有几种正经的处理思路一是用镜像站点比如 gitee 上有很多仓库的镜像速度会快很多二是即便你配置了本地代理也要注意 Git 默认不走系统代理必须手动设置git config --global http.proxy http://127.0.0.1:端口号这种形式才能生效。我不建议你去折腾任何不该折腾的工具但把仓库克隆到国内代码托管平台再同步是合规又高效的做法。换行符这个坑很多团队踩过。Windows 上 Git 默认会把仓库里的LF换成CRLF再放到工作区提交的时候再换回去。这本身没毛病但如果有文件在某个提交里因为换行符问题被整个标记为修改代码评审的时候简直是灾难。推荐的做法是统一配置git config --global core.autocrlf input这个配置的含义是提交时把CRLF转成LFCheckout 时不转换。团队成员无论是 Windows 还是 Linux仓库里始终保存的是LF最大程度避免换行符引起的 diff 噪音。如果项目里有.editorconfig文件也可以在项目层面把end_of_line统一为lf。环境问题先聊到这下面进入日常使用频率最高的命令场景。2. 日常开发核心命令详解这一部分是整个速查手册的基石。前面配置好了环境接下来所有操作都围绕这套核心流程展开初始化仓库、查看状态、暂存修改、提交记录。2.1 初始化与状态查看进入项目目录执行git init就完成了仓库初始化。这条命令会在当前目录生成一个.git隐藏文件夹里面存的就是整个版本历史。你可以把.git理解成数据库工作区里所有文件的修改、提交记录、分支指针全在里面。初始化之后马上用git status看看当前状态。这个命令是开发过程中使用频率最高的没有之一。它能告诉你三件事当前在哪个分支、工作区有哪些文件被修改、暂存区有哪些文件待提交。我见过太多新手不看status就瞎操作结果不是把不想提交的文件加进去了就是漏提交了关键改动。git status -sb是我个人更推荐的用法。-s是 short 模式输出更精简每一行一个文件的状态-b显示当前分支和上游跟踪关系比如## main...origin/main就说明当前分支是main它跟踪远程的origin/main。2.2 文件操作三件套add、rm、mvgit add是把改动放入暂存区。使用频率太高但注意下面这几个细节git add file.txt # 暂存指定文件 git add . # 暂存当前目录所有改动包括新增和修改 git add -u # 暂存所有已跟踪文件的修改和删除但不包括新增 git add -A # 暂存所有变动和 git add . 效果基本一致 git add -p # 交互式暂存逐个 hunk 选择是否暂存git add -p是个被低估的命令。开发中经常遇到一次改了三个文件但只想把其中两个提交的情况。用-p可以在同一个文件里挑出一部分改动暂存另一部分留在工作区这样每个 commit 的边界就会清晰很多代码评审的人也舒服。git rm用来删除文件。普通删除也能被git status感知到但用git rm一步到位同时删除工作区文件和暂存区记录。git rm --cached file.txt是最常用的变体它的作用是只从版本库中移除跟踪关系但保留本地文件。最常见的场景是某人不小心把配置文件提交了现在想让它不再被 Git 跟踪但要保留本地的config.ini这时候就靠这个命令。git mv重命名文件。直接重命名文件Git 也能识别但用git mv管理更清晰旧文件名和新文件名的对应关系在提交历史中一目了然。2.3 提交与提交信息规范git commit是核心中的核心。常规用法是git commit -m 提交信息但建议习惯两个步骤先git add想要的改动再git commit。有人喜欢git commit -am 信息一步到位这个命令只对已跟踪文件生效新增的文件还是得先git add。提交信息怎么写我强烈建议团队统一规范。我一直在推的格式是type(scope): subjecttype表示提交类型常用的有feat新功能、fix修复 Bug、docs文档变更、style格式调整、refactor重构、test测试相关、chore构建或辅助工具变动。scope表示影响范围比如模块名、组件名。subject是对这次提交的简要描述一般控制在 50 个字符以内动词开头、不用句号。示例git commit -m feat(login): add password reset flow git commit -m fix(cart): resolve total price calculation error还有一个很实用的技巧提交之后发现漏了一个文件或者提交信息写错了用git commit --amend修正。这个命令会把暂存区的内容并入上一次提交同时可以修改提交信息。前提是这段提交还没有推送到远程或者推送了但是在个人分支上不然会重写历史影响协作。2.4 查看历史log 与 diffgit log默认输出是一长串信息足够但不够直观。推荐这几个变体git log --oneline # 一行显示一个提交简洁至极 git log --graph --oneline # 带分支图的精简历史 git log -p # 显示每个提交的具体改动 git log --author名字 # 按作者过滤 git log --since2 weeks ago # 按时间过滤 git log --follow -- file.txt # 跟踪单个文件的完整历史git diff比log更细粒度。git diff查看工作区与暂存区的差异git diff --cached查看暂存区与当前提交的差异。我经常在 commit 之前执行git diff --cached做一次自测 review看看即将提交的改动是否符合预期有没有把调试日志、临时代码一起提交进去。有个很适合每天上班用的命令是git log --oneline --all --since1 day ago我直接给它起了个别名git config --global alias.today !git log --oneline --all --since1 day ago配置好之后敲git today就能看到最近一天所有分支上的提交站会汇报或者自检的时候非常高效。3. 分支管理与合并策略分支是 Git 相比传统版本控制工具的最大优势也是新手最容易绕晕的地方。这个概念可以类比成平行宇宙你在main分支上开一条新分支相当于复制了当前宇宙然后在新宇宙里随便折腾不影响主宇宙的人。3.1 分支的增删改查git branch # 查看本地分支当前分支前带星号 git branch -a # 查看所有分支包含远程分支 git branch feature/login # 基于当前 HEAD 创建新分支 git switch feature/login # 切换到目标分支 git switch -c feature/login # 创建并切换最常用 git branch -d feature/login # 删除已合并的分支 git branch -D feature/login # 强制删除未合并的分支git switch是 Git 2.23 之后推荐使用的命令替代了老版本的git checkout一部分功能。如果你更习惯老命令git checkout -b也没毛病两个命令都是合法的。删除分支时-d会检查分支是否已合并到当前分支没合并就拒绝删除-D就不管这么多直接删。强制删除之前建议再确认一遍真删了分支这个分支上的全部提交就找不回来了。3.2 分支合并与变基的取舍合并最常用的两种方式git merge和git rebase这俩经常被拿来对比确实值得理清楚。git merge feature/login会把 feature 分支的提交合并到当前分支生成一个合并提交提交历史是网状结构保留了完整的时间线和分支发展脉络。这种方式的好处是安全、可追溯缺点是历史看起来“乱”提交图里有交叉有分叉。git rebase main的效果是把你当前分支的提交一个个摘下来按顺序重新放到main分支的最新提交之上历史变成一条直线非常整洁。但它的本质是改写提交所以绝对不能对已经推送到远程的公共分支执行rebase否则协作者拉取代码时会产生大量冲突。我的个人习惯是本地开发时勤用git rebase main同步主线更新保证当前分支始终基于最新的main这样最后合并回主线的冲突最小准备推送到远程进行代码评审的分支用git merge main拉新代码不要 rebase因为评审经过的 commit sha 可能会变化评审平台的历史会乱。说白了就是一句话公开分支不 rebase私有分支怎么爽怎么来。3.3 解决合并冲突的实战方法冲突是 Git 里最让人头痛的事情但理解了之后也就是个流程问题。冲突发生的前提很简单两个分支改动了同一个文件的同一段代码Git 不知道该听谁的。当你执行git merge或git rebase遇到冲突时Git 会在冲突文件里插入这样的标记 HEAD 这是当前分支的代码 这是被合并分支的代码 feature/login处理步骤打开文件逐段看冲突区域。手动决定保留哪边的代码或者两边都保留并做整合。删掉、、这三行标记。保存文件后git add这个文件。如果是 merge直接git commit完成合并提交如果是 rebase执行git rebase --continue继续。排查冲突时有个好用的命令是git status它会列出一个Unmerged paths列表所有还没处理完的文件都在这。还有一个设置值得提一下git config --global merge.conflictStyle diff3改成 diff3 风格之后冲突区域会多显示一个“合并前共同祖先”的版本很多时候这个信息能帮你判断到底哪边才是正确的语义。4. 远程仓库协作全流程单人开发只用到本地功能就够但真实项目里一定有远程协作。从克隆仓库到推送拉取再到处理远程分支的变化这一整套流程是团队开发的地基。4.1 远程仓库关联如果是从零开始先创建远程仓库比如在 GitHub、GitLab 或 Gitee 上建一个空仓库然后本地关联git remote add origin gitgithub.com:用户名/仓库名.git如果项目本身是从远程克隆下来的比如git clone gitgithub.com:用户名/仓库名.git那就已经自动配置好了origin。查看关联地址用git remote -v这个命令会显示远程仓库的抓取和推送地址。远程地址有两种协议HTTPS 和 SSH。HTTPS 每次推送都要输账号密码不过可以用凭据管理器记住SSH 需要先生成密钥对把公钥配置到代码托管平台之后推送就不需要反复输入账号密码了。4.2 生成 SSH 密钥并配置免密Windows 和 Linux 生成方式一致在终端执行ssh-keygen -t ed25519 -C 你的邮箱一路回车即可默认生成的密钥对在~/.ssh/目录下id_ed25519.pub是公钥id_ed25519是私钥。公钥内容用cat ~/.ssh/id_ed25519.pub查看复制全部内容粘贴到代码托管平台GitHub、GitLab、Gitee 都有对应菜单的 SSH Keys 配置页。配置完成之后用ssh -T gitgithub.com测试是否连通返回欢迎信息就说明配好了。SSH 相比 HTTPS 还有个天然优势推送和拉取时不会因为网络中间设备限制而频繁失效尤其是公司网络环境里SSH 的 22 端口通常比 HTTPS 的 443 端口更稳。如果22端口被限制还可以在~/.ssh/config里加一段配置走443端口Host github.com Hostname ssh.github.com Port 443 User git这也是官方支持的方式合规且常用。4.3 push 与 pull 的正确姿势推送和拉取是团队协作的基本动作但这两个命令的细节远不止“提交之后推上去”这么简单。git push origin main # 推送到远程 main 分支 git push -u origin feature/login # 推送并设置上游跟踪 git push origin --delete old-branch # 删除远程分支 git pull origin main # 拉取远程 main 并合并到当前分支 git fetch origin # 只拉取远程更新不合并-u参数很关键。第一次推送新分支时加上它本地分支和远程分支会建立跟踪关系。建立之后后续直接敲git push和git pull就够用了Git 会自动从对应的远程分支同步。git pull是git fetch加git merge的组合。如果远程分支有新的提交而本地也有未推送的提交pull 会产生一个合并提交。想保持历史干净的话可以用git pull --rebase相当于先 fetch 再用 rebase 把你的本地提交放到远程提交之上。注意前文的原则私有分支用 rebase 没问题公共分支要谨慎。推送失败是最常见的协作问题提示大概意思是“远程有更新被拒绝了”。这时候先别慌按这个顺序排查执行git fetch origin获取最新的远程状态。用git log --oneline origin/main看远程多了哪些提交。执行git pull --rebase把你的改动变基到远程最新。有冲突解决冲突然后git push重新推送。这套流程能处理 90% 以上的推送冲突关键就是别在推送失败的时候直接git push --force。--force是能够覆盖远程历史的高危操作一旦有人已经基于旧的历史做了提交强制推送会把别人的提交直接从远程抹掉。4.4 子模块与多仓库项目管理项目里有时需要引用另一个仓库的代码比如公共组件库、共享协议定义这时候子模块就派上用场了。git submodule add https://github.com/example/common-lib.git libs/common git submodule update --init --recursive添加子模块之后主仓库会记录子模块对应的提交指针子模块内部的代码版本被精确锁定。别人克隆主仓库之后要执行git submodule update --init --recursive才能把子模块真正拉下来。子模块的坑在于子模块内部改了代码主仓库只会看到子模块指向的 commit 变了不会帮你自动推送子模块的改动你得先进子模块目录单独提交和推送再回到主仓库提交指针更新。如果只是临时借用公共代码子模块有点重我更推荐用包管理工具如 npm、Maven、Go modules来管理依赖。子模块适合那些必须守住“主仓库控制版本”的强绑定场景。5. 撤销修改与时间回溯Git 最让人安心的特性就是几乎所有错误都能撤销。这一节把撤销的三种主要手段拆开讲工作区的撤销、暂存区的撤销、历史提交的撤销各司其职别混用。5.1 工作区与暂存区的反悔文件改了但还没git add想放弃修改回到上一次提交的状态git restore file.txt这个命令会用暂存区的内容覆盖工作区文件所有未暂存的修改直接丢弃。如果是新创建的文件还没被跟踪git restore对它无效要手动删除文件或者用git clean -fd清理所有未跟踪文件。注意git clean是很危险的命令因为未跟踪文件不在 Git 版本库中删了就彻底没了建议先git clean -nd看看会删哪些文件再动手。文件已经git add进了暂存区想撤销暂存git restore --staged file.txt这个命令刚才提过等价于git reset HEAD file.txt把文件从暂存区移出来但工作区改动保留。这一步只是撤销了暂存动作文件内容不受影响。5.2 提交层面的回滚reset、checkout、revert提交之后的撤销有三种手段适用场景完全不同。git reset是移动 HEAD 指针和分支指针的过程。用法git reset --soft HEAD~1 # 撤销最近一次提交保留改动到暂存区 git reset --mixed HEAD~1 # 撤销最近一次提交保留改动到工作区默认 git reset --hard HEAD~1 # 撤销最近一次提交丢弃所有改动--soft、--mixed、--hard的区别在于丢不丢本地改动、改动停留在暂存区还是工作区。--hard最危险会直接丢弃提交对应的全部改动慎用。git reset只适用于还没推送到远程的提交一旦推送过了reset 之后远程历史还是旧的。git checkout的撤销场景和 reset 不同。git checkout commit-sha会把 HEAD 切换到指定提交处于“游离 HEAD”状态此时如果你直接改代码并提交会创建一个不属于任何分支的提交切换分支之后就可能找不回来了。所以这个用法只推荐用于临时查看历史版本的代码。git revert是安全的回滚手段它会生成一个新提交这个新提交的内容是“撤销之前提交的修改”但完全不删除历史提交。团队协作中如果某个提交已经被推送并被多人拉取回滚操作必须用git revert而不是git reset。示例git revert HEAD # 撤销最近一次提交 git revert a1b2c3d # 撤销指定提交revert 之后如果后悔了可以再 revert 一次把撤销操作本身撤销回来。5.3 重新整理提交历史这是 Git 进阶技巧里含金量最高的一块git rebase -i交互式变基。git rebase -i HEAD~4执行之后会打开编辑器列出最近的 4 个提交每条记录前面有pick字样。把pick改成不同的指令就能对提交执行不同操作pick保留提交。reword保留提交内容但修改提交信息。edit停下来允许修改提交内容比如补文件。squash把提交合并到上一个提交里并合并提交信息。fixup把提交合并到上一个提交放弃当前提交的提交信息。drop删除该提交。最经典的场景是开发过程中提交了十几次全是“wip”“debug”“fix typo”推到远程之前用rebase -i把它们整理成两三个逻辑完整的提交评审的人看到的是一个清晰的故事线而不是一段混乱的开发日志。需要特别注意的是git rebase -i千万不要对已经推送到远程并和其他人共享的分支执行否则会重写公共历史导致协作者再次拉取时出现大量冲突甚至丢失提交。6. 工作现场保存与随手操作技巧开发中经常会遇到这种场景正在改代码突然需要切分支处理线上紧急问题。本地改动还没完成又不想直接提交一个半成品。这种时候就要靠git stash这套机制。6.1 stash 存储和恢复git stash把当前工作区和暂存区的改动保存到一个栈中然后工作区恢复到干净的 HEAD 状态。切换分支、干完别的活再回来恢复现场git stash save 描述信息 # 保存当前改动建议写描述 git stash list # 查看所有 stash git stash apply # 应用最近一次 stash但保留 stash 记录 git stash pop # 应用最近一次 stash并从栈中删除 git stash drop stash{0} # 删除指定 stash git stash clear # 清空全部 stashapply和pop的区别在于是否删除 stash 记录。我的习惯是如果应用之后马上验证没问题就pop如果只是临时借用代码后面可能还要对照或恢复就用apply。还有一点值得注意git stash默认不保存未跟踪的新文件如果需要连新文件一起保存加-u参数。6.2 标签管理与版本发布发布版本时打标签是个好习惯标签相当于对某个提交贴上永久标记方便后续精确回溯到发布版本。git tag v1.0.0 # 打轻量标签 git tag -a v1.0.0 -m 正式版发布 # 打附注标签推荐 git tag -l # 查看全部标签 git show v1.0.0 # 查看标签详情 git push origin v1.0.0 # 推送指定标签 git push origin --tags # 推送全部标签 git tag -d v1.0.0 # 删除本地标签 git push origin :refs/tags/v1.0.0 # 删除远程标签轻量标签只是某个提交的指针附注标签则包含打标签的人、时间、说明等完整元数据正式发布建议用附注标签。6.3 日志分析与错误定位问题排查时日志命令能帮大忙。除了之前提过的git log --oneline还有几个定向诊断的命令git blame file.txt # 逐行显示文件每行代码的提交信息 git log -S 函数名 --oneline # 查找新增或删除了某字符串的提交 git log -p -- file.txt # 查看文件每个提交中的具体改动 git bisect start # 开始二分查找定位坏提交git bisect是个隐藏神器。它能在提交历史中做二分搜索帮你快速定位“到底是哪次提交引入了 Bug”。流程是标记一个已知好的提交和一个已知坏的提交Git 会每次切到一个中间提交你测试并标记git bisect good或git bisect bad重复几次之后就锁定问题提交。几十个提交的区间五六次就能定位到问题比肉眼一条一条翻 log 高效得多。7. 高频实际问题排查速查表整理了一份我在实际开发中最常遇到的 Git 问题清单按症状列出来直接对着表格排查就行。症状可能原因解决方案git不是内部或外部命令未安装或环境变量未配置重新安装 Git检查 PATH 中是否包含 Git 的 bin 目录推送被拒绝non-fast-forward远程有新提交未拉取git pull --rebase后重新推送误提交了大文件文件超过托管平台限制git rm --cached移除跟踪然后调整.gitignore并推送误删了未提交的代码未跟踪文件被clean或手误删除如果文件从未 commit 过基本无法恢复只能靠编辑器的本地历史提交到了错误的分支分支切换前忘了确认如果未推送用 reset 回到提交前再切分支如果已推送revert 并重新提交想拆分一个大提交提交内容混杂了多个逻辑用git reset --soft HEAD~1退回暂存区再分批次 add 和 commit文件改乱了想丢弃工作区未暂存改动git restore file.txt或git checkout -- file.txt远程分支被删了本地还有远程仓库分支已清理git remote prune origin清理本地失效的跟踪引用commit 信息写错了手误未推送时用git commit --amend修改临时保存的改动找不到了stash 列表被清理git fsck --lost-found或git stash list确认clean 之前务必三思换行符导致整个文件 diffautocrlf 配置不一致统一core.autocrlf input用.gitattributes控制特定文件类型这张表覆盖了新手到中级开发者九成以上的日常困境。如果问题不在表中也可以按这个通用思路排查先git status看当前状态再git log --oneline -5看最近提交最后git diff看具体改动基本能定位问题所在。8. 我的一些常用快捷键与别名配置最后分享几个我长期使用的高频别名配置直接贴进终端就能用git config --global alias.st status git config --global alias.co checkout git config --global alias.br branch git config --global alias.cm commit git config --global alias.lg log --graph --oneline --all --decorate git config --global alias.unstage reset HEAD -- git config --global alias.last log -1 HEAD --stat配了这些别名之后git st就是git statusgit lg就是带图的日志树敲命令的幸福感提升不少。不过这个纯属个人偏好团队协作场景下谨慎使用——别人可能不知道你的别名是什么意思。还有个小技巧git log --oneline --graph --all --decorate加--simplify-by-decoration可以只看分支和标签节点忽略中间的普通提交用来快速了解仓库的整体结构非常直观。排查大仓库时也比直接翻git log高效得多。写到这里整份速查手册的主干内容就全部覆盖了。Git 命令本身不难难的是在正确的时间用正确的命令以及理解每条命令背后到底改了什么。我见过不少同事用 Git 几年还是只靠 add、commit、push 三招遇到问题就删掉整个仓库重新 clone这其实是在浪费 Git 本身最强大的能力。把这些命令用熟哪怕只记住一半日常工作效率都能提升一大截。