
1. 从装好到能提交Git的安装与初始配置Git对搞技术的人来说基本等同于写字楼里的工牌——不戴没法进门戴上了又没人多看你一眼。但说实话真正把Git用得顺溜的人并不算多大部分人停留在git add、git commit、git push这三板斧上遇到稍微复杂一点的场景就懵了。这篇文我从安装开始把Git基本操作里最常用、最核心的部分捋一遍重点是让你看完能直接上手干活而不是背一堆命令。先说安装。如果你用的是Windows直接去Git官网下载exe安装包就行注意选64位版本。安装过程基本一路Next但有两个地方需要留意一是安装路径尽量不要带中文和空格二是默认编辑器建议保留Vim不要手欠改成记事本不然之后写提交信息会出乱子。macOS上最简单的方式是直接装Homebrew终端里输入brew install git一条命令搞定比去网站下载安装包省事得多。Linux的话Debian系用apt install gitRedHat系用yum install git发行版对应的包管理器装完就能用。装好之后输入git --version能看到版本号说明安装成功。这时候别急着创建仓库先做两件非常重要的事配置用户名和邮箱。这两项会写进每一次提交记录里相当于你在代码世界里的身份证没有它你连commit都提交不了。git config --global user.name 你的名字 git config --global user.email 你的邮箱我见过不少新人在这一步偷懒结果就是提交记录里显示一堆乱码或者邮件地址是空的后面要改还得用filter-branch之类的复杂命令清洗历史麻烦得要命。所以该配的配好省得以后折腾。global参数表示全局生效意思是你这台机器上所有Git仓库都会用这份身份信息。如果你的不同项目需要用不同身份就在具体仓库里去掉global重新设置仓库级配置会覆盖全局配置。2. 天生反直觉的暂存区add、commit、status的底层逻辑很多人学Git最别扭的地方在于它多了一层“暂存区”的概念。对比一下SVN时代你改完文件直接commit就完事Git非要搞一个中间态看起来多此一举。但正是这个设计让Git在操作灵活性上甩开老一代版本控制工具几条街。打个比方暂存区就像你逛超市时手上的购物车。你逛一圈拿了很多东西修改过的文件最后结账commit前还可以决定哪几样放进购物车、哪几样放回货架。买什么、不买什么你说了算。这就是git add和git reset不带任何参数时的默认行为干的事。日常工作流通常是这样的。你改了代码之后先git status看看当前仓库状态红色文件就是改过但没加入暂存区的绿色文件是已经加进暂存区准备提交的。看清楚了再git add指定文件或者直接git add .把当前目录下所有改动全部加进去。add完再git commit -m 提交说明把暂存区内容固化成本地版本。这里有个很重要的实操心得提交说明一定要写清楚“为什么改”而不是“改了啥”。看历史记录的时候“修复登录接口500错误”一眼就知道这次提交干了什么“修改代码”、“更新文件”这种等于没写。遇到需要回退版本的时候好的提交说明能帮你节省大量翻代码的时间。还有一个很多人容易搞错的点git add只会把你当前工作区的最新状态暂存。如果你add之后又改了同一个文件需要再次add才能把新改动纳入暂存区否则commit提交的是前一次add时的旧版本。这个坑我踩过不止一次最惨的一次是上午add完下午又调了几个参数直接commit推上去了最后回滚费了好大劲。3. 分支就是平行宇宙创建、切换、合并与冲突解决分支是Git最引以为傲的功能也是新手从“会用”走向“会用得优雅”的分水岭。理解分支之前你要先在脑子里建立一个认知Git的每一次commit都像给项目拍了一张快照而分支就是一条条从主线上分出去的平行时间线。默认情况下你所在的分支叫master现在也有不少项目叫main因为GitHub新建仓库默认分支名改成了main。你在一个分支上做修改、提交不会影响其他分支。这就是为什么多人协作时每个人可以放心大胆地改代码不用担心弄坏别人的东西。建立新分支用git branch 分支名切换到新分支用git checkout 分支名。觉得麻烦的话可以直接git checkout -b 分支名一步完成“创建并切换”。另一套命令是git switch专门负责切换分支逻辑更清晰新版本Git推荐用这个。分支开发完要合回主线就用到git merge。合并有两种情况一种是没有冲突的快进合并Git直接把指针往前挪历史线是直的干净利落另一种是两个分支各自都有新提交Git需要做三方合并这时候如果同一行代码被两个人改得不一样就会产生冲突。冲突解决是Git学习中最大的拦路虎。我第一次遇到冲突的时候看着代码里一排排的 HEAD和 分支名整个人都是懵的。其实规则很简单上面的部分是当前分支的代码下面是待合并分支的代码。你需要手动决定保留哪一边或者两边都保留、都修改把冲突标记符号全删掉再git add标记为已解决最后commit完成合并。这里给一个独家建议在没有充分把握的情况下不要在大半夜精神疲惫的时候做复杂合并。代码冲突本来就是最需要细心的时候疲劳状态下极容易删错代码而且有些错误不会立刻暴露等发现时已经过了好几个提交流程定位起来非常痛苦。另外推荐养成“小步提交、频繁合并”的习惯分支与主线的差异越小冲突概率越低即便冲突了也容易解决。4. 时光机不是科幻reset、revert、checkout的回退艺术版本回退这块内容是我跟新手交流时最爱细讲的部分。因为大家的需求太一致了改坏了想回到某个“还能用的状态”。Git提供的回退方案有好几套它们各有适用场景用错了可能丢东西所以这部分必须讲透。先认识HEAD这个概念。HEAD就是一个指针指向当前分支最新的那个提交。如果要回退历史版本最常用的命令是git log查看提交历史拿到一串hash值就是每个提交的唯一ID然后git reset --hard 目标hash你当前的分支就直接跳到了目标版本上。git reset有三种工作模式--soft只动HEAD指针暂存区和工作区都不变--mixed默认把暂存区也重置工作区不动--hard最狠HEAD、暂存区、工作区全部回到目标状态。换句话说--hard会把你工作区里没有提交过的修改统统丢掉现场不可恢复。所以我强烈建议不到万不得已别用--hard。如果改动已经push到了远程仓库回退就要换一个策略。git reset只会影响本地历史直接覆盖远程会污染公共历史影响团队其他人。Git提供了一条更文明的路——git revert。它做的事情不是“撤销”而是“反做”生成一个新的提交把目标提交的所有改动反向执行一遍。举个例子你需要撤销某次删除了配置文件的提交revert得到的这个新提交会把那个文件重新加回来。这样历史是往前走的不回改变动过的提交ID团队协作时不会引发“我的历史和你的历史对不上”这种恐怖故事。至于git checkout它既能切分支也能把单个文件恢复到某个版本的状态。git checkout -- 文件名效果是把工作区里对该文件的未提交修改全部丢弃恢复到最近一次commit的状态。注意这个操作同样不可逆执行前真的想清楚。我曾经因为手滑执行了git reset --hard HEA D多打了个空格直接把一下午的改动全清了。那时候我还不知道有git reflog这个东西。Git其实会对HEAD的每一次移动做记录reflog就是查看这些记录的入口。就算reset错了从reflog里找到移动之前的hash再用reset切回去数据就能找回来。这个技巧我放到最后的常见问题里细讲因为关键时刻它是能救命的。5. 本地与云端同步remote、push、pull的协作姿势版本控制做到本地仓库这一层只算完成了一半。真正让Git发挥价值的是与远程仓库联动。所谓远程仓库可以理解成一台24小时开机的“公共服务器”所有人把代码推上去、拉下来实现协同开发。远程仓库的主流选择是GitHub、GitLab、Gitea这类平台。不管用哪个核心操作模式都差不多。初始化本地的连接方式有两种一种是在平台上先建好空仓库然后把地址关联到本地另一种是从远程仓库直接克隆下来。克隆非常简单git clone 仓库地址一条命令就把远程项目完整地复制到本地。关联已有本地项目则需要手动添加远程地址git remote add origin https://github.com/用户名/仓库名.git这里origin只是远程仓库的默认别名你可以理解成给这台服务器起了个简短的外号免得多敲一段又长又容易打错的URL。改完代码推送用git push origin 分支名拉取更新用git pull origin 分支名。但push和pull背后各有一个隐藏细节讲清楚能帮你少踩很多坑。push比较旧版本Git时会被提示“无法推送因为当前分支没有设置跟踪的上游分支”。这时要么在执行push时后面补上-u参数命令变成git push -u origin 分支名建立一次上游关联之后再push只需输入git push。要么重新remote add关联远程地址。pull这边如果你本地和远程都各自提交了内容Git需要自动或手动合并这和前面说的分支合并是同一套逻辑。如果合并出冲突解决办法跟分支冲突一模一样。关于HTTPS和SSH的选型我推荐直接用SSH。HTTPS方式每次push、pull都要输一次账号密码虽然可以把凭证缓存到系统里但换机器、换网络环境后经常莫名失效体验比较割裂。SSH只需要把本地生成的公钥添加到GitHub或GitLab账号里之后所有操作都不用再输密码。私钥相当于你的终身密钥只要不泄露连接就是安全的。命令是ssh-keygen -t rsa -b 4096回车之后一路确认会在用户目录的.ssh文件夹下生成id_rsa私钥和id_rsa.pub公钥两个文件。然后把公钥内容复制到平台设置的SSH Key配置里。这套流程一次配置处处受用值得花十分钟把它搞定。6. 再懒也要会的进阶技巧stash、log、tag一个都不能少等前面这些操作都熟练了你会发现日常开发中还有三个高频场景靠基础命令也能完成但效率很低。这时候更优雅的解决方案就登场了。第一个场景你正在分支A上写一个功能写到一半领导突然让你去分支B修个紧急Bug。这时候工作区里的改动直接切换分支会被Git拦截因为会覆盖未被保存的改动但提交又不合适——功能还没写完提交记录会变得很脏。git stash就是为这种场景设计的它把工作区中未提交的修改打包存到一个临时储物间让你的工作区恢复干净。处理完Bug回到分支Agit stash pop把改动恢复出来继续写之前的功能。这个命令救过我无数次新人不掌握真的会处处碰壁。第二个场景查看历史提交。很多人习惯git log之后发现输出太长、太杂就放弃了。其实加几个参数就能得到漂亮简洁的格式。我个人最常用的是git log --oneline --graph --decorate效果是每条提交只显示一行简短hash和说明文字分支走向用线条画出来一目了然。如果你只想看最近N条记录git log -N就行。想看某个文件的完整修改历史git log --follow 文件名。掌握这些过滤组合排查问题的时间能压缩一大半。第三个场景发布版本打Tag。项目中每个正式对外发布的版本最好打一个标签这样以后任何时间点需要回溯“上个版本长啥样”直接根据tag找到对应提交即可。创建标签命令是git tag v1.0.0给当前分支的最新提交打标签。打标签的时候最好附带说明用git tag -a v1.0.0 -m 发布v1.0.0版本包含xxx功能。带a参数的意思是创建附带注释的标签。推送标签到远程仓库和推送分支的命令略有不同普通git push不会自动把本地标签推到远端得显式执行git push origin --tags。7. 现场实录一个日常功能开发的完整Git流程理论知识讲了一大堆是时候把它们串起来跑一遍完整流程。下面这几段是我的个人项目里一次典型的功能开发记录你照着这个节奏走基本能把前面所有知识点融会贯通。假设我正在开发一个博客系统线上稳定版本在master分支我需要新增一个“标签云”功能。第一步从最新的master拉一条新分支出来git checkout master git pull origin master git checkout -b feature/tag-cloudgit pull先把本地master同步到和远程完全一致确保分支基于的是最新代码。checkout -b创建并切换到新分支命名为feature/tag-cloud一眼就能看出这个分支要做什么事。接着我在项目里创建了新模块、改了不少代码。做到一半去上了个厕所回来想看看自己到底动了哪些文件输入git status发现有些改动已经达到阶段性完成的状态有些还在开发中。这时候我把能提交的先提交还没完成的继续写git add api/tag.py models/tag.py templates/tag.html git commit -m 新增标签云的后端模型与接口等到功能全部写完、本地自我测试通过把剩下的改动也提交掉然后把分支推到远程仓库git add . git commit -m 完成标签云页面样式与前端交互 git push -u origin feature/tag-cloud因为这是第一次推这个分支加了-u参数建立上游关联。推完之后如果在团队开发环境可以去GitHub/GitLab上发起Pull Request或者叫Merge Request让同事Review代码确认没问题后合并到master。个人项目的话直接在本地合并更痛快git checkout master git pull origin master git merge feature/tag-cloud git push origin master切回master后先pull一遍防止这段时间别人往master上推了东西。merge的时候如果没冲突消息非常干净利落。最后别忘了给这个功能合入打一个开发过程中的小tag方便日后回溯git tag -a v1.3.0 -m 新增标签云功能 git push origin v1.3.0如果你把这条流程跑完会发现Git的大部分常用操作其实就发生在这么几个时刻开发前拉分支、开发中攒提交、开发后合代码。真正需要高级操作的机会并不多但每一个都需要你用之前的知识框架去理解去查证去稳健处理。8. 避坑指南新手最容易翻车的5个Git问题最后这部分把我在新手期和帮别人救火时遇到的高频问题整理一遍。这些问题平时不注意一旦遇到了就是极其痛苦的几个小时对照表收藏一下能省很多事。问题现象根因解决方案commit之后发现漏了一个文件忘了addgit commit --amend -m 新提交说明 可以把漏掉的文件补进上一次提交且不会多生成一条提交记录提交信息写错了手滑git commit --amend 重新编辑提交信息推送到远程后不要随意用会影响协作误执行了reset --hard工作区被清空回退前没确认状态立即执行git reflog查看最近的HEAD移动记录找到之前的hash然后git reset --hard 那个hash恢复明明add了文件但push没生效步骤没走完检查是否漏了git commit。push推送的是commit不是add后的暂存状态.gitignore写了规则但文件还是被跟踪规则写错或文件已被跟踪新规则只对未跟踪文件生效已经跟踪的文件需要git rm --cached 文件名取消跟踪后再提交单拎几个问题出来详细说一下。误执行reset --hard是新手最致命的操作再多的理论讲解都不如一句实操建议来得有效任何一次reset --hard之前先看一眼git status确认没有未提交的修改或者先stash一份备胎。我是经历过用reflog救回一整天的成果之后才真正理解备份和谨慎在Git操作里的分量。关于.gitignore很多人把它当成“只要写上就万事大吉”的护身符。实际上.gitignore只对还没纳入Git跟踪的文件生效。如果你的项目里有个文件早就在版本管理里了后来才想到要忽略它直接在.gitignore里加规则根本不生效必须git rm --cached先把文件从索引中移除但保留工作区的物理文件然后再提交才生效。职场里常见的一个场景是开发配置文件local_settings.py被误提交处理方式就是先rm --cached再提交。还有一个我只踩过一次也必须说的坑git pull在默认配置下其实是自动执行fetch和merge两个步骤。如果你的工作区有未提交的改动有的新版本为了安全直接阻止合并有的则是尝试尝试合并。最稳妥的做法是pull之前先commit或stash把工作区整理干净再拉取不要让Git在脏工作区上做合并判断。这个习惯能帮你避免一大半莫名其妙的冲突。最后关于push失败。我遇到最多的情况是本地和远程仓库各自有对方没有的提交直接push会被拒绝。这个时候很多人第一反应是慌其实只要一条git pull --rebase origin 分支名就能解决。rebase跟merge的区别是它会把你本地的提交“搬”到远程提交的后面让历史保持线性多试几次再回头看log你会对Git的设计有更深的体会。9. 我的Git工作流心得说点个人的体会。我先用了很长一段时间的SVN后来才转向Git。刚切换那阵子最不适应的不是命令行而是“怎么会有暂存区这么麻烦的东西”。可当我真正做到了“按逻辑单元临时攒一批改动再提交”之后再也不想回去了。Git的暂存区给我的不是麻烦是掌控感——我能决定每次提交精确包含哪些内容而不是一股脑把所有改动都塞进一个快照里。Git的核心设计思想其实一直都是这八个字“本地操作分布式协作”。你所有的add、commit、branch、reset几乎都在本地完成速度快、离线可用、随时后悔只有push和pull才依赖网络。理解了这八个字面对Git的各种指令就不会无所适从。这套工具学起来说难不难说简单也绝对不简单。但只要你把今天讲的这些基本操作先练熟用一段时间有问题多看帮助文档和reflog你会发现Git真的是一款越用越顺手的工程利器。