资讯动态

Git 从入门到实战:掌握暂存区、分支与远程协作

发布时间:2026/10/9 3:22:44 来源:尧图企业网站定制
1. 为什么很多人学了 Git 还是不敢用先纠正心智模型带过不少新人也处理过不少“上来就背命令”的求助我发现一个挺反直觉的现象大多数人学不会 Git不是因为命令太多记不住而是从一开始就把 Git 理解错了。Git 的根本属性和网盘完全不是一回事。网盘是“我把文件传上去同步给别人”本质是中心化的“上传—下载”。Git 是分布式的版本控制工具它的核心动作不是“上传”而是“在本地给项目拍快照”。你 push 到远程仓库只是把本地已经拍好的快照同步一份出去而已。这个逻辑如果没扭转过来后面所有命令都会越学越迷糊。我建议所有初学者在敲第一条命令之前先花十分钟建立一个最简单的三层模型工作区Working Directory就是你电脑里能看到的那些文件随便改不影响任何历史记录。暂存区Staging Area / Index可以理解成“候车区”你手动决定哪些改动要搭上下一班车。本地仓库Local Repository车票已验、正式入档每次提交就是一个不可变的历史快照。在这三层之外才是远程仓库Remote也就是 GitHub、Gitee 或者公司内网 GitLab。远程仓库只是本地仓库的一个备份和协作枢纽它不负责“保存你的文件”这个最核心的职责——你断网的时候本地仓库已经是完整的历史记录。对应的一个文件在 Git 眼里有四种状态未跟踪untracked、已修改modified、已暂存staged、已提交committed。初学者最常犯的错误就是跳过了暂存区以为改了文件就等于“保存”了。其实改完文件之后Git 只知道“有文件变了”但你的修改还没有真正进入版本历史。你必须用git add把文件送进暂存区再用git commit完成快照。这中间的隔离是有意设计不是为了折腾你而是为了让你能按逻辑分批提交——这一点后面详细说。这一篇我不会给你列一长串“常用命令大全”而是按一个真实的项目推进顺序从安装配置、日常提交、分支合并、远程协作到事故救援把“为什么这么做”也一起讲清楚。你跟着走一遍大概率会比背二十条命令有用得多。2. 环境搭建里的坑安装、全局配置和第一条命令2.1 三个平台怎么装Windows 上最容易踩的暗坑安装本身并不复杂。Windows 上最标准的做法是去 Git 官网下载 Git for Windows 安装包一路下一步。但有几个选项容易被忽略装完才后悔默认编辑器安装时会让你选 Git 默认使用的文本编辑器默认是 Vim。对从没用过 Vim 的人来说某次提交时想改一下注释结果卡在:wq里出不来体验非常痛苦。建议直接在这里选你熟悉的编辑器比如 VS Code 或 Notepad。PATH 环境变量建议选“Git from the command line and also from 3rd-party software”这样以后在 PowerShell 或 CMD 里也能直接敲git不会出现“命令找不到”。换行符转换这一步最容易坑人。Windows 下 Git 默认会帮你把文件里的 LF 转成 CRLF看起来是贴心实际经常引发“我什么都没改为什么 diff 一片飘红”的怪现象。选择Checkout as-is, commit as-is按原样检出、按原样提交通常更省心团队里统一换行策略之后基本不会再出幺蛾子。macOS 上最简单的方式是brew install gitLinux 发行版一般用apt install git或yum install git。装完可以用git --version验证是否成功。2.2 不配置身份信息连一次提交都做不了Git 的每次提交都会记录作者信息所以装完 Git 之后第一件事不是建仓库而是配置全局身份git config --global user.name 你的名字 git config --global user.email 你的邮箱这两个配置会写进用户主目录下的~/.gitconfig文件里。注意 email 很关键因为 GitHub 或 Gitee 是靠邮箱把本地提交关联到你的账号头像的。我见过有人乱填邮箱导致账号一直不显示绿格子排查半天才发现是历史提交的用户邮箱和账号不匹配。顺手建议配置几条别名日常操作能快不少git config --global alias.st status git config --global alias.co checkout git config --global alias.ci commit git config --global alias.br branch如果你想检查当前所有配置用git config --list就能看到。2.3 第一个仓库git init 之后到底发生了什么在项目目录里执行git initGit 会创建一个隐藏的.git文件夹。这个文件夹里装着所有历史快照、分支指针、配置信息。很多人不理解这一点直接把.git删了或者把它上传到网盘同步回过神来发现整个项目的版本历史全没了——后悔都来不及。另外提醒一句.git目录的安全性值得注意。网站上线时如果把这个目录暴露在公网别人可能通过特定路径下载到你的提交历史源码和配置信息就全泄露了。针对这类泄露风险的防御我放在最后一章讲但大家从第一天起就要养成习惯不要把.git目录当作普通文件处理也不要在提交里写入任何密码、令牌、密钥。到这一步一个可以正常使用的 Git 环境就算搭好了。接下来进入最核心的日常循环。3. 每天都会用到的循环status、add、commit、log3.1 暂存区为什么值得你多“折腾”一步第一次用 Git 的人几乎都会问一句我改完文件直接 commit 不行吗为什么非要先 add这个设计其实非常实用。暂存区的本质是“提交内容的选择器”。它允许你把多个文件的改动分成若干逻辑单元各自独立提交。比如你修了一个 Bug顺手又改了一个无关的配置文件这两种改动混在一次提交里会很难追踪。有了暂存区你可以把 Bug 修复相关的文件先git add提交一次再把配置文件单独提交一次。历史记录干干净净每一条提交在做什么一目了然。实操里我见过最舒服的开发者工作流是这样的git status看一下当前工作区状态git diff确认改动内容是不是符合预期按逻辑分批次git add file需要的话用git diff --cached再看一遍将要提交的内容git commit -m feat: 添加用户注册功能循环。用电影拍摄来类比工作区是片场所有素材堆在那里暂存区是你选的“今日可用镜头”git commit就是剪辑师把选好的镜头烧录进成片。你当然可以把整个片场全烧录进去但那样剪出来的片子没人看得懂。3.2 一个完整的提交长什么样假设你在项目里新增了一个README.md第一次提交就按这个流程走echo # My Project README.md git status这时候README.md会出现在 “Untracked files” 列表里表示 Git 看见了它但从未跟踪过。接着执行git add README.md git status文件移动到了 “Changes to be committed”绿色显示说明已经进入暂存区。最后git commit -m docs: 初始化项目文档git log --oneline就能看到一条简短的提交记录a1b2c3d docs: 初始化项目文档注意那一串a1b2c3d这是 Git 用内容计算出来的 SHA-1 哈希。它不止是个编号还是这条提交在历史中的唯一地址后面做回滚、修补、cherry-pick 全都会用到它。3.3 提交信息不能只会写 update很多人提交信息就是两个字update。一两个月后回看历史全是 update、update、update等于没写。团队协作时更麻烦同事翻你的提交记录根本不知道你动了什么。我自己习惯用这种格式第一行类型 简述控制在 50 个字符左右。比如fix: 修复登录接口空指针异常空一行再加详细描述说明改动背景、影响范围、测试情况。常用的类型前缀包括feat新功能、fix修 Bug、docs文档、refactor重构、test测试。这套写法不是唯一标准但比清一色的 update 有价值得多。如果提交之后发现信息写错了或者漏了一个文件可以用git commit --amend修补最后一次提交。它会把暂存区里的内容合并进上一条提交并弹出编辑器让你修改注释。注意一个原则--amend只适合修补还没推送出去的本地提交。如果这个提交已经 push 到远程、并且别人可能已经拉取过了再去 amend 就会造成历史分叉处理起来非常麻烦。3.4 .gitignore 过滤文件为什么“没作用”这是热搜词里出现频率很高的一个问题。很多人建好了.gitignore把node_modules、target、*.log写了进去结果发现这些文件还是出现在git status里甚至被提交上去了。原因很简单.gitignore只对“尚未被 Git 跟踪的文件”生效。如果某个文件之前已经被git add或git commit跟踪了那么它就不会再理会.gitignore。你把规则加进忽略清单它的状态依然是 tracked。正确的处理办法是把这些文件从 Git 的跟踪列表里移除但保留本地文件git rm -r --cached node_modules git commit -m chore: 停止跟踪 node_modules--cached的意思是从暂存区/索引里删掉跟踪关系硬盘上的实际文件不受影响。提交这次变更之后配合已有的.gitignore规则这个目录才会真正被忽略。一份实用的.gitignore至少应该包含编译产物、依赖目录、日志、临时文件、IDE 个人配置和本地环境变量文件。网上有现成的模板库比如 GitHub 的 gitignore 仓库按语言类型直接抄就行。4. 分支、合并和那个经典的“写错分支”问题4.1 分支为什么特别便宜所以别怕建分支Git 的分支本质上只是一个指向某个提交的指针。新建一个分支不是什么重量级操作不复制文件不占多少空间几十个分支同时存在毫无压力。这就是为什么绝大多数团队都鼓励“开分支干活稳定后再合回主干”。日常基本操作git branch dev # 创建 dev 分支但还在当前分支 git switch dev # 切换到 dev 分支 git switch -c feature/login # 直接创建并切换注意我用的是git switch这是 Git 2.23 之后推荐的新命令语义比git checkout更清晰。老教程里大量使用git checkout -b现在依然能用但新项目建议优先用switch。每次切换分支Git 会同步修改工作区的文件内容。所以有两个原则必须记住切换分支前把当前改动提交干净或者用git stash临时收起来否则要么切不过去要么把没提交的改动带到别的分支上造成混乱。4.2 merge 和 rebase 不是一回事合并分支有两种主流方式git merge和git rebase。两者目标一致把一个分支的改动并入另一个分支但历史形态完全不同。git merge会保留两条分支各自的“时间线”再增加一个合并提交把它们汇合。优点是完整记录真实发生过什么适合公共分支的合并缺点是一个频繁 merge 的分支历史里会多出很多“Merge branch ...”的节点。git rebase则是把你当前分支的提交“摘下来”重新铺到目标分支的顶端。历史会呈现一条直线读起来很清爽。但它重写了提交顺序和基点所以绝不应该对已经推送到远程并且大家共用的分支执行 rebase。我的个人习惯是本地开发时用 rebase 让历史保持整洁往公共分支合并时用 merge 保证真实协作轨迹不被篡改。这没有绝对标准关键是团队定好规矩、保持一致。操作历史形态是否会改写提交公共分支上用merge分叉后汇合新增合并提交不改旧提交安全rebase线性重放会生成新的提交对象危险4.3 冲突是怎么来的又该怎么解当两个分支修改了同一个文件的同一段代码Git 合并时不知道该听谁的就会报告冲突。这不是故障而是它拒绝替你瞎猜。解决步骤很简单git merge feature/a提示冲突时用git status查看哪些文件出现了 “both modified”打开这些文件搜索、、标记手动保留需要的代码删掉冲突标记git add相关文件再次执行git commit完成合并。想避免冲突最好的办法不是少开分支而是把分支生命周期缩短、频繁把主干更新拉回自己的分支里。两个人都越过越久冲突概率就会急剧上升。用完 IDE 的图形化冲突解决工具也行但底层逻辑还是上面这套手动流程会了你才能看懂工具在干什么。4.4 我在 master 上写了一堆代码想挪到 dev 分支上这是非常典型的操作事故。解决方案取决于你“有没有把这些改动提交成 commit”。情况一改动还没 commit只是体现在工作区里。直接切换到 dev 分支这些改动会跟着你走——前提是切换过程中没产生文件冲突。所以理论上只需要git switch dev如果切换时出现“local changes would be overwritten”的提示就用git stash把改动暂存切换到 dev 后再git stash pop恢复。情况二你已经在 master 上提交了好几个 commit现在想把这几个提交挪到 dev 上。推荐用git cherry-pickgit switch dev git cherry-pick a1b2c3d这条命令会把指定的提交“摘”到当前分支上生成一个新的提交。如果涉及多个连续提交可以先在 master 上查看它们的哈希范围或者用交互式 rebase 的--onto参数做整段移动。cherry-pick的关键作用是只拿走某几个提交不把整个 master 的后续历史搬过来。这里顺便回应一个搜出来的疑问“git pick 和 fetch 有什么区别”。搜到的“pick”十有八九指的是cherry-pick它和 fetch 是两个维度的东西。cherry-pick是把某个提交的内容复制到当前分支fetch是把远程仓库的最新提交拉取到本地但不动你的工作区和不自动合并。两者解决的问题完全不同你会搜到一起大概率是看了某篇把名词缩写写混的文章。5. 远程协作remote、SSH 认证和推送那些事5.1 关联远程仓库之前先搞清楚 fetch、pull、push本地仓库要跟远程仓库建立联系用git remote add origin 仓库地址。地址有两种形式HTTPShttps://github.com/user/repo.gitSSHgitgithub.com:user/repo.git用git remote -v可以查看当前关联了哪些远程地址。三个涉及远程的命令语义必须分清楚git fetch从远程把最新历史下载到本地但不影响你的工作区也不合并任何分支。它是纯同步动作无聊但安全。git pull等于git fetchgit merge把远程分支拉下来并和当前分支合并。git push把本地已经提交的 commit 推送到远程。很多新人习惯有更新就git pull但遇到本地也改了同一个文件时pull 会直接触发合并可能出现意外冲突。我更推荐养成先git fetch、看一眼远程变化再决定是merge还是rebase的习惯。这一步多花两分钟能省很多次抓狂。5.2 SSH 密钥配置和“认证失败”的完整排查思路SSH 认证失败尤其是Permission denied (publickey)几乎每个用 Git 的人都遇到过。排查思路其实是固定的。如果用的是 GitHub 或 Gitee流程是这样生成密钥对ssh-keygen -t ed25519 -C your_emailexample.com一路回车会在~/.ssh/下生成id_ed25519私钥和id_ed25519.pub公钥。把公钥内容加到代码托管平台的 SSH Keys 管理页。cat ~/.ssh/id_ed25519.pub复制输出内容即可不是把私钥给别人私钥永远留在本机。测试连接ssh -T gitgithub.com返回成功提示后再把远程地址改成 SSH 形式。如果依然失败按下面这几个原因依次排查现象最可能的根因Permission denied (publickey)公钥没添加到平台或添加的不是这一台机器的公钥密钥文件权限过宽~/.ssh和私钥文件权限需要收窄Windows 下尤其常见ssh: connect to host ... port 22: Connection timed out本机网络环境对 22 端口不友好考虑改用 SSH over HTTPS 端口Agent refused operationssh-agent 没加载密钥执行ssh-add ~/.ssh/id_ed25519最后一个常见场景是网络环境限制导致ssh: connect to host github.com port 22连不上。GitHub 官方支持用 443 端口来做 SSH 连接我试过比较稳定。在~/.ssh/config里加一段即可Host github.com Hostname ssh.github.com Port 443 User git改完再ssh -T gitgithub.com验证。如果还是不通那就换 HTTPS remote配合凭据管理器免密推送这也是多数人实际在用的方案。5.3 HTTPS 免密方案从记住密码到 Token不爱用 SSH 的人也可以彻底告别每次推送都要输账号密码。Git for Windows 内置了凭据管理器第一次输入账号密码后会自动缓存。但更通用的做法是使用访问令牌以 Gitee 或 GitHub 为例在账号设置里生成一个有repo权限的 Personal Access Token然后把它当成密码使用。令牌在记忆里就是一串随机字符泄露了也能随时吊销不再影响账号密码。需要特别提醒的是令牌不要提交到代码仓库里这是原则性的问题。如果想要长期免密执行一次git config --global credential.helper store这个方案会把明文凭据存在本机安全要求高的环境不建议开。我更推荐用系统的凭据管理器也就是 Git for Windows 默认的manager-core它存储在系统凭据库而不是纯文本文件里。5.4 推送大文件失败不是 Git 自己的问题Git 的设计目标是管理代码文本不是管理二进制大文件。把几十上百 MB 的安装包、数据集、视频直接提交进仓库几乎必然遇到推送失败或者仓库体积膨胀到难以克隆。当提示类似error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413或者fatal: the remote end hung up unexpectedly时多数是因为推送的单个对象过大HTTP POST 缓冲区或者服务端单文件限制被触发。两个应急思路提高单次推送的缓冲区上限git config --global http.postBuffer 524288000检查是不是有不该跟踪的大文件混进来了。先用git ls-files列出所有被跟踪文件按体积排个序把大文件从历史里剔除。核心建议还是别让 Git 承担文件存储库的职责。大文件要用 Git LFSLarge File Storage来管或者干脆放到对象存储、网盘里仓库里只留使用说明和下载链接。这个认知早一点建立能避免很多折腾。5.5 想用集成开发环境里的 Git 面板搜“idea 创建新项目拉取 git”说的是在 IDE 里通过 “Get from VCS” 克隆远程仓库或者右键菜单的 Git 功能拉取更新、合并分支。IDE 图形界面只是把命令包装成了按钮理解了前面这些概念你在界面上看到的一行行菜单就不会再觉得陌生。比如 “Update Project” 对应的是pullrebase的策略选项“Cherry-Pick” 在日志面板里直接选提交右键就能操作。图形化工具负责点击命令行负责兜底两者结合是效率最高的状态。6. 出事了别慌回滚、子模块和那些奇怪的报错6.1 revert 和 reset救急的时候选哪个出了错想撤销首先分清两件事是想“抹掉历史”还是想“追加一个反向提交”。git reset是移动当前分支指针假装某些提交从没发生过。它可以用--soft、--mixed、--hard控制重置的深度比如git reset --hard HEAD~2会直接丢弃最近两个提交工作区状态同步回退。这是本地救急利器但一旦提交已经推送到远程reset 会导致本地历史和远程不一致再 push 就会被我拒绝需要强推覆盖远程历史——非常危险尤其多人协作时。git revert则是生成一个新的提交这个提交的内容是“把之前某个提交的改动反向撤销”。历史完整保留了我知道我犯过错我又用一个新提交把错误修正了。这种操作推送到远程毫无压力也不会影响别人。命令是否改写历史适用场景推送后是否安全git reset --hard是本地提交写错了想彻底抹掉不安全git revert否提交已推送想安全撤销安全我个人的守则很简单只要提交还没离开本地随便 reset只要提交已经上了远程就老老实实用 revert。还有一个压箱底的命令是git reflog。它记录了你本地所有分支指针的变动历史即使你误用了 reset 把提交弄丢了只要 reflog 里还有记录就能找回来。这个命令是真正的“后悔药”建议你出事时第一个想到的就是它。6.2 submodule 什么时候用什么时候别碰git submodule允许你在一个仓库里引用另一个仓库的特定提交常用于公共组件、多仓库联调的场景。添加方式git submodule add 仓库地址 path/to/submodule克隆包含子模块的仓库时需要加--recurse-submodules参数拉取子模块更新也要单独git submodule update。说实话我对 submodule 的态度是能不用就不用。它的版本一致性问题会让团队的入门成本翻倍经常出现“我明明更新了子模块为什么别人看到的是旧版本”的困惑。如果只是为了复用公共代码优先考虑包管理器或者 monorepo 结构。在你对 Git 已经比较熟练之前不建议引入 submodule 增加心智负担。6.3 那些“看着像闹鬼”的报错“git open /dev/null or dup failed: no such file or directory”这个报错我遇到过多半发生在 Windows 环境下的 Git Bash触发点经常是某些命令需要重定向标准输入输出但进程环境里的/dev/null不可用。常见解法是重启 Git Bash 或 Windows 终端或者把命令放到 PowerShell 里执行。如果频繁出现检查有没有老旧的 Git 版本升级到新版基本能解决。“fatal: refusing to merge unrelated histories”这是因为两个仓库没有共同的历史起点最常见于本地仓库已经 init 过且提交过又去git pull或者关联了一个全新的远程仓库。解决方案是git pull origin main --allow-unrelated-histories这条命令强制合并两段无关历史。执行前想清楚你真的需要保留两边的全部提交吗有时不如删掉本地重新克隆更干净。“LF will be replaced by CRLF”这提醒就是前面安装篇说的换行符问题。统一团队规范后在.gitattributes里显式声明各类型文件的换行符策略比如* textauto *.sh text eollf *.bat text eolcrlf配置提交后这类提示会明显减少。6.4 从防御角度聊一下 .git 目录泄露前面提过.git目录一旦被公网访问整个版本历史都会暴露等于把源码送到别人面前。从运维的角度防御手段是在 Nginx 或 Apache 配置里禁止访问.git路径。Nginx 下可以加一条location ~ /\.git { deny all; }这类问题经常出现在静态站点部署时把构建输出目录直接暴露出去、忘了过滤点开头目录。检查一下自己的线上配置比事后发现泄露再补救要划算得多。Git 本身还支持设置在 Git 仓库里开启extensions.worktreeConfig之类的细粒度控制但最管用的还是“别把敏感目录暴露给外部”这条底线。一点个人的结束语Git 这个工具真正天天用到的命令二三十条顶天了。我带过的新人里凡是先背命令再上手项目的基本两周后就忘得差不多凡是拿着自己真实项目边做边查、反复踩坑的反而记得很牢。所以我最后想分享的是我的一个习惯每天下班前一定把当天的改动整理成清晰的提交出差或者换电脑前一定把本地分支推到远程备份。长期坚持下来你的历史记录就是一份精确到“我哪天做了什么改动以及为什么改”的工作日志这份日志在半年后写周报、追线上问题、交接项目时价值高到无法衡量。如果你真的想把 Git 用顺从今天开始给自己定一个小目标一个月内所有版本操作都主动通过 Git 完成不要回退到“复制一份文件改名为 xxx_final_v2”的老路上去。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑