我自己刚开始用 Git 的时候其实是被吓到的——满屏的fatal、error网上搜到的命令又各自为政仿佛每篇教程都在教一个不同的 Git。后来带过几波新人又帮同事救过好几次仓库之后我才慢慢摸清楚一件事大多数人在 Git 基本使用上卡住根本不是“记不住命令”的问题而是脑子里没有一个清晰的模型。工作区、暂存区、版本库这三层关系一旦想通后面所有命令都只是在这个模型上做操作而已。这篇文章我就按我带新人时的思路把 git 基本使用从头到尾捋一遍从安装配置、日常提交、分支合并到远程协作、改错恢复再到 LFS、worktree 这类容易出问题的高级话题全程用手头实际操作过的经验说话尽量少说废话。1. 先把环境收拾利索安装、验证与全局配置1.1 不同平台安装 Git 的常见路径Git 的安装本身不难但很多人的第一个坑恰恰出在“装完了却用不了”。先看 Windows直接到官网下载安装包一路 Next 就行。这里有个很现实的提醒——官网下载在国外服务器上国内网络环境有时候会很慢等几分钟没反应就把页面关了去国内镜像站下载对应版本的安装包速度快很多文件内容一模一样。装的时候注意一个选项安装器会让你选“Adjusting your PATH environment”这时候一定要选中间那项“Git from the command line and also from 3rd-party software”选错了或者跳过这一步后面在 PowerShell 里敲git就会提示命令不存在。macOS 上有两条路装 Homebrew 的话就brew install git没装 Homebrew 就用 Xcode Command Line Tools第一次在终端敲git时系统会弹窗引导安装装完一样可用。Linux 用户则是apt install gitDebian/Ubuntu或dnf install gitFedora/RHEL的常规操作。装完之后别急着往下走先验证git --version比如你看到git version 2.40.0.windows.1这种输出说明已经装好。接下来 Windows 用户大概率会遇到热搜里那个经典报错git : 无法将“git”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。这个错误的根因有两个一个是大意装的时候 PATH 没选对二是装好了但当前 PowerShell 是旧进程环境变量还没刷新。我的排查顺序是先关掉终端重新开一个不行就去“系统属性 → 环境变量”里确认C:\Program Files\Git\cmd是否在 PATH 里没有就手动加上。绝大多数人卡在这一步就是这两个原因跟 Git 本身一点关系都没有。1.2 两个必做的全局配置安装完成后的第一件事不是急着建仓库而是配置你的身份。Git 每次提交都会记录提交者的名字和邮箱这两个字段会写进历史里跟你绑一辈子。配置命令是git config --global user.name 你的名字 git config --global user.email 你的邮箱加--global表示写进用户级配置文件Windows 在C:\Users\你的用户名\.gitconfigLinux/macOS 在~/.gitconfig以后这台机器上所有仓库都默认用这个身份。有些教程会让你在项目里再配一次那是局部覆盖一般不需要。配完可以用git config --list检查所有生效的配置顺便看一眼有没有credential.helper这一项。这个话题挺关键很多新手在 push 的时候被反复要求输账号密码输到崩溃就是因为没配凭据助手。Windows 上执行git config --global credential.helper wincredmacOS 就换成osxkeychain配完之后账号密码会被安全地存进系统钥匙串或凭据管理器后续操作不用重复输入这就是“git免密”的第一步。VSCode 里如果一直弹窗让你输 GitHub/Gitee 的账号密码本质也是这套机制没配对。1.3 生成并配置 SSH 密钥高频踩坑点比 HTTPS 更常用的是 SSH 方式连接远程仓库因为它天然免密又更安全。生成密钥的命令ssh-keygen -t ed25519 -C 你的邮箱一路回车到底会在~/.ssh/下生成一对密钥id_ed25519是私钥id_ed25519.pub是公钥。私钥绝对不要泄露给任何人公钥则要填到平台后台。比如 Gitee 用户去“设置 → SSH 公钥”GitHub 用户去“Settings → SSH and GPG keys”把.pub文件里的内容整个复制粘贴进去保存。配完验证一下ssh -T gitgithub.com # 或 ssh -T gitgitee.com看到Hi xxx! Youve successfully authenticated...就说明通了。热搜词里那个“ssh认证失败 git”我排查过很多次归根结底就那么几种原因公钥压根没加到平台项目远程地址用的是 HTTPS 而不是 SSHgit remote -v看一下就能分辨或者生成密钥时设了 passphrase 又记不住导致每次都要输一遍。还有一个不常见但很坑的本机配了多个平台、多个账号~/.ssh/config没写对SSH 默认拿id_ed25519去试试到 GitHub 上碰巧是另一个账号密钥就会报 Permission denied。我建议新手只生成一个密钥、只用于一个平台等真正需要多账号了再研究 config 文件别一上来就把自己绕晕。2. 把“提交”这件事彻底搞懂工作区、暂存区、版本库2.1 初始化仓库的两种姿势Git 基本使用里最核心的概念就是“仓库”。创建仓库有两条路本地从零开始或者从远程拉取。本地从零开始最直白git init敲完这句当前目录就变成了一个 Git 仓库目录下会多出一个隐藏的.git文件夹你的所有版本历史都存在这里面。从远程拉取则是git clone 远程仓库地址这里顺便说一下经常有同事问我“IDEA 创建新项目拉取 Git 怎么操作”其实就是把git clone封装成了图形界面操作——新建项目时选“Get from VCS”填入远程地址后点克隆IDE 帮你把命令执行完了而已。理解了 clone 是干嘛的图形界面上的按钮就只是个快捷键了。2.2 第一次完整提交的操作链初始化好仓库之后第一步永远是看状态git status它会告诉你哪些文件被改了、哪些文件还没被跟踪、当前在哪个分支上。新手一定要养成“操作前先 status”的习惯这能帮你少犯一半错误。接着建立第一个提交完整链路是git add . # 把所有改动加入暂存区 git commit -m feat: 初始化项目结构这里请你务必理解git add到底在干嘛。Git 把工作区想成三个层你正在编辑的文件所在的地方叫工作区git add把文件的快照放进了暂存区也叫索引git commit才真正把暂存区的内容固化成一个版本提交存进版本库。形象点说add是把要打包的货物放进快递盒commit是封箱贴单。你随时可以git add一部分文件、git commit一部分文件两者之间可以反复调整。提交完了用git log看历史git log --oneline --graph--oneline只显示一行摘要--graph用线把分支走向画出来这是我日常用的最多的查看命令。另外提一句提交信息怎么写动词开头、点明改动意图feat、fix、docs、refactor这类前缀约定俗成地表明改动类型提交历史会因此变得清晰可追溯。我在团队里最怕看到的就是git commit -m 修改五十条提交全叫“修改”回滚的时候根本不知道哪个是哪个。2.3 “fatal: not a git repository”到底是怎么回事这个报错在热搜里出现频率极高完整版本是fatal: not a git repository (or any of the parent directories): .git新手第一次看到基本都会懵。原理其实很简单Git 在找不到.git目录时会沿着当前目录往上级目录一层层找一直找到根目录都找不到就报这个错。也就是说你当前所在的目录根本不在任何一个 Git 仓库的管理范围内。最常见的场景有两种一种是你在git clone之后直接进了子目录但那个子目录是仓库里的普通文件夹不是你 clone 下来的根目录另一种是密码输错导致 clone 失败以为克隆成功了其实半途而废。排查办法也很简单先pwd确认自己在哪再ls -a看当前目录有没有.git没有就往上级目录走。记住一句话以后看到这个报错先问自己一句“我找对仓库根目录了吗”八成问题就出在这。2.4 .gitignore为什么必须学会忽略文件新手最容易忽略的配置文件就是.gitignore。它是干什么用的告诉 Git “这些文件我不想纳入版本管理”。很多人第一次把项目推到远程仓库发现node_modules这种几百兆的依赖目录也被传上去了这就是没配.gitignore的后果。正确做法是在项目根目录建一个.gitignore文件# 依赖目录 node_modules/ target/ venv/ # 系统与编辑器文件 .DS_Store .idea/ *.iml # 日志与临时文件 *.log temp/每种语言生态都有自己的模板Java 项目关注target/Python 项目关注venv/和__pycache__/Node 项目里node_modules/是头号大敌。有一个新手常犯的错项目已经跟踪了一堆文件才想起来写.gitignore写完发现不生效。原因在于 Git 只对未被跟踪的文件应用忽略规则已经进暂存区的文件不受影响。这时候要先把它们移出跟踪再提交git rm -r --cached node_modules git commit -m chore: 停止跟踪node_modules--cached的意思是只从 Git 的索引里移除不删你磁盘上的文件这个参数很关键少了它你的本地依赖目录会被直接干掉。3. 分支不是用来“备份”的日常分支流转与合并3.1 从 SVN 迁过来的人最容易栽在分支上带过团队的人一定听过这种话“我建了个分支怕代码丢了所以一直没合并。”这话十有八九是从 SVN 或者更早的集中式版本控制系统转过来的习惯。Git 和 SVN 有个本质区别SVN 是集中式仓库分支目录是物理复制的副本建多了服务器压力大Git 的分支只是一个指向特定提交的指针创建分支的成本低到几乎为零。所以 Git 世界里鼓励“多开分支、大胆操作、频繁合并”分支不是用来备份的保险箱而是隔离试验区的工具。团队里常见的工作流是这样的main或master分支永远保持可发布状态开发新功能时从main拉出一个feature/xxx分支写完合并回去。这个流程既保证了主干稳定又能让多个需求并行推进。3.2 创建、切换、合并的标准流程完整走一遍就是git checkout -b feature/login # 基于当前分支创建并切换 # 或者新版写法 git switch -c feature/logincheckout -b这个组合命令我用了很多年它等价于git branch feature/login加git checkout feature/login两步连招。新版 Git 推荐git switch语义更清晰但老命令到处都能用看你习惯。在 feature 分支上提交几个 commit 之后切回主分支合并git switch main git merge feature/login合并分两种情形。如果主分支在你拉出 feature 之后一直没动过Git 做的是fast-forward合并只是把main指针往前挪到 feature 的顶端历史是一条直线干净利落。如果主分支也有新提交Git 就会创建一次真正的merge commit把两条线交汇在一起。用git log --oneline --graph看后者会有一个像“Y”字一样的交汇点这是非常正常的。关于合并工具我提一句merge 和 rebase 的选择是团队级决策不是个人喜好。merge保留真实的合并历史操作简单rebase让历史看起来是一条直线但会改写提交用不好就是灾难。新手阶段老老实实merge等能熟练看懂提交历史了再考虑 rebase这是我带新人时定的规矩。3.3 冲突解决的完整排查链路冲突是 Git 基本使用里最劝退人的一个场景但其实它没那么可怕。冲突的本质是你和你同事改了同一文件的同一块区域Git 不知道该听谁的。比如两个人都在config.js里改了各自的 API 地址但改的是同一行合并时 Git 会停下来给出类似这样的标记 HEAD const apiUrl http://localhost:8080; const apiUrl http://test.example.com; feature/login这表示HEAD当前分支也就是 main里是 8080被合并的 feature 分支里是 test.example.com。解决冲突的方式很直接编辑文件把你要保留的代码留下来把标记行全部删掉。比如最终决议是用测试环境的地址那就保留const apiUrl http://test.example.com;然后git add config.js git commit -m merge: 解决config.js冲突统一使用测试环境地址注意解决冲突后一定不要直接 commit要先 add。因为我前面说过commit 只固化暂存区的内容你不 add 等于没告诉 Git“这个文件我已经处理好了”。我的经验是冲突能不能少取决于三分——一工作开始前先git pull把远程的最新代码拉下来二提交粒度要小每次提交改动量小冲突面就小三解决冲突时用 IDE 或 VSCode 的图形化比较工具。VSCode 里打开冲突文件会在冲突区域显示 “Accept Current Change” 和 “Accept Incoming Change” 的按钮一个点选一个手动微调效率比在黑终端里裸写快太多了。我见过太多人在编辑器里手动删标记删到心态崩掉其实图形化工具就是为这个场景设计的。4. 和远程仓库打交道push、pull、fetch 与凭据管理4.1 “先 pull 再 push”这条纪律还是有用的既然是 Git “基本使用”远程协作一定绕不开。最朴素的一套日常动线是git pull # 先拉下远程的最新改动 git push # 再推自己的改动上去git pull不是一个原子命令它等于git fetch把远程仓库的最新提交下载下来加上git merge把下载下来的内容合并进本地分支。理解了这层拆解你就明白为什么“先 pull 再 push”是有道理的——别人在你上次 pull 之后推了新代码你不拉下来直接 push远程仓库会拒绝你的提交提示你本地落后于远程non-fast-forward。先 pull 相当于跟同事把话对齐了再 push 才不会互相覆盖。我自己的习惯是git pull用得多但心里清楚它做的是 fetchmerge。如果你想强调“只要拉取不要合并”用git fetch看完差异再决定下一步。在团队协作里我更推荐的做法是git pull --rebase替代默认的 merge这样可以把本地提交“挪”到远程最新提交之后历史看着像一条直线后续代码审查更舒服。不过这条建议要建立在团队大家都理解 rebase 的基础上否则宁可按默认设置走。4.2 GitHub/Gitee 的账号密码与免密配置远程仓库用 HTTPS 地址连接时push 会让你输账号和密码。这个“密码”在很多平台上早就不是登录密码了而是Personal Access Token个人访问令牌。比如你在 GitHub 上提交时密码框里要粘贴的不是账号密码而是在“Settings → Developer settings”里生成的 token。Gitee 也一样在“安全设置 → 私人令牌”里生成。很多新人卡在这里就是因为傻傻地输登录密码输一百遍都过不去。想要免密两条路一是前面说的 SSH 密钥方式配置好后不用输任何密码二是 HTTPS 方式配合credential.helper把凭据存进系统。如果你已经配置过密码后来想清除掉比如换账号了可以这么操作git config --global --unset credential.helperWindows 系统还要去“控制面板 → 用户账户 → 凭据管理器 → Windows 凭据”里手动删除对应条目的记录不然光删配置不删凭据系统还是会自动填旧账号密码。这个细节坑过我好几次删完配置以为干净了一 push 发现用的还是旧身份。4.3 分支追踪关系与“diverged”的常见处理远程仓库克隆下来后本地会有一个叫main的分支它追踪track着远程的origin/main。每次git status显示的“您的分支与‘origin/main’一致/领先/落后”就是在汇报这种追踪关系。一旦你本地领先后又落后Git 会说“您的分支和‘origin/main’ 已经分叉”这就是很多人慌张的那个状态。分叉并不可怕它只是说两边都有对方没有的提交。处理方式就是前面说的git pull把双方合到一起或者git pull --rebase把本地提交挪到最新之上。真正要担心的是 push 时被拒绝那通常意味着你没 pull 就 push或者 pull 过了但产生了冲突没有解决。按 3.3 节的冲突解决流程走一遍就好不需要重置远程仓库这种大杀器。这里还要提醒一点推错分支怎么办。比如你在feature/a上工作一失手把它推到了origin/main。发现得早的话用git push origin --delete删除远程分支再用git push origin HEAD:feature/a推回正确分支如果已经有人基于这个错误分支做了操作那就需要和团队沟通删除操作会破坏其他人的历史。我的经验是平时多养成git branch --show-current看一眼当前分支的习惯推错分支的概率会低很多。5. 改错了也别慌amend、reset、revert 与 stash5.1 git commit --amend 怎么用、什么时候用热搜里有个高频问题git commit --amend怎么用。这个命令的作用是修改最后一次提交。两种典型场景发现上次提交漏了一个文件或者提交信息写错了。用法git add 漏掉的文件 git commit --amend -m 修正后的提交信息执行完之后原本的提交会被一个新提交替换提交内容hash发生变化。这里有一条铁律只有还没推送到远程的提交才能 amend。如果你已经 push 到共享分支再用 amend 改写历史就会导致其他人的本地仓库和远程不一致他们下次 pull 会报一堆奇怪错误。我的建议是提交信息写错了还没推送改没问题已经推送了别改老老实实加一个新的提交来说明修正。5.2 reset 与 revert 一字之差方向完全相反“改错了想回去”是最高频的需求之一。Git 给了一个精准的答案还没推的提交用 reset已经推了的用 revert。git reset会把当前分支的 HEAD 指针往后退。它有三个模式表格对比一下模式影响范围典型用途--soft只移动 HEAD暂存区和工作区都不动想重新组织多个提交时--mixed默认移动 HEAD暂存区重置工作区不变把误提交的文件退回工作区重新 add--hard移动 HEAD暂存区和工作区全部重置彻底抛弃本地改动回到指定提交举两个例子git reset --soft HEAD~1 # 撤销提交但改动还在 git reset --hard HEAD~1 # 撤销提交改动也直接扔掉HEAD~1表示当前提交的上一个提交。这里我必须把警告写清楚git reset --hard是危险操作它会把工作区未提交的改动一并清空这些改动无法通过 Git 恢复除非编辑器有本地历史缓存。我见过一个真实事故同事本想reset --soft重新整理提交结果手滑打了--hard一下午的代码全没了。所以执行--hard之前一定先git status确认没有未提交的改动或者用git stash先把改动保出来。git revert的机制完全不同它不会改写历史而是生成一个新的提交这个新提交的内容和你要撤销的那个提交是相反的操作。git revert HEAD它会打开编辑器让你补一条提交信息默认写的是“Revert xxx”保存后历史里就多了一条反向提交记录。这样做的好处是历史完整可追溯、不影响别人的克隆所以只要提交已经推送共用就必须走这条路。很多人刚接触时觉得 revert 不如 reset 干净但“干净”不是目的“安全协作”才是。5.3 git stash把手头未提交的工作存起来还有一种高频场景正在feature/a上写代码写到一半突然main上有个 bug 要紧急修复。你不能直接切换分支因为未提交的改动会跟着你跑甚至可能和新分支代码冲突。这时候git stash就是为你准备的git stash # 把当前未提交的改动保存到临时栈工作区变干净 git switch main # 安心切分支 git pull # 拉最新代码 # ...修bug、提交... git switch feature/a git stash pop # 把之前存的改动恢复到工作区git stash list可以查看所有暂存记录git stash pop是恢复最后一次暂存并删除记录。注意 stash 是“栈”结构多个 stash 会叠在一起恢复时一般用git stash pop弹最上面那个。我见过有人存了五六条 stash 忘了恢复过了几个月整理时发现一堆 “stash{2}” 不知道是什么最后只能一个个git stash show查看内容。小建议stash 的提交信息留清楚别随手一存就丢脑后。6. 大型文件与多工作区两个高频但易出错的高级话题6.1 git lfs大文件管理的适用范围与常规用法项目越来越大有人往仓库里塞资源文件、模型文件、设计稿结果所有同事 clone 的时候都被几百 MB 的历史拖慢甚至git lfs clone卡住半天没反应。这就是 Git LFS 要解决的事。LFS 的全称是 Large File Storage核心思路是大文件本体不直接进 Git 历史Git 里只存一个几 KB 的指针文件大文件本体放到远程的 LFS 存储服务里。大家 clone 时拉到的都是小指针需要用到具体文件时再由 LFS 按需下载。基本用法很简单git lfs install # 初始化 LFS每个仓库第一次用时要执行 git lfs track *.zip # 声明哪些文件走 LFS 管理 git add .gitattributes # 跟踪规则写在 .gitattributes 里必须提交 git add 你的大文件 git commit -m feat: 添加设计资源 git pushgit lfs track会生成一个.gitattributes文件把它一并提交这样其他人 clone 下来才知道这个仓库用了 LFS。如果你的仓库已经有大量历史也走入了 Git 本体想迁移到 LFS 需要git lfs migrate这种高级命令操作不当会改写历史建议在专业指导下进行这里不展开。关于“clone 卡住”这个热搜词我排查过的常见原因有三个一是这个仓库确实用了 LFS 且历史里大文件很多首次 clone 要拉取全部 LFS 对象二是网络状态不佳导致 LFS 下载大文件时超时三是.gitattributes没有提交导致 clone 时拉取的是 LFS 指针内容而非真实文件之后打开文件才发现是几个 KB 的空壳。我的建议是对只需要代码的开发环境可以不装 LFS client 直接 clone代码正常真正需要大文件的人在本地装好 Git LFS再git lfs pull按需拉取。6.2 git worktree基于同一仓库“开多个工作目录”日常开发中另一个高频痛点需求并行时频繁切换分支每次切完都得重新在编辑器里等索引刷新或者两个分支依赖不同的依赖包版本切换后还得重新npm install/mvn package。git worktree专门解决这个问题——它允许你从同一个仓库中在多个目录同时检出不同的分支。基本用法git worktree add ../project-feature-a feature/a这条命令会在你项目外层的../project-feature-a目录创建一个工作区里面检出的就是feature/a分支。然后你可以开两个终端窗口一个在main分支修 bug一个在 feature 分支写新功能互不干扰两边都能随时提交。用完后清理git worktree remove ../project-feature-a git worktree list # 查看当前所有 worktree注意一个容易误解的点worktree 不是分支副本它和主仓库共享同一份.git历史数据只是工作目录不同。所以它在主仓库目录下的.git其实是个文本文件内容是指向主仓库.git目录的路径这是正常现象别以为是仓库坏了。用git worktree remove时如果该 worktree 还有未提交的改动或未合并的分支Git 会拒绝需要你自己先处理干净再删。6.3 .git 目录泄露的防范最后聊一个跟 Git 基本使用相关、但容易被忽略的安全话题——.git目录泄露。.git目录是整个仓库的核心里面存了所有提交历史、配置、甚至可能包含敏感信息比如某些人把密码文件提交进去了。如果你把项目打包上传到公开环境或者把整个目录直接扔进网盘分享等于把所有历史代码和潜在敏感信息都暴露了出去。更常见的一种危险是网站部署时把静态服务器根目录设在了项目根路径下导致外部可以直接访问你的域名/.git/下的文件这就等于把源码仓库公开了。防范建议很简单部署时不要直接把项目根目录暴露给 Web 服务把静态文件或发布产物单独放到部署目录压缩源码包上传前先检查压缩包里是否包含.git目录包含就去掉不要把.gitconfig、.ssh这类文件提交进仓库或随代码打包。这些小习惯不需要你成为安全专家但能在很大程度上避免仓库信息泄露。关于 Git 基本使用我最后再分享一个小习惯每次觉得“这条命令该记下来了”就在自己的笔记里记一句用途不准复制粘贴大段文档只准用自己的话写一行。我带了这么多年新人发现凡是能把add、commit、pull、merge、reset、revert这六个操作的不同理解写成一句话的人后续学 Git 都特别快。这门工具的本质就是一人一套模型模型通了命令自然就不慌了。