ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Git高频命令实战指南:从三区域模型到分支冲突撤销全解析

Git高频命令实战指南:从三区域模型到分支冲突撤销全解析 在命令行里讨生活的人Git的常用命令几乎是每天都要敲的。有人说Git难学命令一长串记不住但我的实际感受是只要把Git背后的运行逻辑搞明白绝大多数命令都是顺理成章的事。这篇文章不是把Git手册抄一遍而是把我多年实战里真正高频使用的命令、踩过的坑、以及那些文档里不会明说的细节按使用场景重新梳理一遍。无论你是刚接触Git的新手还是用了几年想查漏补缺的老手都能从中找到可直接照抄的操作思路。1. 先搞明白Git在干什么命令才记得住很多人学Git失败不是因为命令多而是因为没弄明白Git内部到底有几个区域。Git和SVN这类集中式版本控制最大的区别就是它把代码状态分成了三个独立的区域理解了这个模型后面所有命令都顺理成章。1.1 三个区域工作区、暂存区、版本库我把这三个区域用一个生活化的类比拆开讲。工作区Working Directory就是你电脑上看到的项目文件夹这里面的文件是你正在编辑、修改的真实内容暂存区Staging Area也叫Index是一个中转站你通过git add把工作区里改动的文件挑出来放进去相当于先打个草稿告诉Git我准备提交这些改动版本库Repository则是Git真正保存历史快照的地方通过git commit把暂存区的内容固化成一个版本记录。可以理解为工作区是你桌面上的草稿纸暂存区是待发信箱版本库是归档柜只有归档柜里的东西才是真正永久留存的。搞懂这个流程就明白为什么git add之后再改文件提交的内容可能不是最新的——因为暂存区里存的只是你add那一刻的版本。1.2 命令和三个区域的关系git status这个命令之所以是最高频的命令就是因为它能告诉你当前每个文件处于什么状态已修改Modified、已暂存Staged、已提交Committed。我在实际工作中几乎每隔几分钟就会敲一次git status这不是强迫症而是确认状态最直接的方式。当你理解了状态流转命令就不是死记硬背了工作区改动用git add进入暂存区暂存区内容用git commit进入版本库版本库内容用git push推到远程仓库反过来远程仓库用git pull拉下来版本库用git reset或git checkout把内容恢复到工作区。整个数据流是单向的、可追溯的每个命令都是在这个管道上开一个阀门。2. 安装、配置和初始化从零到能用起来的必修课这一部分看似简单但我在帮同事处理环境问题的时候发现很多Git命令用不了的根源都出在安装和配置环节而不是命令本身。2.1 各平台安装要点Windows平台现在主流是直接下载Git for Windows安装包一路下一步就行。安装完成后记得在开始菜单里确认一下Git Bash和Git GUI是否正常启动——Git Bash是一个模拟Linux终端的工具在Windows上跑Git命令比自带的cmd和PowerShell顺手得多因为很多快捷键比如CtrlU清空当前行和命令行习惯都跟Linux一致。macOS建议用Homebrew安装brew install git比官网下载dmg包方便升级。Linux发行版则看包管理器Ubuntu/Debian用apt install gitCentOS/RHEL用yum install git。装完务必用git --version确认版本号我看到过有人装了个很古老的2.x版本很多新特性比如部分switch、restore命令都用不了。2.2 三件套配置身份、编辑器、换行符初始化之前必须配好身份信息否则提交会报Please tell me who you are的错误。全局配置只需要做一次git config --global user.name 你的名字 git config --global user.email 你的邮箱这里有个细节很多人不知道user.name 不一定要填真名但 user.email 建议填你在Git平台比如Gitee、GitHub绑定的邮箱这样提交记录才能正确关联到你的账号。除了身份信息我强烈建议顺手配置默认编辑器和换行符。默认编辑器如果不配在Linux上会弹vi在Windows上可能直接卡住无法退出配成VS Code或者Notepad会舒服很多git config --global core.editor code --wait git config --global core.autocrlf input关于换行符core.autocrlf多说一句Windows用CRLF换行Linux/macOS用LF换行如果不做处理跨平台协作时会出现整个文件都被标记为改动的情况。Windows建议设为true提交时自动转成LF检出时转成CRLFmacOS和Linux建议设为input只处理提交时的转换检出保持LF。2.3 初始化仓库和.gitignore过滤文件在项目根目录执行git init这条命令会在当前目录生成一个隐藏的.git文件夹这个文件夹就是版本库本体。有个高频报错fatal: not a git repository (or any of the parent directories): .git出现这个错误多半是你站在一个没有初始化过的目录里执行Git命令用ls -a看看有没有.git就知道了。初始化后第一件事我建议是写.gitignore文件。这个文件的匹配规则我踩过不少坑总结几个关键点node_modules/表示忽略整个目录*.log表示忽略所有.log文件!important.log表示排除例外比如虽然忽略*.log但important.log必须提交build/结尾带斜杠表示只匹配目录。很多新手发现我明明写了过滤规则但文件还是被提交了大概率是因为文件在加入.gitignore之前就已经被git add过了——Git会追踪已经被追踪的文件.gitignore对它们无效。解决办法是先git rm --cached取消追踪再提交一次。另外注意.gitignore对于已经忽略的文件在不同目录层级都生效规则就近匹配所以不要在子目录里重复写全局规则。3. 日常开发最高频的三板斧add、commit、push写代码一天下来我碰得最多的命令就是这三个但真正把它们用利索的人不多尤其commit里面藏着不少细节。3.1 状态检查和diff差异查看动手提交之前一定要先看状态。git status会告诉你当前分支、暂存区和工作区的情况。但如果想看具体改了什么内容就得用git diff默认的git diff看的是工作区和暂存区的差异git diff --staged看的是暂存区和版本库的差异git diff HEAD则是工作区与当前版本库的全部差异。实际场景里我经常写完代码后先git diff自己review一遍再决定怎么提交。如果只想看某个文件的变化就git diff path/to/file。这里有个好习惯提交之前一定要用git diff --staged过一遍暂存内容防止把调试代码或者临时文件提交上去。3.2 add的几种姿势和提交规范添加文件到暂存区最常用的写法git add . # 把当前目录及子目录所有改动加入暂存 git add src/ # 添加目录 git add app.js # 添加单个文件 git add -p # 交互式添加分块选择git add -p是个隐藏神器。当你在一个文件里混着改了多个不相干的功能可以用它选择性地只暂存某些hunk代码块做到一次提交只包含一个逻辑变更。推荐提交信息遵循Angular规范type(scope): subject比如fix(login): 修复密码框无法自动填充的问题。type常用feat新功能、fix修复、docs文档、refactor重构、style格式、test测试。规范的好处不是给谁看而是日后git log回溯时一眼就能看出某个改动是干什么的配合git blame找历史责任人极其高效。3.3 commit的细节与amend操作git commit -m feat(user): 增加用户注册接口 git commit -am fix(order): 修复订单状态更新问题-a参数表示把已追踪文件的改动直接提交但注意它只能暂存已经跟踪过的文件新文件还是需要先add。提交完了发现信息写错了或者少提交了一个文件如果还没有push到远程用git commit --amend可以把最近一次提交修补掉。这个命令实际上是用一个新的提交替换掉旧的提交所以提交ID会变。使用场景git add漏掉的文件想补进去提交信息打错字或者想把两个提交合并成一个。这里有个严肃提醒已经 push 到公共分支的提交千万不要用 amend因为它会改写历史远程其他人的本地历史就会产生分叉除非你有充分的、可控的团队协作理由。3.4 push到远程仓库本地提交完成后把当前分支推到远程git push origin main git push -u origin main # 第一次推送带上-u建立本地分支与远程分支的跟踪关系-u--set-upstream很关键。第一次推送时加上它以后直接敲git push和git pull就不用再写远程仓库名和分支名了。还有个常见操作是删除远程分支git push origin --delete old-branch。注意删除远程分支不会影响本地分支本地分支要单独删。4. 分支管理并行开发的命脉分支是Git最强大的设计之一日常开发中你的代码永远不该直接提交到main或master上而是应该基于一个功能分支工作。4.1 查看、创建、切换、删除分支git branch # 查看本地分支带*的是当前分支 git branch -r # 查看远程分支 git branch -a # 查看所有分支 git branch feature-login # 创建分支 git switch feature-login # 切换分支新版命令 git checkout feature-login # 老版切换分支仍然可用 git switch -c feature-login # 创建并切换等价于git checkout -b git branch -d feature-login # 删除分支新版Git推荐用switch和restore代替checkout的部分职责区分更清晰switch只管切换分支restore只管恢复文件。带-c的创建加切换是最常用写法因为实际工作中99%的场景是从主分支拉一个新分支开始干活。删除分支用-d表示safe delete只有已经合并过的分支才允许删除如果分支未合并但确实不要了用-D强制删除。我建议不要习惯性用-D除非你有十足把握。4.2 合并分支与冲突处理把功能分支合并回主分支git switch main git merge feature-logingit merge会基于当前分支和待合并分支的共同祖先生成一个新的合并提交merge commit。如果两个分支都能各自演进合并时可能有冲突。冲突文件会被Git标记出来文件内容会出现类似 HEAD 当前分支的代码 要合并进来的代码 feature-login处理冲突的手动步骤是打开冲突文件手动选择和修改保留的代码删除、、这些标记行然后git add这个文件再git commit。这里有一个容易忽略的点合并时如果有文件冲突Git不会自动创建提交而是处于待解决状态你确认解决完全部冲突后才能提交。而且合并冲突不等于世界末日你随时可以用git merge --abort取消合并回到合并前的状态我觉得这个命令就像游戏里的存档点压力大了就退回来。4.3 rebase的用法和禁忌分支操作中还有一个高频场景是git rebase。git rebase main会把当前分支上基于旧基点产生的提交重新在 main 分支的最新提交后面重放一遍让分支历史变成一条干净的直线。我个人的习惯功能分支开发期间每隔一段时间就git rebase origin/main一下把主分支的新改动吸收进来减少最后合并时的冲突。注意这里是吸收了主分支的改动不是把自己的改动往主分支上推。rebase的禁忌比merge严格得多绝对不要对已经推送到远程共享分支的提交做rebase这等于重写公共历史会让其他人的本地分支乱成一团。如果冲突太多就用git rebase --abort退出。5. 撤销与后悔药改了想反悔的完整方案写代码早晚要删错文件、提交错代码Git的撤销体系是分层的你得知道自己处于哪个状态。5.1 工作区、暂存区、提交后的撤销不想破坏历史且只撤销工作区改动git checkout -- file.txt # 老写法 git restore file.txt # 新写法这条命令会把工作区指定文件恢复到最新提交的状态风险在于所有未提交的改动会丢失且无法找回。想撤销git add但也保留工作区改动让文件退回到已修改状态git reset HEAD file.txt # 老写法 git restore --staged file.txt # 新写法提交之后的撤销有两种思路git reset移动分支指针git revert新增一个反向提交。5.2 reset的三种模式和revert的差异git reset --soft HEAD~1 # 撤销提交保留暂存区内容 git reset --mixed HEAD~1 # 撤销提交保留工作区内容但取消暂存默认模式 git reset --hard HEAD~1 # 撤销提交工作区和暂存区都恢复到上一个版本改动全部丢弃--soft适合刚才提交信息写错了想重新提交--mixed适合提交后发现还有文件忘了加退回后重新组织完整提交--hard是最危险的它会把所有改动抹掉我几乎只有在彻底不要这些改动的时候才用。与之配套的是git revert它与reset逻辑完全不同revert不会移动历史指针而是创建一个新的提交把目标提交的改动反向应用一遍所以它适用于已经push到远程的提交。团队协作场景里撤销线上代码我永远用revert而不是reset因为revert是安全的历史追加不会破坏其他人的本地记录。5.3 stash的暂停魔法正改着代码突然需要紧急切换分支去修bug半成品又不能提交这时候git stash就是救命稻草git stash # 把工作区改动保存到栈中工作区恢复干净 git stash save 描述 # 带描述存入 git stash list # 查看所有暂存记录 git stash pop # 恢复最近一条并删除它 git stash apply # 恢复但保留记录 git stash drop # 删除一条记录 git stash branch new-branch # 基于暂存内容创建新分支取回我常用的场景就是临时切分支用stash把当前工作区暂时收起来切换到目标分支处理紧急任务处理完切回来stash pop恢复现场完好无损。有一个小坑如果暂存完之后有多个记录git stash pop默认弹的是最近一次stash的记录也就是栈顶。恢复时出现冲突也是常见问题解决方法和merge冲突一样手动修改后git add然后stash drop即可但注意如果poph冲突了那条stash记录不会被删掉你得手动删。6. 远程仓库协作clone、fetch、pull、认证那些事单人开发用Git很简单一旦多人协作远程相关的命令就绕不开了。6.1 clone和remote管理从远程拉取一个项目到本地git clone gitgitee.com:username/project.git git clone https://gitee.com/username/project.git git clone -b develop gitgitee.com:username/project.git # 克隆指定分支clone之后Git自动建立origin这个远程仓库别名并拉取默认分支实际开发多分支场景建议-b指定一个分支不然默认是主分支。管理多个远程仓库的场景也越来越多比如同时对接开源镜像和公司内部仓库git remote add origin gitgitee.com:username/project.git git remote add upstream https://github.com/xxxx/project.git git remote -v # 查看远程列表 git remote remove upstream # 删除远程git remote -v是我排查问题第一步必执行的命令很多push失败其实是远程地址写错了这个命令一看便知。6.2 fetch、pull的区别git pull实际上是git fetch加git merge的组合fetch只把远程仓库的最新提交拉到本地的远程跟踪分支比如origin/main不会动你本地分支merge再把origin/main合并到当前分支。所以当你只想看看远程有什么新东西而暂时不想合并时用git fetch是完全没有副作用的我可以放心执行想直接同步最新代码用git pull。日常开发有一个痛苦时刻本地改了文件远程也改了同一个文件git pull会直接报告冲突处理方式和分支合并一样。有人偏爱git pull --rebase让本地提交重放到远程最新提交之后保持提交历史是一条直线我个人的风格是在自己未push的功能分支上偏向用--rebase在多人共享的release分支上绝对只用普通merge避免rebase改写历史。6.3 SSH密钥配置和认证故障排查热词里有人搜git配置gitee密钥这里完整讲一遍。生成密钥对ssh-keygen -t ed25519 -C 你的邮箱一路回车即可密钥默认保存在~/.ssh/目录下生成id_ed25519私钥和id_ed25519.pub公钥。然后把公钥内容复制粘贴到Gitee/GitHub后台的SSH Keys设置里。验证是否配置成功ssh -T gitgitee.com看到欢迎信息就说明认证通过。常见的ssh认证失败问题第一先排查公钥是否有粘贴完整公钥是从ssh-ed25519或ssh-rsa开头的完整字符串不能有换行第二检查ssh-add -l看私钥是否被SSH agent加载如果提示没有执行ssh-add ~/.ssh/id_ed25519第三排查代理因素很多公司网络环境存在SSH端口超时问题可以尝试把Git SSH端口改为443在~/.ssh/config中添加Host gitee.com、HostName gitee.com、Port 443、User git四行配置。另外如果之前用HTTP方式登录过仓库Windows凭据管理器里会缓存旧密码导致切换账号后依然报认证失败需要去控制面板的凭据管理器里删掉对应的Generic Credential条目再重新操作。7. 高频排查与常见问题速查最后我把真正在实战中经常遇到的疑难杂症整理成一个速查表遇到问题直接照着查。现象原因解决方案fatal: not a git repository当前目录没有初始化过Git检查是否在项目根目录执行ls -a看有无.git没有就git initPlease tell me who you are没配置身份信息全局git config --global user.name、user.emailpush被拒绝non-fast-forward本地落后远程最新先git pull合并或git pull --rebase后再pushpull冲突本地与远程改到同一文件手动解决冲突add后commitSSH认证失败公钥没配好或代理影响用ssh -T gitgitee.com测试检查公钥粘贴、私钥加载commit信息写错反悔未push用git commit --amend已push用revert误删文件工作区版本丢失未提交可用git checkout -- file恢复已删除未跟踪就只能自求多福status显示一堆删除或新增换行符或文件权限变化检查core.autocrlf用git config core.filemode false忽略文件权限变化想把多个commit合并成一个提交历史凌乱git rebase -i HEAD~n里把pick改为squash.gitignore不生效文件已被Git追踪git rm --cached -r .后重新add补充两个我个人非常依赖的配置。第一个是别名alias把长命令缩短成自己的快捷键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 --oneline --graph --all --decorate配置完之后git lg可以图形化查看提交历史分支走向一清二楚我强烈推荐给所有人设一个。第二个是大文件管理像二进制包、模型文件、设计素材这类超大文件直接用Git提交会让仓库体积爆炸团队协作到后期clone仓库卡死、磁盘膨胀。这种情况建议启用Git LFS先装git-lfs在仓库里执行git lfs install再用git lfs track *.zip指定要管理的大文件类型。注意LFS也有坑LFS文件本身是存指针的真实内容存在远程LFS存储里如果遇到git lfs clone 卡住多半是网络带宽问题或者做了lfs.fetchexclude把某些LFS路径排除了。最后再分享一个小的实战心得Git其实是很宽容的工具几乎所有危险操作都有对应的补救办法。如果你不确定某个命令的后果最好的办法是先开个新分支试一遍或者用git stash把当前状态留个底再操作。用的时间久了你会发现会用的命令多不如避开的坑多更实在熟记上面这些常用命令和对应场景日常开发基本就能游刃有余了。
返回列表