Git和GitHub入门教程:版本控制、分支管理与代码推送实战 📅 发布时间:2026/9/19 10:35:47 👁 浏览次数: 第一次把代码传到 GitHub 上的那种兴奋感很多程序员应该都记得你在本地写了一堆文件战战兢兢敲下git push看到屏幕上滚过一行 main - main 之类的输出终于松一口气。但在那之前几乎所有小白都得先经历一轮灵魂拷问Git 是什么GitHub 又是什么它俩到底怎么配合为什么我在自己电脑上写代码还非要折腾一个网站这篇文章不打算绕弯子我要从安装 Git 开始先把 Git 和 GitHub 的分工讲清楚再把新手日常最常用的 6 个操作逐个拆开——clone、commit、pull、push、branch、Pull Request每一步不仅告诉你怎么敲更告诉你为什么要这么敲以及有哪些我在真实项目里踩过之后才明白的细节。先说个最适合新手的类比Git 是一台装在你电脑本地的“时光机”它记录你每次修改让你随时可以回到任意一个历史版本GitHub 则是一个“公共存档馆”你把本地时光机里保存的那套东西推上去别人才能看到、才能一起改。名字里都带 Git但一个是你终端里敲的软件一个是你浏览器里开的网站。很多新手把这两个概念混成一团于是后面每次报错都变成天书。下面我从头开始走完整条链路。1. 先卸下心理包袱“版本控制”到底在控制什么1.1 每次提交都是一张完整的快照而不是在“存差异”很多人第一次听说 Git 时会有一个错觉Git 是不是像一个网盘一样每次自动把改动同步一遍其实不是。Git 真正拿手的是“快照”每当你执行一次git commit它就把当前整个项目状态打成一张快照存到.git目录里。只不过 Git 很聪明对于没有变化的文件它不会重复保存整份内容而是直接引用上一次的那个文件对象所以仓库不会因为历史多而爆炸。这个设计带来一个很踏实的好处你完全可以离线使用 Git。没有网络没有 GitHub你在飞机上照样可以commit可以看历史可以对比两个版本之间的差别。因为版本历史全都在你本地.git文件夹里GitHub 并不是必需角色。很多人一直到很后期才意识到这一点你先把自己的代码用 Git 管好GitHub 只是这堆历史的一个远程副本和协作入口。1.2 GitHub 解决的不是“版本”而是“协作”本地 Git 解决的是时间维度的问题过去某个时刻的代码长什么样是谁在什么时间改的。GitHub 解决的是空间维度的问题不同电脑、不同人的代码怎么合并到一起。想想你自己写一个项目的时候其实不太需要 GitHub本地git init就够用了。但一旦涉及团队协作、开源项目、多台电脑同步你就需要有一个“大家都认的地方”来交换提交记录。GitHub 就是一个托管 Git 仓库的平台它存储远程仓库同时提供网页界面、分支管理、Pull Request简称 PR、Issue 追踪等一整套协作工具。说到底Git 管的是“版本”GitHub 管的是“托管与协作”这才是两个东西配合关系的核心。1.3 Git 和 GitHub 的边界一张表看清楚维度GitGitHub是什么版本控制工具基于 Git 的代码托管平台运行位置本地命令行远程服务器 网页核心能力提交、分支、合并、回滚远程仓库、PR、Issue、Actions 自动化离线可用完全可以几乎不行核心操作都要联网必须使用是没有 Git 就没有版本历史否单人项目可以完全不用常见操作add, commit, branch, mergefork, Pull Request, Releases这一张表理解了后面所有命令就不容易跑偏。2. 开整前唯一正确的起点先把 Git 和 GitHub 的“门禁”配齐很多小白学习 Git 时最容易忽略的就是初始化配置结果第一次提交后发现自己提交人的名字是乱码或者邮箱没绑定后面历史全部带着错误身份改起来很麻烦。越早配置越省心。2.1 安装 Git 并确认终端能认出它安装这一步太容易被跳过但实际上值得认真确认一次。Windows 用户建议直接去 Git 官网下载安装包安装时一路默认即可。Linux 用户用系统自带包管理器装比如 Debian/Ubuntu 下执行sudo apt update sudo apt install gitmacOS 用户装了 Xcode Command Line Tools 之后通常就有 Git不确定的话先执行git --version看看。装完之后做一次真正的验证不要只看“安装成功”弹窗。打开终端敲git --version能显示出版本号才算装好。如果系统提示找不到命令优先检查环境变量如果用的是 Windows可以在开始菜单里打开Git Bash这个终端自带 Git 的运行环境对新用户最友好。我见过不少人在 IDE 里装了一堆插件结果根本不知道真正的 Git 可执行文件在哪所以建议第一课还是回到命令行。2.2 提交信息的“身份证”必须现在写好Git 每次提交都会记录一行 “Author: 名字 邮箱”这行信息从哪里来就是靠你在本地配置的全局选项。设置方法很简单git config --global user.name 你的昵称 git config --global user.email 你的邮箱加上--global就表示这台机器上的所有仓库都用这个身份不用每个仓库重新配一遍。写的时候注意邮箱最好和 GitHub 账号绑定的邮箱一致这样 GitHub 才能在提交记录上正确关联到你的账号头像。更讲究一点还可以顺手配置默认分支git config --global init.defaultBranch main这能让新仓库的默认分支叫main而不是旧的master避免以后每次创建仓库都看到老分支名时还要额外操作一次。2.3 配置 SSH Key一次输入之后 push / pull 都免密用 HTTPS 方式连接 GitHub 也能用但新版 GitHub 要求使用 Personal Access Token 代替密码输入每次都被要求输入用户名和 token对频繁操作的人来说很烦。所以我推荐直接用 SSH Key配置一次后后续的git clone、git pull、git push都不需要再输密码。生成密钥的命令ssh-keygen -t ed25519 -C 你的邮箱一路回车就行生成的默认路径在~/.ssh/id_ed25519.pub。然后用cat命令查看公钥内容cat ~/.ssh/id_ed25519.pub把输出的一整串内容复制下来打开 GitHub 网页进入Settings - SSH and GPG keys - New SSH key粘贴保存。这里的关键点是复制的必须是以ssh-ed25519开头、以邮箱结尾的完整字符串不能少行。2.4 验证连通性提前诊断别等 push 报错配置完之后测试一下 SSH 链路是否通ssh -T gitgithub.com如果你看到类似Hi username! Youve successfully authenticated, but GitHub does not provide shell access.的输出说明一切正常。这条路不通后续任何推送都会失败所以这个验证非常值得做。如果卡在 ask passphrase 提示说明生成密钥时设置了密码短语如果提示连接超时或认证失败优先检查公钥是否粘贴完整、本机~/.ssh目录下是否有id_ed25519和id_ed25519.pub这两个文件。3. 六个高频操作从“拿到仓库”到“代码合并”手把手走完这六个操作是我在团队里带新人必讲的几乎覆盖了日常工作百分之九十以上的 Git 操作场景每一条都会从用途讲到实操再到典型输出解释。3.1 操作一git clone把 GitHub 上的完整项目复制到本地场景你在 GitHub 上看到一个项目想把它下载到本地开始研究。在仓库主页找到绿色Code按钮点开以后会看到仓库 URL。如果是前面配置过 SSH Key 的情况优先选择 SSH 格式的地址然后执行git clone gitgithub.com:用户名/仓库名.git执行完当前目录下会多出一个以仓库名命名的文件夹而且这个文件夹里已经初始化好了一个完整的 Git 仓库也就是说它自带.git目录、自带远程地址配置、自带所有历史提交。我在教新人的时候会特别强调clone不是简单的“下载 zip”它把整个版本历史和远程关系都带过来了。一个常见误区是有人会在 clone 完成后再执行一次git init这完全是多余的甚至会搞乱仓库结构。clone 之后直接cd 仓库名进去工作就行。3.2 操作二git add 和 git commit把改动“快照”进本地历史场景你改了一些代码想先存一个版本确保后面改坏了可以退回来。Git 的数据流有一个很重要的中间站叫“暂存区”。你改完文件后需要先用git add把改动放进暂存区再用git commit把它写成一条永久提交。这一条“先暂存再提交”的设计常被小白吐槽多此一举但它的意义在于你可以精确控制这一次提交到底包含哪些文件而不是把所有改动都混在一起。# 把某个文件放入暂存区 git add README.md # 把当前所有改动放入暂存区注意这个命令不会添加删除操作需要配合 -A git add -A # 写成一条提交记录 git commit -m 添加项目说明文档提交之后最好用git log --oneline看一眼提交记录git log --oneline你会看到一条类似a1b2c3d 添加项目说明文档的输出前面的a1b2c3d是这条提交的唯一标识以后想回退、想对比靠的都是它。commit并不会把代码传到 GitHub它只是本地的一次快照真正同步需要后面的push。3.3 操作三git pull每次开始干活之前先同步远端最新状态场景你和同事同时在改一个仓库他往 GitHub 上推了新内容你本地还停留在旧版本继续改下去很可能冲突。Git 里有两类“同步命令”git fetch和git pull。fetch只是从远端下载最新提交记录到本地不会动你当前的工作区pull则是一个组合拳它先fetch再做一次合并直接改变你本地的工作文件。新手阶段直接用git pull是没问题的但必须接受一个概念pull 的背后是一次合并操作。默认情况下git pull等价于git fetch origin git merge origin/main所以当你本地的代码和远端有分歧时pull可能会触发合并提交也可能会产生冲突。如果远端没有新提交pull 会非常安静地告诉你 Already up to date如果远端有更新Git 会试图自动合并你没有改过的文件只有双方都改到同一处才会冲突。我把这个操作放在开工之前就是因为“先 pull 再写代码”是成本最低也最值得养成的习惯。坐在电脑前第一件事不是急着写而是先同步。3.4 操作四git push把本地提交推送到 GitHub场景本地 commit 已经累积了几条你要把它推到 GitHub 上备份或者让同事看见。git push origin main这条命令的意思是把本地main分支推送到名为origin的远程仓库。origin是 clone 之后默认给远程仓库起的别名你不需要记一长串完整 URL只要记住origin就行。如果你从头新建了一个本地仓库但还没有配远程需要先手动绑定git remote add origin gitgithub.com:用户名/仓库名.git git branch -M main git push -u origin main-u参数很常用它的作用是让本地分支和远程分支建立“上游关系”之后你每次直接输git push和git pullGit 就自动知道该和谁同步不用每次都说一遍origin main。推送成功后会看到类似main - main的输出。如果推送被拒绝最常见的原因就是远端有本地没有的新提交这时候不要强行覆盖按第 4 章的方法先 pull 再 push。3.5 操作五git branch让每一次改动都从“分支”起飞场景你想做一个新功能但又不想直接在main主分支上动手怕改一半把主分支搞坏。分支是 Git 最强大的能力之一也是新手最容易忽略的一块。一个分支本质上就是一个可移动的指针指向某条提交记录。你创建分支后在其中提交不影响其他分支的内容。创建一个新分支并切过去的最快方式git checkout -b feature/login这个命令等于执行了两条git branch feature/login git checkout feature/login切完之后你所有的 commit 都会落在feature/login这个分支上main分支保持在原样。我常用git branch查看当前分支列表当前所在分支前面会有一个*号。分支的意义不是让你“多一个名字”而是让你把不稳定的开发过程和稳定的主干隔离开。等新功能稳定并且测试通过后再把分支合并回主分支。GitHub 上几乎所有协作流都建立在分支之上fork 一个仓库创建分支改完推分支最后发 PR 等审查。3.6 操作六Pull Request这不是 Git 命令而是 GitHub 上最重要的协作开关场景你本地有一个feature/login分支改完了也想让这些改动进入主力main分支但不想直接乱推想让别人帮你审查一眼。Pull Request简称 PR严格来说不是 Git 的功能而是 GitHub 提供的协作机制。它的本质是请求仓库维护者把你某个分支的改动合并到另一个分支。在开源项目里你甚至不需要有仓库的写权限只需要先 Fork 一份到自己的账号下改完推上去再向原仓库发起 PR。实际操作路径是先把你改好的分支推到 GitHubgit push origin feature/login打开 GitHub 仓库页面会看到一个醒目的 “Compare pull request” 提示点进去确认合并方向base: main是接受合并的目标分支compare: feature/login是你提交的源分支这个方向不能搞反填写 PR 标题和描述说清楚你改了什么、为什么改、怎么测试的点击创建 PR等待维护者或同事 reviewPR 带来的最大价值不光是合并代码它把“代码评审”变成了一个明确流程每一条改动都有讨论位置、有 CI 检查、有修改历史。这也是新手进入协作开发的关键一步。用熟这个流程后你会发现之后的每个操作都变得有章可循分支负责隔离PR 负责审查merge 负责合入。4. 我已经把仓库玩坏了怎么办四个最容易翻车的真实场景命令行工具的报错之所以吓人是因为它每条都像在骂人。其实这些报错非常诚实它能把你当前的状态描述得清清楚楚。下面这几个场景是我带新人时出现频率最高的。4.1 push 被拒绝远端有新提交必须“先拉后推”现象! [rejected] main - main (fetch first) error: failed to push some refs hint: Updates were rejected because the remote contains work that you do not have locally.这句话翻译成人话就是远端仓库已经有别人或者你另一台电脑推送的新提交而你的本地还没有。Git 出于安全考虑不允许你直接覆盖历史。解决办法很规矩按顺序执行git pull origin main git push origin main先把远端的更新拉到本地合并再把自己的提交推上去。如果 pull 过程中出现冲突那你需要先解决冲突文件git add解决后的文件再git commit完成一次合并提交最后才能 push。这里有个很重要的心态看到 denied / rejected 不要慌它不是代码被拒只是流程没走完。Git 的保护机制是安全的你要做的是顺着流程走一遍。4.2 合并冲突看到 HEAD 不必恐惧场景你 pull 或 merge 时双方代码都改了同一块区域Git 无法自动判断该保留哪个于是冲突就出现了。冲突文件里会出现类似的标记 HEAD 你的本地内容 远端拿来的内容 origin/main这么说吧这三个符号其实是在“问答卷”上用不同颜色的笔标出不同答案。你需要做的是打开文件手动决定到底保留哪一部分只留本地、只留远端、还是两边整合一下。改完之后删掉所有、、标记保存文件然后git add 冲突文件名 git commit -m 解决合并冲突冲突不是你的错它是多人协作的正常产物。我第一次遇到冲突时也是心跳加速现在处理多了反而觉得这是了解彼此代码意图的最好机会。4.3 误把 node_modules 或密钥文件提交进仓库现象你把依赖目录、日志文件、临时产物、甚至带密码的配置文件一股脑git add -A提交了。后面每次 pull 或 clone这些无用文件都会被带出去既庞大又不安全。解决办法是提前用.gitignore文件把不需要追踪的路径排除掉node_modules/ dist/ .env *.log.gitignore的规则支持通配符和目录忽略规则也很直观node_modules/表示整个目录都不追踪*.log表示所有日志文件不追踪。如果你已经不小心提交了最有效的补救是用git rm --cached把文件从索引中移除但保留本地文件git rm -r --cached node_modules git commit -m 移除不应该跟踪的目录 git push origin main注意--cached很关键少写这个参数会把本地文件也删掉那个后果才真叫麻烦。改完还要记得补上.gitignore避免下一次再犯。4.4 在 main 分支上直接开发单分支工作流为什么不适合新手现象你从 clone 到 push 全程只在main分支上操作觉得切分支多此一举。直到某天你想做一个实验性改动改到一半发现彻底搞坏了想回到没改之前的状态发现main上已经有你自己的上次提交回退起来束手束脚。如果你想保留原始干净的主线同时又能自由试错就应该从main拉一个新分支git checkout -b experiment在experiment上随便试哪怕试出一堆垃圾提交只要切回main就是一片清净。这种“把风险隔离在分支里”的思路能让你在做任何实验时都更有底气。等实验成熟了再把它合并或直接 PR 回主分支。5. 报错语言的“翻译”常见错误提示和解决方向Git 的报错信息其实每一句都能转译成大白话。我列一个高频报错对照表照着这个方向排查大概率能少走很多弯路。报错信息片段大白话翻译处理方向fatal: not a git repository当前目录不是一个 Git 仓库先cd进仓库目录或执行git initfatal: origin does not appear to be a git repository找不到名为 origin 的远程仓库用git remote -v查看或重新git remote add originPermission denied (publickey)SSH 认证没通过检查公钥是否已加到 GitHub密钥文件是否存在Updates were rejected because the remote contains work远端有本地没有的提交先git pull再git pushYour branch is ahead of origin/main by 1 commit本地多了一条还没有推送的提交git push推上去即可branch is up to date with origin/main本地和远端一致没有需要同步的内容如果你明明改过文件检查是否忘了git add和git commitYou are not currently on a branch你处于 detached HEAD 状态不要继续提交切换到已有分支或新建分支保护当前修改fatal: refusing to merge unrelated histories两个仓库的历史没有共同祖先确认合并方向确需合并时用git pull origin main --allow-unrelated-historiesYour local changes would be overwritten by merge本地有未提交改动合并无法进行先git stash暂存改动pull 之后再用git stash pop还原这张表不是让你背的而是让你形成一种直觉报错信息里往往已经说了当前状态你可以先把报错中的人名、分支名、文件名读一遍再去判断是没提交、没推送、还是有冲突。新手最常见的毛病是看到红色英文就立刻复制到搜索引擎其实很多时候你只是漏了一步回到仓库里看一眼git status就能清楚。6. 从我自己的使用习惯出发最后送新手几条实在建议6.1 每次开工先 pull每次收工前 push分支随建随删我在团队里的使用习惯非常简单坐到电脑前第一件事切到主力分支git pull开始新功能时git checkout -b feature/xxx功能完成时commit 写得清楚一点推到远端发 PR合并完成并确认成功后git branch -d feature/xxx删掉本地分支顺手在 GitHub 网页上删除远端分支这一套循环看起来极其机械但它让仓库始终处于干净、可控、可回溯的状态。分支短期存在没问题长期堆积反而会让仓库显得混乱很多人不知道分支是便宜且可随手删除的资源用完就留着最后git branch列出一大堆。6.2 提交信息写清楚一点未来不骂人的只有你自己有人 commit message 写update、fix、ddd。当时觉得无所谓三个月之后回看日志你完全不知道那一次提交动过什么。我的建议很简单开头用动词短语描述“做了什么”比如修复登录页在移动端的样式错乱而不是fix bug。如果改动特别大还可以用多行描述把原因也写进去。6.3 看懂 git status 和 git log比背 20 条命令更重要很多教程都在堆命令但我带了这么多新人之后最深的体会是把git status读懂比背任何高级命令都管用。git status会直接告诉你哪些文件被修改了、哪些已经暂存了、你的分支领先或落后远端几条提交。它是一个一次能看清现状的“仪表盘”几乎每次你想做下一步操作前都应该先看一眼它。git log --oneline --graph --all是我日常排查仓库时使用频率最高的查看命令它能以图形化方式看到全部分支和提交的排列关系。这只是查看指令而不是改动指令多敲永远不会出事。6.4 不要怕冲突也不要怕出错最后讲一句掏心窝的话我见过太多新手因为怕搞坏仓库而不敢敲命令结果反而卡在原地。Git 是少数几个“出错成本极低”的工具之一绝大多数操作都可以撤销。本地历史没提交的修改可以用git restore还原提交错了可以用git reset --soft撤回push 错了远程还有历史记录可查。真正让你越来越熟练的方法只有一个字练。在自己电脑上多建几个测试仓库每个指令都亲手敲一遍即使敲错了Git 给你的报错本身就是最好的老师。等哪天你能看着报错信息说出“这个我见过是因为本地没先 pull”你就已经入门了。