Git实战指南:从安装配置到分支合并与疑难杂症全解析
有些工具刚接触时觉得不过是个“命令行提交代码”的东西真正用起来才发现它每天都在跟你的代码、你的习惯、甚至你的崩溃打交道。我说的就是Git。这篇文章其实是整理给我自己的一份个人笔记顺手把安装、配置、密钥、日常提交、分支合并、还有这些年踩过的疑难杂症都串了一遍。如果你正好准备换新电脑、刚入职要看公司仓库、或者在学校里被Git折磨过直接照着这里抄作业就行至少能少走我走过的那些弯路。我不会按官方文档那种“参数大全”的方式写而是按真实使用顺序来先装好再打通远程仓库然后才是每天都要用的那一串命令最后是分支和一堆让人头疼的报错。写到的命令都是在Windows和Linux上真实跑过的macOS的差异我尽量标出来。1. 安装与环境配置装对版本后面少踩一半坑1.1 Windows装Git的几个关键选项Git在Windows上最推荐去官网git-scm.com下载认准当前系统对应的64位版本。不要图方便去第三方下载站下那种“精简版”Git的安装包本身不大官网版本最稳后面出各种“Permission denied”“PATH找不到git”的问题十有八九和装了个来路不明的版本有关。安装界面会蹦出一堆选项大部分默认就行但有三个必须认真选选择默认编辑器不习惯Vim的话一定选Visual Studio Code或Notepad之类你熟悉的编辑器不然commit时注释写错需要改直接卡在Vim里连退出都不会。调整PATH环境变量选“Git from the command line and also from 3rd-party software”。这一步特别重要选错了会导致IDEA、VSCode里找不到Git。配置行尾换行符选“Checkout as-is, commit as-is”最不容易出幺蛾子。很多人被“CRLF will be converted to LF”这种提示烦死就是因为装了默认的autocrlf转换。装完打开Git Bash输入git --version能打印出版本号就算成功。我在公司经常帮同事排查环境问题第一个命令永远是它。Linux这边更省事Ubuntu/Debian是sudo apt install gitCentOS/RHEL是sudo yum install git。macOS如果装了Xcode Command Line Tools本身就会带一个Git没装的话官方推荐的Homebrew方案brew install git。1.2 命令行与GUI的配合方式陆陆续续用过Git GUI、小乌龟TortoiseGit、SourceTree和VSCode自带的界面我的结论是日常看图用GUI干活用命令行。GUI适合看分支走向、看文件改动情况、处理复杂冲突时做辅助但真正要精确控制版本库状态命令行是不可替代的。小乌龟TortoiseGit在Windows上是很多老开发者的标配右键就能提交、拉取确实符合Windows用户习惯。但如果你要在服务器上操作或者将来换到Linux环境命令行功底就显出价值了。VSCode里的“源代码管理”面板是我现在最常用的GUI辅助提交、推送、撤销都可以点比较直观。建议路线是先用IDEA或VSCode的图形界面体验Git怎么工作同时逼自己在终端里重复敲两周命令后面就自然不动脑子了。2. 把本机和远程仓库打通SSH密钥、Gitee与GitHub2.1 生成密钥以及多台电脑怎么管理安装完Git只是本地的事真正第一次卡人的地方永远是SSH密钥。本地代码要push到Gitee、GitHub或公司的GitLab都得先建立信任关系。生成密钥的命令在Git Bash里执行ssh-keygen -t ed25519 -C 你的邮箱example.com参数解释一下-t ed25519是密钥类型现在完全没必要再生成老的RSA 2048ed25519更短更安全GitHub、Gitee都支持。-C后面的注释只是标记用途方便你在管理后台认出这把钥匙是哪台电脑的。一路回车会在~/.ssh/下生成两个文件id_ed25519是私钥绝对不能给任何人id_ed25519.pub是公钥需要复制到代码托管平台的“SSH公钥设置”里。强烈建议每台电脑生成独立的密钥一台一个这样哪天某台电脑丢失或泄漏密钥只在后台删掉那一把就行不用全军覆没。我见过有人把所有电脑的公钥都复制成同一把看似省事出一件事就得全部重置。生成之后把公钥内容加到Gitee/GitHub的SSH keys管理页然后测试ssh -T gitgitee.com如果返回“Hi xxx! Youve successfully authenticated”通路就算是打通了。多台电脑使用同一个账号逻辑上就是每台电脑都要执行上面的“生成密钥添加公钥”两步。私钥不需要在两台电脑之间互相拷贝这是很多人搞错的点。2.2 配置提交身份信息与远程地址密钥解决的是“机器认不认识你”提交记录里显示谁还得配置user.name和user.emailgit config --global user.name 你的名字 git config --global user.email 你的邮箱--global是全局配置对当前电脑所有仓库生效。如果公司内部仓库需要独立的提交身份在某个仓库目录下执行不带--global的git config就会只对该仓库生效。提交身份配错很常见后面我专门讲IDEA里怎么改。远程地址有两种https://和git开头的SSH形式。想实现免密推送最好把远程地址设置成SSH地址git remote add origin gitgitee.com:用户名/仓库名.git git remote -v一眼就能看到当前所有远程地址。如果之前用的是HTTPS地址可以这样换成SSHgit remote set-url origin gitgitee.com:用户名/仓库名.git这里有个细节很多人仓库clone的时候顺手选的HTTPS后来push每次都要输用户名密码烦到不行才想起来换SSH。把上面这条命令记住往后能省很多事。不想换协议也可以Git会默认记住Windows凭据管理器里的HTTPS凭据但账户密码一改、token一过期照样要你重新输一次。2.3 用token提交的坑Gitee现在也支持个人访问令牌Access Token很多内部系统必须用token走HTTPS。这种情况下push时提示输入密码填的不是账号密码而是token本身。有些平台为了安全账号冲没用。团队协作里如果总有人被提示“Authentication failed”八成是把这个东西填错了或者token过期了。这个坑在新手入职第一个月出现的频率非常高。3. 日常提交链路add、commit、push、pull的完整闭环3.1 工作区、暂存区、本地仓库、远程仓库的关系Git刚上手时脑子里的模型如果不对后面所有操作都会乱。我用大白话给你建立四个概念工作区就是你电脑上看得见摸得着的文件目录在这里改代码。暂存区Index/Stage可以理解成快递发货前的“待打包区”你把想发的货先码到这里。本地仓库已经打包好放进自己家仓库里的东西有完整的版本历史。远程仓库放在服务器上的那一个相当于托管给别人的正式库房。对应的三个命令就是git add xxx # 把工作区改动放到暂存区 git commit -m 说明 # 把暂存区内容存进本地仓库形成一次版本 git push # 把本地仓库的版本同步到远程为什么要搞暂存区这一层因为实际开发中你一次可能改了很多文件有些是修Bug有些是调整格式有些是临时调试用的。让你能精挑细选哪些进这次提交就是暂存区存在的意义。用git status随时可以看哪个文件在哪个区这个命令几乎是每天使用频率最高的敌人。3.2 提交与提交信息commit的自我修养提交信息这件事很多人不当回事真到回滚代码找某个功能改动时面对一堆“fix bug”“update”你会疯掉。我习惯于一条提交信息里说明“为什么改”而不是单纯“改了什么”比如“fix: 修复登录超时后token未清理导致的白屏问题”这样的历史别人看和三个月后的自己看都没负担。git commit --amend是一个很实用的命令作用是修改最近一次提交的注释或者把漏掉的文件补进上一次提交。用法git add 漏掉的文件 git commit --amend -m 新的提交信息执行完上一次提交就被替换成了新的提交。但这个操作有副作用如果上次提交已经push到了远程amend之后本地和远程历史就不一致了此时直接push会被拒绝需要强制推送。所以我的经验是commit刚写完、还没有push时amend随便用已经push到公共分支就别再用它老老实实再补一个新的提交。日常提交链路建议养成一套固定节奏git status # 先看当前状态 git diff # 再确认改了什么内容 git add 具体文件 # 不要无脑git add . git commit -m 规范信息 git pull --rebase # 提交到本地后拉取远程最新 git push很多人为了方便从来都是git add .一把梭但这样容易把调试代码、配置文件一起提交进去。配置文件一旦带上了本机绝对路径或密码迟早要出事。3.3 撤销操作版本库的“后悔药”分几个等级Git最强大的地方就在于几乎所有操作都能反悔难点是分清每个命令撤销的范围。工作区里有一行改动写乱了还没执行git add想恢复成最近一次提交的状态git checkout -- 文件名如果文件已经被git add进了暂存区想撤销暂存但保留工作区改动git reset HEAD 文件名已经commit到本地仓库了想撤回这次提交git reset三种模式是关键模式作用范围HEAD位置暂存区工作区--soft仅撤销commit回退到上个提交保留保留--mixed撤销commit和add回退到上个提交清空保留--hard全部撤销回退到上个提交清空清空--hard最暴力也最容易用错。我见过有人想撤销一个commit用了git reset --hard结果把整个工作区的代码全清没了最后靠Git的reflog才救回来。所以我给新人的建议是不确定工作区里有没有不想丢的修改时先git stash把当前改动暂存起来再reset出问题还能救。如果代码已经push到远程了处理思路就变了。公共分支上不要用reset改变历史而是用git revert生成一个反向提交。git revert会保留原来的提交记录再加一条“撤销某次提交”的新提交团队成员pull下来不会遇到冲突。如果是自己的功能分支则可以git reset --hard回退再git push --force强制覆盖远程但这非常危险多人在同一分支上开发时禁用。IDEA里也内置了这些操作右键Git - Undo Commit等价于reset --softRevert Commit等价于git revert Drop Commit等价于--hard。图形界面点起来很顺但要记住背后是什么逻辑不然点错了都不知道怎么回来的。热搜里“idea git 需要撤销已经提交到远程分支的代码”这个问题只要分清了“自己分支可以强推公共分支要用revert”基本就解决了。4. 分支操作切换、合并、剪切代码与子模块4.1 分支的本质一个会移动的指针很多教科书讲分支都讲得很玄其实分支的本质就是一个指向某个提交的指针。新建分支只是新建了一个指针所以git branch dev瞬间完成。HEAD是另一个指针表示你现在站在哪个分支上。理解了这是指针你就能明白为什么Git切换分支那么快它根本不复制文件只是把HEAD从一个分支名移到另一个分支名然后更新工作区内容。团队里的分支规范我见过无数种比较通用的是master/main分支永远保持可发布状态开发在feature分支上进行通过合并请求合回主干。公司强制走MR/PR流程的话本地提交完直接push到远程自己的分支就行不用自己合主干。4.2 在master上写的代码怎么“剪”到dev分支这是一个真实高频场景你忘了切分支在master上改了一堆代码然后发现其实应该在dev分支上做。怎么把这些改动原样搬到dev上答案有很多最稳妥的是stash也就是“临时寄存站”git stash # 所有未提交的改动先存起来工作区变干净 git checkout dev # 切到目标分支 git stash pop # 把刚才存起来的内容恢复出来git stash默认只能暂存已跟踪文件的改动新文件untracked需要加-u参数才能一并暂存。还有用git stash pop解出来的文件如果和目标分支现有代码冲突会提示冲突文件手动解决后照常add、commit即可。另一种场景是master上已经产生了若干提交不是零星改动而是完整的一段时间线。这时候适合用git cherry-pick把特定提交“摘”到目标分支git log --oneline -5 # 找到要移植的提交哈希 git checkout dev git cherry-pick 哈希值cherry-pick会把那个提交的补丁在当前分支重新应用一遍产生一个全新的提交。它适合用来移植某个Bug修复或小功能但千万别顺手摘一个依赖了其他大量历史提交的巨型提交摘过去冲突会多到你怀疑人生。4.3 合并时merge和rebase怎么选合并分支Git提供了两条路。git merge dev把dev分支的变更合并进当前分支会产生一个专门的合并提交历史优势是真实记录分支关系看git图能看出来哪些是并行开发的。团队协作要求保留来源脉络时就用它。git rebase dev则是把当前分支的提交“变基”到目标分支上历史变成一条直线看起来干净git log更清晰。但rebase会改写提交哈希如果这个分支已经push出去了别人也拉走继续用了你rebase后再强推就会把别人的历史打乱非常麻烦。我的个人习惯是还没push的本地小分支用rebase把历史整理干净已经多人共享的开发分支只用merge。记住一个万能原则——别改写别人也会基于它开发的分支历史。4.4 git submodule仓库里套仓库一些项目需要依赖另一个仓库里的代码既不想把对方代码直接复制进来复制其历史又想要随时能更新这时候就用到了git submodule。添加一个子模块git submodule add gitgitee.com:某组织/公共组件.git components/common执行完仓库根目录下会出现一个.gitmodules文件记录子模块的地址和路径components/common并不是普通文件而是指向子模块仓库特定提交的“指针”。别人clone你的项目时光是git clone还拿不到子模块内容需要再执行git submodule init git submodule update或者一条命令搞定git clone --recursive 仓库地址。子模块更新是常见的坑你改完子模块里的代码主仓库不会自动跟着更新必须在主仓库里把子模块的指针提交一下别人才能拿到你更新后的版本。说一下什么时候不该用submodule。如果你只是需要把一段代码复制过来没有双向维护需求那直接复制一个目录进来更省事。submodule带来的是版本同步的便利代价是操作复杂度、clone时的额外步骤、还有“怎么子模块里改了主仓库没响应”的理解成本。小团队初期不要为了架构上的美观强行上submodule等公共组件真的被多个仓库复用了再考虑也不迟。5. 我在使用中遇到过的疑难杂症碰到再来看5.1 ssh认证失败可能不是密钥本身的问题热搜里“ssh认证失败 git”是个高频单词。“Permission denied (publickey)”这种报错排查顺序我自己总结成一套口诀看当前用的远程地址git remote -v如果显示https://开头那SSH密钥用不上走的是账号密码或token问题不在密钥。看本地有没有私钥ls ~/.ssh/如果只有.pub公钥文件而没有私钥文件说明密钥对丢了重新生成一对再添加公钥吧。看ssh是否加载了私钥ssh-add -l如果提示“The agent has no identities”执行ssh-add ~/.ssh/id_ed25519。看公钥是否真的粘到托管平台重新打开Gitee/GitHub设置页比对一下。还有一个很多人忽略的问题如果~/.ssh/下同时存在多对密钥git默认只会用id_rsa或id_ed25519这个名字去找。你生成的密钥如果叫了别的名字需要在~/.ssh/config里配置Host别名指定IdentityFile。这几年公司项目同时绑定GitHub和GitLab、还有内部服务器时这个坑我踩得最深。5.2 git open /dev/null or dup failed: no such file or directory这个报错名字很长出现的场景大多是Windows下脚本调用Git时Git需要访问/dev/null这个Unix设备文件而在Windows的某些环境特别是非Git Bash的第三方程序调用下找不到它。我遇到时是在IDEA里执行了一个自定义的pre-commit钩子脚本脚本里直接用了/dev/null做重定向。解决办法有几种如果是本地钩子脚本的问题把脚本里的/dev/null改成Windows兼容写法NUL或者干脆用git -c core.quotepathfalse等参数绕过对设备的依赖。如果是IDE插件的问题检查IDE是否安装了非官方Git插件或看看环境变量GIT_EXEC_PATH有没有被污染。还可以试试把终端从PowerShell切换成Git Bash再执行相同命令报错往往会消失因为这本质上是“Windows进程环境与Unix风格命令不兼容”的问题。这种错误不属于逻辑错误不会因为你的代码写得对而自己消失重点永远是检查调用Git的宿主进程是什么、它的环境变量是继承自谁。5.3 .git目录泄露被别人看到了不该看的源码“git目录泄露如何下载”这个热搜背后是一个常见的安全配置问题项目部署或打包时把.git目录一并放到了Web服务器可访问的目录下。Git仓库的全部历史都藏在.git文件夹里攻击者只要能通过浏览器访问http://目标站点/.git/理论上就能把整个源码包括误提交的密码、密钥全部下载下来。作为开发者正确的处理方式首先是预防部署到服务器前确认.git目录不会出现在Web根目录下如果使用Nginx可以配置禁止访问以点开头的目录location ~ /\.(?!well-known).* { deny all; }用Apache的话在项目根目录创建.htaccess加一行RedirectMatch 404 /\.git。如果发现自己负责的系统已经有这个风险第一步先把服务器上的.git目录移走然后去托管平台或代码库查历史提交里有没有提交过敏感信息有的话用工具清洗历史并立即轮换所有可能已经泄漏的密码和密钥。这个排查过程一定要完整因为Git历史里旧痕迹特别难清干净只删当前文件不清理历史等于白做。正规授权测试场景里从泄露的.git恢复源码只是验证风险的过程重点永远是修复和预防。5.4 其他容易糊弄过去的细节提交账户、换行符、乱码提交人信息不对是我在IDEA用户里见过最频繁的“小事”。多人共用一台测试机或者入职后第一次提交忘了改user.namepush上去显示的是上一任的名字。修改方法分两层临时修改当前仓库git config user.name 新名字然后git config user.email 新邮箱。需要彻底改干净包括历史提交也能正名的话警告一句修改历史提交作者是结构化操作必须在专业指导下执行不然仓库历史会被重写。IDEA里的设置路径是File - Settings - Version Control - Git右侧有User Name和Email输入框修改后对新提交生效。如果只是某一次提交时想换身份在Commit面板右下角的Author区域临时改就行。换行符问题Windows和Linux协作时特别明显。因为Windows用CRLFLinux用LFGit默认会做转换。很多看起来“明明没改文件为什么diff一大堆”的诡异现象根源都是换行符。前面安装时选了“checkout as-is, commit as-is”之后再把.gitattributes里对应文件的换行规则声明清楚基本能杜绝。中文乱码则多数是编码问题最常见的是git log显示中文乱码设置一下核心寻码git config --global core.quotepath false git config --global gui.encoding utf-8 git config --global i18n.commit.encoding utf-8core.quotepath false这个参数信息量很大默认情况下Git会把非ASCII文件名转义成八进制序列显示出来就是一团乱码关掉之后就能正常显示中文文件名了。最后想说一句个人体会Git入门的门槛不在于记住多少命令而在于把它背后的模型想清楚——工作区和仓库的关系、分支和指针、本地状态和远程状态的差异这几件事一旦通了绝大多数报错都能自己推出来。你不需要把本文每条命令背下来需要用的时候翻到这里照着敲踩几次坑之后这些操作就长在脑子里了。本文收藏起来当你的Git速查手册用。